diff options
author | Melanie | 2010-03-15 17:23:35 +0000 |
---|---|---|
committer | Melanie | 2010-03-15 17:23:35 +0000 |
commit | d3f33acc1a6a385ee19814286fe27cb5e48c1551 (patch) | |
tree | 07795e74a637ca63d96b5ee06950b8c1a7a99489 /OpenSim | |
parent | Merge branch 'careminster' into careminster-presence-refactor (diff) | |
parent | flip UVs for profile faces (diff) | |
download | opensim-SC-d3f33acc1a6a385ee19814286fe27cb5e48c1551.zip opensim-SC-d3f33acc1a6a385ee19814286fe27cb5e48c1551.tar.gz opensim-SC-d3f33acc1a6a385ee19814286fe27cb5e48c1551.tar.bz2 opensim-SC-d3f33acc1a6a385ee19814286fe27cb5e48c1551.tar.xz |
Merge branch 'master' into careminster-presence-refactor
Diffstat (limited to 'OpenSim')
77 files changed, 7488 insertions, 3209 deletions
diff --git a/OpenSim/Data/IGridUserData.cs b/OpenSim/Data/IGridUserData.cs index abd2cef..bd7a435 100644 --- a/OpenSim/Data/IGridUserData.cs +++ b/OpenSim/Data/IGridUserData.cs | |||
@@ -44,7 +44,7 @@ namespace OpenSim.Data | |||
44 | /// </summary> | 44 | /// </summary> |
45 | public interface IGridUserData | 45 | public interface IGridUserData |
46 | { | 46 | { |
47 | GridUserData GetGridUserData(string userID); | 47 | GridUserData GetGridUserData(string userID); |
48 | bool StoreGridUserData(GridUserData data); | 48 | bool StoreGridUserData(GridUserData data); |
49 | } | 49 | } |
50 | } \ No newline at end of file | 50 | } \ No newline at end of file |
diff --git a/OpenSim/Data/MSSQL/MSSQLAvatarData.cs b/OpenSim/Data/MSSQL/MSSQLAvatarData.cs index 4992183..49a6b09 100644 --- a/OpenSim/Data/MSSQL/MSSQLAvatarData.cs +++ b/OpenSim/Data/MSSQL/MSSQLAvatarData.cs | |||
@@ -47,7 +47,7 @@ namespace OpenSim.Data.MSSQL | |||
47 | 47 | ||
48 | public MSSQLAvatarData(string connectionString, string realm) : | 48 | public MSSQLAvatarData(string connectionString, string realm) : |
49 | base(connectionString, realm, "Avatar") | 49 | base(connectionString, realm, "Avatar") |
50 | { | 50 | { |
51 | } | 51 | } |
52 | 52 | ||
53 | public bool Delete(UUID principalID, string name) | 53 | public bool Delete(UUID principalID, string name) |
diff --git a/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs b/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs index 506056d..904366e 100644 --- a/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs +++ b/OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs | |||
@@ -110,7 +110,7 @@ namespace OpenSim.Data.MSSQL | |||
110 | { | 110 | { |
111 | List<string> constraints = new List<string>(); | 111 | List<string> constraints = new List<string>(); |
112 | string query = string.Format(@"SELECT | 112 | string query = string.Format(@"SELECT |
113 | COL_NAME(ic.object_id,ic.column_id) AS column_name | 113 | COL_NAME(ic.object_id,ic.column_id) AS column_name |
114 | FROM sys.indexes AS i | 114 | FROM sys.indexes AS i |
115 | INNER JOIN sys.index_columns AS ic | 115 | INNER JOIN sys.index_columns AS ic |
116 | ON i.object_id = ic.object_id AND i.index_id = ic.index_id | 116 | ON i.object_id = ic.object_id AND i.index_id = ic.index_id |
@@ -157,7 +157,7 @@ namespace OpenSim.Data.MSSQL | |||
157 | string where = String.Join(" AND ", terms.ToArray()); | 157 | string where = String.Join(" AND ", terms.ToArray()); |
158 | 158 | ||
159 | string query = String.Format("SELECT * FROM {0} WHERE {1}", | 159 | string query = String.Format("SELECT * FROM {0} WHERE {1}", |
160 | m_Realm, where); | 160 | m_Realm, where); |
161 | 161 | ||
162 | cmd.Connection = conn; | 162 | cmd.Connection = conn; |
163 | cmd.CommandText = query; | 163 | cmd.CommandText = query; |
@@ -296,7 +296,7 @@ namespace OpenSim.Data.MSSQL | |||
296 | query.AppendFormat("[{0}] = {1} ", names[i], values[i]); | 296 | query.AppendFormat("[{0}] = {1} ", names[i], values[i]); |
297 | if (constraints.Count > 0) | 297 | if (constraints.Count > 0) |
298 | { | 298 | { |
299 | List<string> terms = new List<string>(); | 299 | List<string> terms = new List<string>(); |
300 | for (int j = 0; j < constraints.Count; j++) | 300 | for (int j = 0; j < constraints.Count; j++) |
301 | { | 301 | { |
302 | terms.Add(" [" + constraints[j].Key + "] = @" + constraints[j].Key); | 302 | terms.Add(" [" + constraints[j].Key + "] = @" + constraints[j].Key); |
diff --git a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs index b4a945c..9993720 100644 --- a/OpenSim/Data/MSSQL/MSSQLGridUserData.cs +++ b/OpenSim/Data/MSSQL/MSSQLGridUserData.cs | |||
@@ -47,7 +47,7 @@ namespace OpenSim.Data.MSSQL | |||
47 | 47 | ||
48 | public MSSQLGridUserData(string connectionString, string realm) : | 48 | public MSSQLGridUserData(string connectionString, string realm) : |
49 | base(connectionString, realm, "UserGrid") | 49 | base(connectionString, realm, "UserGrid") |
50 | { | 50 | { |
51 | } | 51 | } |
52 | 52 | ||
53 | public GridUserData GetGridUserData(string userID) | 53 | public GridUserData GetGridUserData(string userID) |
@@ -58,7 +58,7 @@ namespace OpenSim.Data.MSSQL | |||
58 | return null; | 58 | return null; |
59 | 59 | ||
60 | return ret[0]; | 60 | return ret[0]; |
61 | } | 61 | } |
62 | 62 | ||
63 | public bool StoreGridUserData(GridUserData data) | 63 | public bool StoreGridUserData(GridUserData data) |
64 | { | 64 | { |
diff --git a/OpenSim/Data/MSSQL/MSSQLManager.cs b/OpenSim/Data/MSSQL/MSSQLManager.cs index 4309b42..575fd21 100644 --- a/OpenSim/Data/MSSQL/MSSQLManager.cs +++ b/OpenSim/Data/MSSQL/MSSQLManager.cs | |||
@@ -46,7 +46,7 @@ namespace OpenSim.Data.MSSQL | |||
46 | /// <summary> | 46 | /// <summary> |
47 | /// Connection string for ADO.net | 47 | /// Connection string for ADO.net |
48 | /// </summary> | 48 | /// </summary> |
49 | private readonly string connectionString; | 49 | private readonly string connectionString; |
50 | 50 | ||
51 | /// <summary> | 51 | /// <summary> |
52 | /// Initialize the manager and set the connectionstring | 52 | /// Initialize the manager and set the connectionstring |
@@ -196,7 +196,7 @@ namespace OpenSim.Data.MSSQL | |||
196 | 196 | ||
197 | migration.Update(); | 197 | migration.Update(); |
198 | } | 198 | } |
199 | } | 199 | } |
200 | 200 | ||
201 | /// <summary> | 201 | /// <summary> |
202 | /// Returns the version of this DB provider | 202 | /// Returns the version of this DB provider |
diff --git a/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs b/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs index 9f18e5e..e7c8dc5 100644 --- a/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs +++ b/OpenSim/Data/MSSQL/MSSQLUserAccountData.cs | |||
@@ -43,7 +43,7 @@ namespace OpenSim.Data.MSSQL | |||
43 | { | 43 | { |
44 | } | 44 | } |
45 | //private string m_Realm; | 45 | //private string m_Realm; |
46 | //private List<string> m_ColumnNames = null; | 46 | //private List<string> m_ColumnNames = null; |
47 | //private MSSQLManager m_database; | 47 | //private MSSQLManager m_database; |
48 | 48 | ||
49 | //public MSSQLUserAccountData(string connectionString, string realm) | 49 | //public MSSQLUserAccountData(string connectionString, string realm) |
diff --git a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs index 756b42d..1253e0b 100644 --- a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs +++ b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs | |||
@@ -197,7 +197,7 @@ namespace OpenSim.Data.MySQL | |||
197 | public virtual T[] Get(string where) | 197 | public virtual T[] Get(string where) |
198 | { | 198 | { |
199 | using (MySqlCommand cmd = new MySqlCommand()) | 199 | using (MySqlCommand cmd = new MySqlCommand()) |
200 | { | 200 | { |
201 | string query = String.Format("select * from {0} where {1}", | 201 | string query = String.Format("select * from {0} where {1}", |
202 | m_Realm, where); | 202 | m_Realm, where); |
203 | 203 | ||
diff --git a/OpenSim/Data/MySQL/MySQLGridUserData.cs b/OpenSim/Data/MySQL/MySQLGridUserData.cs index 15834d2..df29ecd 100644 --- a/OpenSim/Data/MySQL/MySQLGridUserData.cs +++ b/OpenSim/Data/MySQL/MySQLGridUserData.cs | |||
@@ -54,7 +54,7 @@ namespace OpenSim.Data.MySQL | |||
54 | return null; | 54 | return null; |
55 | 55 | ||
56 | return ret[0]; | 56 | return ret[0]; |
57 | } | 57 | } |
58 | 58 | ||
59 | public bool StoreGridUserData(GridUserData data) | 59 | public bool StoreGridUserData(GridUserData data) |
60 | { | 60 | { |
diff --git a/OpenSim/Data/MySQL/MySQLPresenceData.cs b/OpenSim/Data/MySQL/MySQLPresenceData.cs index 68a68af..143dbe3 100644 --- a/OpenSim/Data/MySQL/MySQLPresenceData.cs +++ b/OpenSim/Data/MySQL/MySQLPresenceData.cs | |||
@@ -134,7 +134,7 @@ namespace OpenSim.Data.MySQL | |||
134 | List<UUID> deleteSessions = new List<UUID>(); | 134 | List<UUID> deleteSessions = new List<UUID>(); |
135 | int online = 0; | 135 | int online = 0; |
136 | 136 | ||
137 | while(reader.Read()) | 137 | while (reader.Read()) |
138 | { | 138 | { |
139 | if (bool.Parse(reader["Online"].ToString())) | 139 | if (bool.Parse(reader["Online"].ToString())) |
140 | online++; | 140 | online++; |
diff --git a/OpenSim/Data/Null/NullPresenceData.cs b/OpenSim/Data/Null/NullPresenceData.cs index 9fc4595..b98b5c9 100644 --- a/OpenSim/Data/Null/NullPresenceData.cs +++ b/OpenSim/Data/Null/NullPresenceData.cs | |||
@@ -55,7 +55,7 @@ namespace OpenSim.Data.Null | |||
55 | } | 55 | } |
56 | 56 | ||
57 | public bool Store(PresenceData data) | 57 | public bool Store(PresenceData data) |
58 | { | 58 | { |
59 | if (Instance != this) | 59 | if (Instance != this) |
60 | return Instance.Store(data); | 60 | return Instance.Store(data); |
61 | 61 | ||
@@ -113,7 +113,7 @@ namespace OpenSim.Data.Null | |||
113 | } | 113 | } |
114 | 114 | ||
115 | public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt) | 115 | public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt) |
116 | { | 116 | { |
117 | if (Instance != this) | 117 | if (Instance != this) |
118 | return Instance.SetHomeLocation(userID, regionID, position, lookAt); | 118 | return Instance.SetHomeLocation(userID, regionID, position, lookAt); |
119 | 119 | ||
@@ -130,28 +130,28 @@ namespace OpenSim.Data.Null | |||
130 | p.Data["HomePosition"] = position.ToString(); | 130 | p.Data["HomePosition"] = position.ToString(); |
131 | p.Data["HomeLookAt"] = lookAt.ToString(); | 131 | p.Data["HomeLookAt"] = lookAt.ToString(); |
132 | foundone = true; | 132 | foundone = true; |
133 | } | 133 | } |
134 | } | 134 | } |
135 | 135 | ||
136 | return foundone; | 136 | return foundone; |
137 | } | 137 | } |
138 | 138 | ||
139 | public PresenceData[] Get(string field, string data) | 139 | public PresenceData[] Get(string field, string data) |
140 | { | 140 | { |
141 | if (Instance != this) | 141 | if (Instance != this) |
142 | return Instance.Get(field, data); | 142 | return Instance.Get(field, data); |
143 | 143 | ||
144 | // m_log.DebugFormat( | 144 | // m_log.DebugFormat( |
145 | // "[NULL PRESENCE DATA]: Getting presence data for field {0} with parameter {1}", field, data); | 145 | // "[NULL PRESENCE DATA]: Getting presence data for field {0} with parameter {1}", field, data); |
146 | 146 | ||
147 | List<PresenceData> presences = new List<PresenceData>(); | 147 | List<PresenceData> presences = new List<PresenceData>(); |
148 | if (field == "UserID") | 148 | if (field == "UserID") |
149 | { | 149 | { |
150 | foreach (PresenceData p in m_presenceData.Values) | 150 | foreach (PresenceData p in m_presenceData.Values) |
151 | { | 151 | { |
152 | if (p.UserID == data) | 152 | if (p.UserID == data) |
153 | { | 153 | { |
154 | presences.Add(p); | 154 | presences.Add(p); |
155 | // Console.WriteLine("HOME for " + p.UserID + " is " + (p.Data.ContainsKey("HomeRegionID") ? p.Data["HomeRegionID"] : "Not found")); | 155 | // Console.WriteLine("HOME for " + p.UserID + " is " + (p.Data.ContainsKey("HomeRegionID") ? p.Data["HomeRegionID"] : "Not found")); |
156 | } | 156 | } |
157 | } | 157 | } |
@@ -194,7 +194,7 @@ namespace OpenSim.Data.Null | |||
194 | } | 194 | } |
195 | 195 | ||
196 | public void Prune(string userID) | 196 | public void Prune(string userID) |
197 | { | 197 | { |
198 | if (Instance != this) | 198 | if (Instance != this) |
199 | { | 199 | { |
200 | Instance.Prune(userID); | 200 | Instance.Prune(userID); |
diff --git a/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs b/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs index 84ce775..2c28375 100644 --- a/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs +++ b/OpenSim/Data/SQLite/SQLiteAuthenticationData.cs | |||
@@ -120,7 +120,7 @@ namespace OpenSim.Data.SQLite | |||
120 | } | 120 | } |
121 | 121 | ||
122 | public bool Store(AuthenticationData data) | 122 | public bool Store(AuthenticationData data) |
123 | { | 123 | { |
124 | if (data.Data.ContainsKey("UUID")) | 124 | if (data.Data.ContainsKey("UUID")) |
125 | data.Data.Remove("UUID"); | 125 | data.Data.Remove("UUID"); |
126 | 126 | ||
diff --git a/OpenSim/Framework/MultipartForm.cs b/OpenSim/Framework/MultipartForm.cs index 8ba6d22..90c4007 100644 --- a/OpenSim/Framework/MultipartForm.cs +++ b/OpenSim/Framework/MultipartForm.cs | |||
@@ -1,4 +1,31 @@ | |||
1 | using System; | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
2 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
3 | using System.Net; | 30 | using System.Net; |
4 | using System.IO; | 31 | using System.IO; |
diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index 2fc5bdf..f6d6a7c 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs | |||
@@ -1,4 +1,31 @@ | |||
1 | using System; | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
2 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
3 | using System.Reflection; | 30 | using System.Reflection; |
4 | using log4net; | 31 | using log4net; |
@@ -219,7 +246,7 @@ namespace OpenSim.Framework | |||
219 | /// Parse a notecard in Linden format to a string of ordinary text. | 246 | /// Parse a notecard in Linden format to a string of ordinary text. |
220 | /// </summary> | 247 | /// </summary> |
221 | /// <param name="rawInput"></param> | 248 | /// <param name="rawInput"></param> |
222 | /// <returns></returns> | 249 | /// <returns></returns> |
223 | public static string ParseNotecardToString(string rawInput) | 250 | public static string ParseNotecardToString(string rawInput) |
224 | { | 251 | { |
225 | string[] output = ParseNotecardToList(rawInput).ToArray(); | 252 | string[] output = ParseNotecardToList(rawInput).ToArray(); |
@@ -237,7 +264,7 @@ namespace OpenSim.Framework | |||
237 | /// <returns></returns> | 264 | /// <returns></returns> |
238 | public static List<string> ParseNotecardToList(string rawInput) | 265 | public static List<string> ParseNotecardToList(string rawInput) |
239 | { | 266 | { |
240 | string[] input = rawInput.Replace("\r", "").Split('\n'); | 267 | string[] input = rawInput.Replace("\r", "").Split('\n'); |
241 | int idx = 0; | 268 | int idx = 0; |
242 | int level = 0; | 269 | int level = 0; |
243 | List<string> output = new List<string>(); | 270 | List<string> output = new List<string>(); |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 214f936..9a6ef77 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | |||
@@ -202,16 +202,14 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
202 | if (!m_pollHandlers.ContainsKey(methodName)) | 202 | if (!m_pollHandlers.ContainsKey(methodName)) |
203 | { | 203 | { |
204 | m_pollHandlers.Add(methodName,args); | 204 | m_pollHandlers.Add(methodName,args); |
205 | pollHandlerResult = true; | 205 | pollHandlerResult = true; |
206 | |||
207 | } | 206 | } |
208 | } | 207 | } |
209 | 208 | ||
210 | if (pollHandlerResult) | 209 | if (pollHandlerResult) |
211 | return AddHTTPHandler(methodName, handler); | 210 | return AddHTTPHandler(methodName, handler); |
212 | 211 | ||
213 | return false; | 212 | return false; |
214 | |||
215 | } | 213 | } |
216 | 214 | ||
217 | // Note that the agent string is provided simply to differentiate | 215 | // 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 d13408d..65b1eb5 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 | |||
47 | bool AddAgentHandler(string agent, IHttpAgentHandler handler); | 47 | bool AddAgentHandler(string agent, IHttpAgentHandler handler); |
48 | 48 | ||
49 | /// <summary> | 49 | /// <summary> |
50 | /// Add a handler for an HTTP request | 50 | /// Add a handler for an HTTP request. |
51 | /// </summary> | 51 | /// </summary> |
52 | /// | 52 | /// |
53 | /// This handler can actually be invoked either as | 53 | /// This handler can actually be invoked either as |
@@ -66,6 +66,10 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
66 | /// or | 66 | /// or |
67 | /// | 67 | /// |
68 | /// http://localhost:9000/object/ | 68 | /// http://localhost:9000/object/ |
69 | /// | ||
70 | /// In addition, the handler invoked by the HTTP server for any request is the one when best matches the request | ||
71 | /// URI. So if a handler for "/myapp/" is registered and a request for "/myapp/page" is received, then | ||
72 | /// the "/myapp/" handler is invoked if no "/myapp/page" handler exists. | ||
69 | /// | 73 | /// |
70 | /// <param name="methodName"></param> | 74 | /// <param name="methodName"></param> |
71 | /// <param name="handler"></param> | 75 | /// <param name="handler"></param> |
@@ -73,7 +77,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
73 | /// true if the handler was successfully registered, false if a handler with the same name already existed. | 77 | /// true if the handler was successfully registered, false if a handler with the same name already existed. |
74 | /// </returns> | 78 | /// </returns> |
75 | bool AddHTTPHandler(string methodName, GenericHTTPMethod handler); | 79 | bool AddHTTPHandler(string methodName, GenericHTTPMethod handler); |
76 | |||
77 | 80 | ||
78 | bool AddPollServiceHTTPHandler(string methodName, GenericHTTPMethod handler, PollServiceEventArgs args); | 81 | bool AddPollServiceHTTPHandler(string methodName, GenericHTTPMethod handler, PollServiceEventArgs args); |
79 | 82 | ||
diff --git a/OpenSim/Framework/UntrustedWebRequest.cs b/OpenSim/Framework/UntrustedWebRequest.cs index 1af7c41..e6411cc 100644 --- a/OpenSim/Framework/UntrustedWebRequest.cs +++ b/OpenSim/Framework/UntrustedWebRequest.cs | |||
@@ -1,4 +1,31 @@ | |||
1 | using System; | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
2 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
3 | using System.IO; | 30 | using System.IO; |
4 | using System.Net; | 31 | using System.Net; |
@@ -118,7 +145,7 @@ namespace OpenSim.Framework | |||
118 | /// <param name="allowLoopback">True to allow loopback addresses to be used</param> | 145 | /// <param name="allowLoopback">True to allow loopback addresses to be used</param> |
119 | /// <param name="uri">The URI to test for whether it should be allowed.</param> | 146 | /// <param name="uri">The URI to test for whether it should be allowed.</param> |
120 | /// <returns> | 147 | /// <returns> |
121 | /// <c>true</c> if [is URI allowable] [the specified URI]; otherwise, <c>false</c>. | 148 | /// <c>true</c> if [is URI allowable] [the specified URI]; otherwise, <c>false</c>. |
122 | /// </returns> | 149 | /// </returns> |
123 | private static bool IsUriAllowable(Uri uri, bool allowLoopback) | 150 | private static bool IsUriAllowable(Uri uri, bool allowLoopback) |
124 | { | 151 | { |
@@ -180,7 +207,7 @@ namespace OpenSim.Framework | |||
180 | /// </summary> | 207 | /// </summary> |
181 | /// <param name="ip">The ip address to check.</param> | 208 | /// <param name="ip">The ip address to check.</param> |
182 | /// <returns> | 209 | /// <returns> |
183 | /// <c>true</c> if this is a loopback IP address; <c>false</c> otherwise. | 210 | /// <c>true</c> if this is a loopback IP address; <c>false</c> otherwise. |
184 | /// </returns> | 211 | /// </returns> |
185 | private static bool IsIPv6Loopback(IPAddress ip) | 212 | private static bool IsIPv6Loopback(IPAddress ip) |
186 | { | 213 | { |
diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index d9782ff..16e44af 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs | |||
@@ -1,4 +1,31 @@ | |||
1 | using System; | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
2 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
3 | using System.Collections.Specialized; | 30 | using System.Collections.Specialized; |
4 | using System.IO; | 31 | using System.IO; |
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index d458364..f54e41a 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; | |||
36 | using OpenSim.Region.Framework.Scenes; | 36 | using OpenSim.Region.Framework.Scenes; |
37 | 37 | ||
38 | namespace OpenSim.Region.CoreModules.Avatar.Attachments | 38 | namespace OpenSim.Region.CoreModules.Avatar.Attachments |
39 | { | 39 | { |
40 | public class AttachmentsModule : IAttachmentsModule, IRegionModule | 40 | public class AttachmentsModule : IAttachmentsModule, IRegionModule |
41 | { | 41 | { |
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -67,6 +67,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
67 | get { return false; } | 67 | get { return false; } |
68 | } | 68 | } |
69 | 69 | ||
70 | public void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, bool silent) | ||
71 | { | ||
72 | m_log.Debug("[ATTACHMENTS MODULE]: Invoking AttachObject"); | ||
73 | |||
74 | // If we can't take it, we can't attach it! | ||
75 | SceneObjectPart part = m_scene.GetSceneObjectPart(objectLocalID); | ||
76 | if (part == null) | ||
77 | return; | ||
78 | |||
79 | if (!m_scene.Permissions.CanTakeObject(part.UUID, remoteClient.AgentId)) | ||
80 | return; | ||
81 | |||
82 | // Calls attach with a Zero position | ||
83 | if (AttachObject(remoteClient, objectLocalID, AttachmentPt, rot, Vector3.Zero, false)) | ||
84 | { | ||
85 | m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); | ||
86 | |||
87 | // Save avatar attachment information | ||
88 | ScenePresence presence; | ||
89 | if (m_scene.AvatarFactory != null && m_scene.TryGetAvatar(remoteClient.AgentId, out presence)) | ||
90 | { | ||
91 | m_log.Info( | ||
92 | "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId | ||
93 | + ", AttachmentPoint: " + AttachmentPt); | ||
94 | |||
95 | m_scene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
70 | public bool AttachObject( | 100 | public bool AttachObject( |
71 | IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent) | 101 | IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent) |
72 | { | 102 | { |
@@ -138,12 +168,87 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
138 | 168 | ||
139 | return true; | 169 | return true; |
140 | } | 170 | } |
171 | |||
172 | public UUID RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | ||
173 | { | ||
174 | m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing single attachment from item {0} for {1}", itemID, remoteClient.Name); | ||
175 | |||
176 | return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true); | ||
177 | } | ||
178 | |||
179 | public UUID RezSingleAttachmentFromInventory( | ||
180 | IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus) | ||
181 | { | ||
182 | SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(remoteClient, itemID, AttachmentPt); | ||
183 | |||
184 | if (updateInventoryStatus) | ||
185 | { | ||
186 | if (att == null) | ||
187 | { | ||
188 | ShowDetachInUserInventory(itemID, remoteClient); | ||
189 | } | ||
190 | |||
191 | SetAttachmentInventoryStatus(att, remoteClient, itemID, AttachmentPt); | ||
192 | } | ||
193 | |||
194 | if (null == att) | ||
195 | return UUID.Zero; | ||
196 | else | ||
197 | return att.UUID; | ||
198 | } | ||
199 | |||
200 | protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( | ||
201 | IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | ||
202 | { | ||
203 | IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); | ||
204 | if (invAccess != null) | ||
205 | { | ||
206 | SceneObjectGroup objatt = invAccess.RezObject(remoteClient, | ||
207 | itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
208 | false, false, remoteClient.AgentId, true); | ||
209 | |||
210 | // m_log.DebugFormat( | ||
211 | // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", | ||
212 | // objatt.Name, remoteClient.Name, AttachmentPt); | ||
213 | |||
214 | if (objatt != null) | ||
215 | { | ||
216 | bool tainted = false; | ||
217 | if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint()) | ||
218 | tainted = true; | ||
219 | |||
220 | AttachObject( | ||
221 | remoteClient, objatt.LocalId, AttachmentPt, Quaternion.Identity, objatt.AbsolutePosition, false); | ||
222 | //objatt.ScheduleGroupForFullUpdate(); | ||
223 | |||
224 | if (tainted) | ||
225 | objatt.HasGroupChanged = true; | ||
226 | |||
227 | // Fire after attach, so we don't get messy perms dialogs | ||
228 | // 3 == AttachedRez | ||
229 | objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 3); | ||
230 | |||
231 | // Do this last so that event listeners have access to all the effects of the attachment | ||
232 | m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); | ||
233 | } | ||
234 | else | ||
235 | { | ||
236 | m_log.WarnFormat( | ||
237 | "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", | ||
238 | itemID, remoteClient.Name, AttachmentPt); | ||
239 | } | ||
240 | |||
241 | return objatt; | ||
242 | } | ||
243 | |||
244 | return null; | ||
245 | } | ||
141 | 246 | ||
142 | public UUID SetAttachmentInventoryStatus( | 247 | public UUID SetAttachmentInventoryStatus( |
143 | SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | 248 | SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt) |
144 | { | 249 | { |
145 | m_log.DebugFormat( | 250 | m_log.DebugFormat( |
146 | "[ATTACHMENTS MODULEY]: Updating inventory of {0} to show attachment of {1} (item ID {2})", | 251 | "[ATTACHMENTS MODULE]: Updating inventory of {0} to show attachment of {1} (item ID {2})", |
147 | remoteClient.Name, att.Name, itemID); | 252 | remoteClient.Name, att.Name, itemID); |
148 | 253 | ||
149 | if (!att.IsDeleted) | 254 | if (!att.IsDeleted) |
@@ -204,7 +309,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
204 | if (m_scene.AvatarFactory != null) | 309 | if (m_scene.AvatarFactory != null) |
205 | m_scene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); | 310 | m_scene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); |
206 | } | 311 | } |
207 | } | 312 | } |
208 | 313 | ||
209 | public void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient) | 314 | public void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient) |
210 | { | 315 | { |
@@ -222,7 +327,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
222 | } | 327 | } |
223 | 328 | ||
224 | DetachSingleAttachmentToInv(itemID, remoteClient); | 329 | DetachSingleAttachmentToInv(itemID, remoteClient); |
225 | } | 330 | } |
226 | 331 | ||
227 | // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. | 332 | // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. |
228 | // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? | 333 | // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? |
@@ -252,6 +357,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
252 | } | 357 | } |
253 | } | 358 | } |
254 | } | 359 | } |
255 | } | 360 | } |
256 | } | 361 | } |
257 | } \ No newline at end of file | 362 | } \ 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 de324c0..312db38 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 | |||
394 | public IClientAPI LocateClientObject(UUID agentID) | 394 | public IClientAPI LocateClientObject(UUID agentID) |
395 | { | 395 | { |
396 | Scene scene = GetClientScene(agentID); | 396 | Scene scene = GetClientScene(agentID); |
397 | if(scene == null) | 397 | if (scene == null) |
398 | return null; | 398 | return null; |
399 | 399 | ||
400 | ScenePresence presence = scene.GetScenePresence(agentID); | 400 | ScenePresence presence = scene.GetScenePresence(agentID); |
401 | if(presence == null) | 401 | if (presence == null) |
402 | return null; | 402 | return null; |
403 | 403 | ||
404 | return presence.ControllingClient; | 404 | return presence.ControllingClient; |
@@ -481,7 +481,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends | |||
481 | m_log.DebugFormat("[FRIENDS]: {0} offered friendship to {1}", principalID, friendID); | 481 | m_log.DebugFormat("[FRIENDS]: {0} offered friendship to {1}", principalID, friendID); |
482 | 482 | ||
483 | // This user wants to be friends with the other user. | 483 | // This user wants to be friends with the other user. |
484 | // Let's add both relations to the DB, but one of them is inactive (-1) | 484 | // Let's add the relation backwards, in case the other is not online |
485 | FriendsService.StoreFriend(friendID, principalID.ToString(), 0); | 485 | FriendsService.StoreFriend(friendID, principalID.ToString(), 0); |
486 | 486 | ||
487 | // Now let's ask the other user to be friends with this user | 487 | // Now let's ask the other user to be friends with this user |
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index c0d3f31..ad050a1 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 | |||
108 | if (!m_Enabled) | 108 | if (!m_Enabled) |
109 | return; | 109 | return; |
110 | 110 | ||
111 | lock(m_Scenes) | 111 | lock (m_Scenes) |
112 | { | 112 | { |
113 | m_Scenes.Remove(scene); | 113 | m_Scenes.Remove(scene); |
114 | } | 114 | } |
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 0fc467b..16e05b7 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 | |||
576 | foreach (SceneObjectPart part in partList) | 576 | foreach (SceneObjectPart part in partList) |
577 | { | 577 | { |
578 | if (part.OwnerID != item.Owner) | 578 | if (part.OwnerID != item.Owner) |
579 | { | 579 | { |
580 | part.LastOwnerID = part.OwnerID; | 580 | part.LastOwnerID = part.OwnerID; |
581 | part.OwnerID = item.Owner; | 581 | part.OwnerID = item.Owner; |
582 | part.Inventory.ChangeInventoryOwner(item.Owner); | 582 | part.Inventory.ChangeInventoryOwner(item.Owner); |
diff --git a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml index 0195c03..aaa318c 100644 --- a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml +++ b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml | |||
@@ -56,6 +56,9 @@ | |||
56 | <RegionModule id="RemotePresenceServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.RemotePresenceServicesConnector" /> | 56 | <RegionModule id="RemotePresenceServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.RemotePresenceServicesConnector" /> |
57 | <RegionModule id="LocalUserAccountServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts.LocalUserAccountServicesConnector" /> | 57 | <RegionModule id="LocalUserAccountServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts.LocalUserAccountServicesConnector" /> |
58 | <RegionModule id="RemoteUserAccountServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts.RemoteUserAccountServicesConnector" /> | 58 | <RegionModule id="RemoteUserAccountServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts.RemoteUserAccountServicesConnector" /> |
59 | |||
60 | <RegionModule id="LocalGridUserServicesConnector" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser.LocalGridUserServicesConnector" /> | ||
61 | |||
59 | <RegionModule id="LocalSimulationConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation.LocalSimulationConnectorModule" /> | 62 | <RegionModule id="LocalSimulationConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation.LocalSimulationConnectorModule" /> |
60 | <RegionModule id="RemoteSimulationConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation.RemoteSimulationConnectorModule" /> | 63 | <RegionModule id="RemoteSimulationConnectorModule" type="OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation.RemoteSimulationConnectorModule" /> |
61 | <!-- Service connectors IN modules --> | 64 | <!-- Service connectors IN modules --> |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs index 292ff8e..63a28fc 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 | |||
61 | m_LocalConnector = new LocalPresenceServicesConnector(config); | 61 | m_LocalConnector = new LocalPresenceServicesConnector(config); |
62 | 62 | ||
63 | // Let's stick in a test presence | 63 | // Let's stick in a test presence |
64 | m_LocalConnector.m_PresenceService.LoginAgent(UUID.Zero.ToString(), UUID.Zero, UUID.Zero); | 64 | m_LocalConnector.m_PresenceService.LoginAgent(UUID.Zero.ToString(), UUID.Zero, UUID.Zero); |
65 | } | 65 | } |
66 | 66 | ||
67 | /// <summary> | 67 | /// <summary> |
@@ -80,7 +80,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence.Tests | |||
80 | p.Data = new Dictionary<string, string>(); | 80 | p.Data = new Dictionary<string, string>(); |
81 | p.Data["Online"] = true.ToString(); | 81 | p.Data["Online"] = true.ToString(); |
82 | m_presenceData.Add(UUID.Zero, p); | 82 | m_presenceData.Add(UUID.Zero, p); |
83 | */ | 83 | */ |
84 | 84 | ||
85 | string user1 = UUID.Zero.ToString(); | 85 | string user1 = UUID.Zero.ToString(); |
86 | UUID session1 = UUID.Zero; | 86 | UUID session1 = UUID.Zero; |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs index 07fee79..30ebb21 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 | |||
73 | IConfig userConfig = source.Configs["UserAccountService"]; | 73 | IConfig userConfig = source.Configs["UserAccountService"]; |
74 | if (userConfig == null) | 74 | if (userConfig == null) |
75 | { | 75 | { |
76 | m_log.Error("[USER CONNECTOR]: UserAccountService missing from OpenSim.ini"); | 76 | m_log.Error("[LOCAL USER ACCOUNT SERVICE CONNECTOR]: UserAccountService missing from OpenSim.ini"); |
77 | return; | 77 | return; |
78 | } | 78 | } |
79 | 79 | ||
80 | string serviceDll = userConfig.GetString("LocalServiceModule", | 80 | string serviceDll = userConfig.GetString("LocalServiceModule", String.Empty); |
81 | String.Empty); | ||
82 | 81 | ||
83 | if (serviceDll == String.Empty) | 82 | if (serviceDll == String.Empty) |
84 | { | 83 | { |
85 | m_log.Error("[USER CONNECTOR]: No LocalServiceModule named in section UserService"); | 84 | m_log.Error("[LOCAL USER ACCOUNT SERVICE CONNECTOR]: No LocalServiceModule named in section UserService"); |
86 | return; | 85 | return; |
87 | } | 86 | } |
88 | 87 | ||
89 | Object[] args = new Object[] { source }; | 88 | Object[] args = new Object[] { source }; |
90 | m_UserService = | 89 | m_UserService = ServerUtils.LoadPlugin<IUserAccountService>(serviceDll, args); |
91 | ServerUtils.LoadPlugin<IUserAccountService>(serviceDll, | ||
92 | args); | ||
93 | 90 | ||
94 | if (m_UserService == null) | 91 | if (m_UserService == null) |
95 | { | 92 | { |
96 | m_log.Error("[USER CONNECTOR]: Can't load user account service"); | 93 | m_log.ErrorFormat( |
94 | "[LOCAL USER ACCOUNT SERVICE CONNECTOR]: Cannot load user account service specified as {0}", serviceDll); | ||
97 | return; | 95 | return; |
98 | } | 96 | } |
99 | m_Enabled = true; | 97 | m_Enabled = true; |
100 | m_Cache = new UserAccountCache(); | 98 | m_Cache = new UserAccountCache(); |
101 | 99 | ||
102 | m_log.Info("[USER CONNECTOR]: Local user connector enabled"); | 100 | m_log.Info("[LOCAL USER ACCOUNT SERVICE CONNECTOR]: Local user connector enabled"); |
103 | } | 101 | } |
104 | } | 102 | } |
105 | } | 103 | } |
@@ -134,6 +132,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts | |||
134 | { | 132 | { |
135 | if (!m_Enabled) | 133 | if (!m_Enabled) |
136 | return; | 134 | return; |
135 | |||
136 | m_log.InfoFormat("[LOCAL USER ACCOUNT SERVICE CONNECTOR]: Enabled local user accounts for region {0}", scene.RegionInfo.RegionName); | ||
137 | } | 137 | } |
138 | 138 | ||
139 | #endregion | 139 | #endregion |
@@ -142,26 +142,27 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts | |||
142 | 142 | ||
143 | public UserAccount GetUserAccount(UUID scopeID, UUID userID) | 143 | public UserAccount GetUserAccount(UUID scopeID, UUID userID) |
144 | { | 144 | { |
145 | UserAccount account = m_Cache.Get(userID); | 145 | bool inCache = false; |
146 | if (account != null) | 146 | UserAccount account = m_Cache.Get(userID, out inCache); |
147 | if (inCache) | ||
147 | return account; | 148 | return account; |
148 | 149 | ||
149 | account = m_UserService.GetUserAccount(scopeID, userID); | 150 | account = m_UserService.GetUserAccount(scopeID, userID); |
150 | if (account != null) | 151 | m_Cache.Cache(userID, account); |
151 | m_Cache.Cache(account); | ||
152 | 152 | ||
153 | return account; | 153 | return account; |
154 | } | 154 | } |
155 | 155 | ||
156 | public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) | 156 | public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) |
157 | { | 157 | { |
158 | UserAccount account = m_Cache.Get(firstName + " " + lastName); | 158 | bool inCache = false; |
159 | if (account != null) | 159 | UserAccount account = m_Cache.Get(firstName + " " + lastName, out inCache); |
160 | if (inCache) | ||
160 | return account; | 161 | return account; |
161 | 162 | ||
162 | account = m_UserService.GetUserAccount(scopeID, firstName, lastName); | 163 | account = m_UserService.GetUserAccount(scopeID, firstName, lastName); |
163 | if (account != null) | 164 | if (account != null) |
164 | m_Cache.Cache(account); | 165 | m_Cache.Cache(account.PrincipalID, account); |
165 | 166 | ||
166 | return account; | 167 | return account; |
167 | } | 168 | } |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs index 1140692..488dbd5 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 | |||
119 | 119 | ||
120 | public override UserAccount GetUserAccount(UUID scopeID, UUID userID) | 120 | public override UserAccount GetUserAccount(UUID scopeID, UUID userID) |
121 | { | 121 | { |
122 | UserAccount account = m_Cache.Get(userID); | 122 | bool inCache = false; |
123 | if (account != null) | 123 | UserAccount account = m_Cache.Get(userID, out inCache); |
124 | if (inCache) | ||
124 | return account; | 125 | return account; |
125 | 126 | ||
126 | account = base.GetUserAccount(scopeID, userID); | 127 | account = base.GetUserAccount(scopeID, userID); |
127 | if (account != null) | 128 | m_Cache.Cache(userID, account); |
128 | m_Cache.Cache(account); | ||
129 | 129 | ||
130 | return account; | 130 | return account; |
131 | } | 131 | } |
132 | 132 | ||
133 | public override UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) | 133 | public override UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) |
134 | { | 134 | { |
135 | UserAccount account = m_Cache.Get(firstName + " " + lastName); | 135 | bool inCache = false; |
136 | if (account != null) | 136 | UserAccount account = m_Cache.Get(firstName + " " + lastName, out inCache); |
137 | if (inCache) | ||
137 | return account; | 138 | return account; |
138 | 139 | ||
139 | account = base.GetUserAccount(scopeID, firstName, lastName); | 140 | account = base.GetUserAccount(scopeID, firstName, lastName); |
140 | if (account != null) | 141 | if (account != null) |
141 | m_Cache.Cache(account); | 142 | m_Cache.Cache(account.PrincipalID, account); |
142 | 143 | ||
143 | return account; | 144 | return account; |
144 | } | 145 | } |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs index e430fc7..a355661 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 | |||
36 | { | 36 | { |
37 | public class UserAccountCache | 37 | public class UserAccountCache |
38 | { | 38 | { |
39 | //private static readonly ILog m_log = | 39 | private static readonly ILog m_log = |
40 | // LogManager.GetLogger( | 40 | LogManager.GetLogger( |
41 | // MethodBase.GetCurrentMethod().DeclaringType); | 41 | MethodBase.GetCurrentMethod().DeclaringType); |
42 | 42 | private ExpiringCache<UUID, UserAccount> m_UUIDCache; | |
43 | private ICnmCache<UUID, UserAccount> m_UUIDCache; | 43 | private ExpiringCache<string, UUID> m_NameCache; |
44 | private Dictionary<string, UUID> m_NameCache; | ||
45 | 44 | ||
46 | public UserAccountCache() | 45 | public UserAccountCache() |
47 | { | 46 | { |
48 | // Warning: the size values are a bit fuzzy. What matters | 47 | // Warning: the size values are a bit fuzzy. What matters |
49 | // most for this cache is the count value (128 entries). | 48 | // most for this cache is the count value (128 entries). |
50 | m_UUIDCache = CnmSynchronizedCache<UUID, UserAccount>.Synchronized(new CnmMemoryCache<UUID, UserAccount>( | 49 | m_UUIDCache = new ExpiringCache<UUID, UserAccount>(); |
51 | 128, 128*512, TimeSpan.FromMinutes(30.0))); | 50 | m_NameCache = new ExpiringCache<string, UUID>(); // this one is unbound |
52 | m_NameCache = new Dictionary<string, UUID>(); // this one is unbound | ||
53 | } | 51 | } |
54 | 52 | ||
55 | public void Cache(UserAccount account) | 53 | public void Cache(UUID userID, UserAccount account) |
56 | { | 54 | { |
57 | m_UUIDCache.Set(account.PrincipalID, account, 512); | 55 | // Cache even null accounts |
58 | m_NameCache[account.Name] = account.PrincipalID; | 56 | m_UUIDCache.AddOrUpdate(userID, account, DateTime.Now + TimeSpan.FromMinutes(2.0d)); |
57 | if (account != null) | ||
58 | m_NameCache.AddOrUpdate(account.Name, account.PrincipalID, DateTime.Now + TimeSpan.FromMinutes(2.0d)); | ||
59 | 59 | ||
60 | //m_log.DebugFormat("[USER CACHE]: cached user {0} {1}", account.FirstName, account.LastName); | 60 | m_log.DebugFormat("[USER CACHE]: cached user {0}", userID); |
61 | } | 61 | } |
62 | 62 | ||
63 | public UserAccount Get(UUID userID) | 63 | public UserAccount Get(UUID userID, out bool inCache) |
64 | { | 64 | { |
65 | UserAccount account = null; | 65 | UserAccount account = null; |
66 | inCache = false; | ||
66 | if (m_UUIDCache.TryGetValue(userID, out account)) | 67 | if (m_UUIDCache.TryGetValue(userID, out account)) |
67 | { | 68 | { |
68 | //m_log.DebugFormat("[USER CACHE]: Account {0} {1} found in cache", account.FirstName, account.LastName); | 69 | //m_log.DebugFormat("[USER CACHE]: Account {0} {1} found in cache", account.FirstName, account.LastName); |
70 | inCache = true; | ||
69 | return account; | 71 | return account; |
70 | } | 72 | } |
71 | 73 | ||
72 | return null; | 74 | return null; |
73 | } | 75 | } |
74 | 76 | ||
75 | public UserAccount Get(string name) | 77 | public UserAccount Get(string name, out bool inCache) |
76 | { | 78 | { |
77 | if (!m_NameCache.ContainsKey(name)) | 79 | inCache = false; |
80 | if (!m_NameCache.Contains(name)) | ||
78 | return null; | 81 | return null; |
79 | 82 | ||
80 | UserAccount account = null; | 83 | UserAccount account = null; |
81 | if (m_UUIDCache.TryGetValue(m_NameCache[name], out account)) | 84 | UUID uuid = UUID.Zero; |
82 | return account; | 85 | if (m_NameCache.TryGetValue(name, out uuid)) |
86 | if (m_UUIDCache.TryGetValue(uuid, out account)) | ||
87 | { | ||
88 | inCache = true; | ||
89 | return account; | ||
90 | } | ||
83 | 91 | ||
84 | return null; | 92 | return null; |
85 | } | 93 | } |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index e0cdb36..bf856c8 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs | |||
@@ -183,7 +183,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
183 | void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) | 183 | void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData) |
184 | { | 184 | { |
185 | //If we are forcing a position for them to go | 185 | //If we are forcing a position for them to go |
186 | if( forcedPosition != null ) | 186 | if (forcedPosition != null) |
187 | { | 187 | { |
188 | ScenePresence clientAvatar = m_scene.GetScenePresence(remoteClient.AgentId); | 188 | ScenePresence clientAvatar = m_scene.GetScenePresence(remoteClient.AgentId); |
189 | 189 | ||
@@ -199,7 +199,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
199 | forcedPosition = null; | 199 | forcedPosition = null; |
200 | } | 200 | } |
201 | //if we are far away, teleport | 201 | //if we are far away, teleport |
202 | else if(Vector3.Distance(clientAvatar.AbsolutePosition,forcedPosition.Value) > 3 ) | 202 | else if (Vector3.Distance(clientAvatar.AbsolutePosition,forcedPosition.Value) > 3) |
203 | { | 203 | { |
204 | Debug.WriteLine(string.Format("Teleporting out because {0} is too far from avatar position {1}",forcedPosition.Value,clientAvatar.AbsolutePosition)); | 204 | Debug.WriteLine(string.Format("Teleporting out because {0} is too far from avatar position {1}",forcedPosition.Value,clientAvatar.AbsolutePosition)); |
205 | clientAvatar.Teleport(forcedPosition.Value); | 205 | clientAvatar.Teleport(forcedPosition.Value); |
@@ -340,7 +340,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
340 | 340 | ||
341 | public void SendYouAreRestrictedNotice(ScenePresence avatar) | 341 | public void SendYouAreRestrictedNotice(ScenePresence avatar) |
342 | { | 342 | { |
343 | avatar.ControllingClient.SendAlertMessage( | 343 | avatar.ControllingClient.SendAlertMessage( |
344 | "You are not allowed on this parcel because the land owner has restricted access."); | 344 | "You are not allowed on this parcel because the land owner has restricted access."); |
345 | 345 | ||
346 | } | 346 | } |
@@ -475,7 +475,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
475 | ForceAvatarToPosition(clientAvatar, m_scene.GetNearestAllowedPosition(clientAvatar)); | 475 | ForceAvatarToPosition(clientAvatar, m_scene.GetNearestAllowedPosition(clientAvatar)); |
476 | } | 476 | } |
477 | } | 477 | } |
478 | else if ( parcel.IsRestrictedFromLand(clientAvatar.UUID)) | 478 | else if (parcel.IsRestrictedFromLand(clientAvatar.UUID)) |
479 | { | 479 | { |
480 | //once we've sent the message once, keep going toward the target until we are done | 480 | //once we've sent the message once, keep going toward the target until we are done |
481 | if (forcedPosition == null) | 481 | if (forcedPosition == null) |
@@ -487,7 +487,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
487 | else | 487 | else |
488 | { | 488 | { |
489 | //when we are finally in a safe place, lets release the forced position lock | 489 | //when we are finally in a safe place, lets release the forced position lock |
490 | forcedPosition = null; | 490 | forcedPosition = null; |
491 | } | 491 | } |
492 | } | 492 | } |
493 | } | 493 | } |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 27d9fdb..e85136a 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 | |||
287 | entry.Flags = AccessList.Ban; | 287 | entry.Flags = AccessList.Ban; |
288 | entry.Time = new DateTime(); | 288 | entry.Time = new DateTime(); |
289 | //See if they are on the list, but make sure the owner isn't banned | 289 | //See if they are on the list, but make sure the owner isn't banned |
290 | if (LandData.ParcelAccessList.Contains(entry) && LandData.OwnerID != avatar ) | 290 | if (LandData.ParcelAccessList.Contains(entry) && LandData.OwnerID != avatar) |
291 | { | 291 | { |
292 | //They are banned, so lets send them a notice about this parcel | 292 | //They are banned, so lets send them a notice about this parcel |
293 | return true; | 293 | return true; |
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 845c4c2..5c7f3b7 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 | |||
618 | return objectOwnerMask; | 618 | return objectOwnerMask; |
619 | 619 | ||
620 | // Estate users should be able to edit anything in the sim if RegionOwnerIsGod is set | 620 | // Estate users should be able to edit anything in the sim if RegionOwnerIsGod is set |
621 | if (IsEstateManager(user) && m_RegionOwnerIsGod) | 621 | if (m_RegionOwnerIsGod && IsEstateManager(user) && !IsAdministrator(objectOwner)) |
622 | return objectOwnerMask; | 622 | return objectOwnerMask; |
623 | 623 | ||
624 | // Admin should be able to edit anything in the sim (including admin objects) | 624 | // Admin should be able to edit anything in the sim (including admin objects) |
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 367ff3d..0222b02 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs | |||
@@ -31,21 +31,55 @@ using OpenSim.Framework; | |||
31 | using OpenSim.Region.Framework.Scenes; | 31 | using OpenSim.Region.Framework.Scenes; |
32 | 32 | ||
33 | namespace OpenSim.Region.Framework.Interfaces | 33 | namespace OpenSim.Region.Framework.Interfaces |
34 | { | 34 | { |
35 | public interface IAttachmentsModule | 35 | public interface IAttachmentsModule |
36 | { | 36 | { |
37 | /// <summary> | 37 | /// <summary> |
38 | /// Attach an object to an avatar from the world. | ||
39 | /// </summary> | ||
40 | /// <param name="controllingClient"></param> | ||
41 | /// <param name="localID"></param> | ||
42 | /// <param name="attachPoint"></param> | ||
43 | /// <param name="rot"></param> | ||
44 | /// <param name="silent"></param> | ||
45 | void AttachObject( | ||
46 | IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, bool silent); | ||
47 | |||
48 | /// <summary> | ||
38 | /// Attach an object to an avatar. | 49 | /// Attach an object to an avatar. |
39 | /// </summary> | 50 | /// </summary> |
40 | /// <param name="controllingClient"></param> | 51 | /// <param name="controllingClient"></param> |
41 | /// <param name="localID"></param> | 52 | /// <param name="localID"></param> |
42 | /// <param name="attachPoint"></param> | 53 | /// <param name="attachPoint"></param> |
43 | /// <param name="rot"></param> | 54 | /// <param name="rot"></param> |
44 | /// <param name="pos"></param> | 55 | /// <param name="attachPos"></param> |
45 | /// <param name="silent"></param> | 56 | /// <param name="silent"></param> |
46 | /// <returns>true if the object was successfully attached, false otherwise</returns> | 57 | /// <returns>true if the object was successfully attached, false otherwise</returns> |
47 | bool AttachObject( | 58 | bool AttachObject( |
48 | IClientAPI controllingClient, uint localID, uint attachPoint, Quaternion rot, Vector3 pos, bool silent); | 59 | IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent); |
60 | |||
61 | /// <summary> | ||
62 | /// Rez an attachment from user inventory and change inventory status to match. | ||
63 | /// </summary> | ||
64 | /// <param name="remoteClient"></param> | ||
65 | /// <param name="itemID"></param> | ||
66 | /// <param name="AttachmentPt"></param> | ||
67 | /// <returns>The scene object that was attached. Null if the scene object could not be found</returns> | ||
68 | UUID RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); | ||
69 | |||
70 | /// <summary> | ||
71 | /// Rez an attachment from user inventory | ||
72 | /// </summary> | ||
73 | /// <param name="remoteClient"></param> | ||
74 | /// <param name="itemID"></param> | ||
75 | /// <param name="AttachmentPt"></param> | ||
76 | /// <param name="updateinventoryStatus"> | ||
77 | /// If true, we also update the user's inventory to show that the attachment is set. If false, we do not. | ||
78 | /// False is required so that we don't attempt to update information when a user enters a scene with the | ||
79 | /// attachment already correctly set up in inventory. | ||
80 | /// <returns>The uuid of the scene object that was attached. Null if the scene object could not be found</returns> | ||
81 | UUID RezSingleAttachmentFromInventory( | ||
82 | IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus); | ||
49 | 83 | ||
50 | /// <summary> | 84 | /// <summary> |
51 | /// Update the user inventory to the attachment of an item | 85 | /// Update the user inventory to the attachment of an item |
@@ -54,7 +88,7 @@ namespace OpenSim.Region.Framework.Interfaces | |||
54 | /// <param name="remoteClient"></param> | 88 | /// <param name="remoteClient"></param> |
55 | /// <param name="itemID"></param> | 89 | /// <param name="itemID"></param> |
56 | /// <param name="AttachmentPt"></param> | 90 | /// <param name="AttachmentPt"></param> |
57 | /// <returns></returns> | 91 | /// <returns></returns> |
58 | UUID SetAttachmentInventoryStatus( | 92 | UUID SetAttachmentInventoryStatus( |
59 | SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt); | 93 | SceneObjectGroup att, IClientAPI remoteClient, UUID itemID, uint AttachmentPt); |
60 | 94 | ||
diff --git a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs index 2401402..8185258 100644 --- a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs | |||
@@ -1,4 +1,31 @@ | |||
1 | using System; | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
2 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
3 | 30 | ||
4 | using OpenSim.Framework; | 31 | using OpenSim.Framework; |
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 1650946..37a51d9 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs | |||
@@ -113,15 +113,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
113 | /// Fired when an object is touched/grabbed. | 113 | /// Fired when an object is touched/grabbed. |
114 | /// </summary> | 114 | /// </summary> |
115 | /// The originalID is the local ID of the part that was actually touched. The localID itself is always that of | 115 | /// The originalID is the local ID of the part that was actually touched. The localID itself is always that of |
116 | /// the root part. | 116 | /// the root part. |
117 | public event ObjectGrabDelegate OnObjectGrab; | 117 | public event ObjectGrabDelegate OnObjectGrab; |
118 | public delegate void ObjectGrabDelegate(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs); | 118 | public delegate void ObjectGrabDelegate(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs); |
119 | 119 | ||
120 | public event ObjectGrabDelegate OnObjectGrabbing; | 120 | public event ObjectGrabDelegate OnObjectGrabbing; |
121 | public event ObjectDeGrabDelegate OnObjectDeGrab; | 121 | public event ObjectDeGrabDelegate OnObjectDeGrab; |
122 | public event ScriptResetDelegate OnScriptReset; | 122 | public event ScriptResetDelegate OnScriptReset; |
123 | 123 | ||
124 | public event OnPermissionErrorDelegate OnPermissionError; | 124 | public event OnPermissionErrorDelegate OnPermissionError; |
125 | 125 | ||
126 | /// <summary> | 126 | /// <summary> |
127 | /// Fired when a new script is created. | 127 | /// Fired when a new script is created. |
@@ -169,7 +169,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
169 | 169 | ||
170 | public delegate void ClientClosed(UUID clientID, Scene scene); | 170 | public delegate void ClientClosed(UUID clientID, Scene scene); |
171 | 171 | ||
172 | public event ClientClosed OnClientClosed; | 172 | public event ClientClosed OnClientClosed; |
173 | 173 | ||
174 | /// <summary> | 174 | /// <summary> |
175 | /// This is fired when a scene object property that a script might be interested in (such as color, scale or | 175 | /// 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.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index eb51019..6ebd048 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | |||
@@ -1106,18 +1106,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
1106 | if (folder == null) | 1106 | if (folder == null) |
1107 | return; | 1107 | return; |
1108 | 1108 | ||
1109 | m_log.DebugFormat("[AGENT INVENTORY]: Send Inventory Folder {0} Update to {1} {2}", folder.Name, client.FirstName, client.LastName); | 1109 | // Fetch the folder contents |
1110 | InventoryCollection contents = InventoryService.GetFolderContent(client.AgentId, folder.ID); | 1110 | InventoryCollection contents = InventoryService.GetFolderContent(client.AgentId, folder.ID); |
1111 | InventoryFolderBase containingFolder = new InventoryFolderBase(); | 1111 | |
1112 | containingFolder.ID = folder.ID; | 1112 | // Fetch the folder itself to get its current version |
1113 | containingFolder.Owner = client.AgentId; | 1113 | InventoryFolderBase containingFolder = new InventoryFolderBase(folder.ID, client.AgentId); |
1114 | containingFolder = InventoryService.GetFolder(containingFolder); | 1114 | containingFolder = InventoryService.GetFolder(containingFolder); |
1115 | if (containingFolder != null) | ||
1116 | { | ||
1117 | int version = containingFolder.Version; | ||
1118 | 1115 | ||
1119 | client.SendInventoryFolderDetails(client.AgentId, folder.ID, contents.Items, contents.Folders, version, fetchFolders, fetchItems); | 1116 | //m_log.DebugFormat("[AGENT INVENTORY]: Sending inventory folder contents ({0} nodes) for \"{1}\" to {2} {3}", |
1120 | } | 1117 | // contents.Folders.Count + contents.Items.Count, containingFolder.Name, client.FirstName, client.LastName); |
1118 | |||
1119 | if (containingFolder != null) | ||
1120 | client.SendInventoryFolderDetails(client.AgentId, folder.ID, contents.Items, contents.Folders, containingFolder.Version, fetchFolders, fetchItems); | ||
1121 | } | 1121 | } |
1122 | 1122 | ||
1123 | /// <summary> | 1123 | /// <summary> |
@@ -1846,35 +1846,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1846 | EventManager.TriggerOnAttach(localID, itemID, avatarID); | 1846 | EventManager.TriggerOnAttach(localID, itemID, avatarID); |
1847 | } | 1847 | } |
1848 | 1848 | ||
1849 | /// <summary> | ||
1850 | /// Called when the client receives a request to rez a single attachment on to the avatar from inventory | ||
1851 | /// (RezSingleAttachmentFromInv packet). | ||
1852 | /// </summary> | ||
1853 | /// <param name="remoteClient"></param> | ||
1854 | /// <param name="itemID"></param> | ||
1855 | /// <param name="AttachmentPt"></param> | ||
1856 | /// <returns></returns> | ||
1857 | public UUID RezSingleAttachment(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | ||
1858 | { | ||
1859 | m_log.DebugFormat("[USER INVENTORY]: Rezzing single attachment from item {0} for {1}", itemID, remoteClient.Name); | ||
1860 | |||
1861 | SceneObjectGroup att = m_sceneGraph.RezSingleAttachment(remoteClient, itemID, AttachmentPt); | ||
1862 | |||
1863 | if (att == null) | ||
1864 | { | ||
1865 | AttachmentsModule.ShowDetachInUserInventory(itemID, remoteClient); | ||
1866 | return UUID.Zero; | ||
1867 | } | ||
1868 | |||
1869 | return AttachmentsModule.SetAttachmentInventoryStatus(att, remoteClient, itemID, AttachmentPt); | ||
1870 | } | ||
1871 | |||
1872 | public void RezMultipleAttachments(IClientAPI remoteClient, RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header, | 1849 | public void RezMultipleAttachments(IClientAPI remoteClient, RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header, |
1873 | RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects) | 1850 | RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects) |
1874 | { | 1851 | { |
1875 | foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects) | 1852 | foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects) |
1876 | { | 1853 | { |
1877 | RezSingleAttachment(remoteClient, obj.ItemID, obj.AttachmentPt); | 1854 | AttachmentsModule.RezSingleAttachmentFromInventory(remoteClient, obj.ItemID, obj.AttachmentPt); |
1878 | } | 1855 | } |
1879 | } | 1856 | } |
1880 | 1857 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index d5d1825..03f1ee2 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -2003,7 +2003,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2003 | public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) | 2003 | public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) |
2004 | { | 2004 | { |
2005 | return m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, sendClientUpdates); | 2005 | return m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, sendClientUpdates); |
2006 | } | 2006 | } |
2007 | 2007 | ||
2008 | /// <summary> | 2008 | /// <summary> |
2009 | /// Delete every object from the scene | 2009 | /// Delete every object from the scene |
@@ -2365,10 +2365,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
2365 | //m_log.DebugFormat(" >>> IncomingCreateObject(userID, itemID) <<< {0} {1}", userID, itemID); | 2365 | //m_log.DebugFormat(" >>> IncomingCreateObject(userID, itemID) <<< {0} {1}", userID, itemID); |
2366 | 2366 | ||
2367 | ScenePresence sp = GetScenePresence(userID); | 2367 | ScenePresence sp = GetScenePresence(userID); |
2368 | if (sp != null) | 2368 | if (sp != null && AttachmentsModule != null) |
2369 | { | 2369 | { |
2370 | uint attPt = (uint)sp.Appearance.GetAttachpoint(itemID); | 2370 | uint attPt = (uint)sp.Appearance.GetAttachpoint(itemID); |
2371 | m_sceneGraph.RezSingleAttachment(sp.ControllingClient, itemID, attPt); | 2371 | AttachmentsModule.RezSingleAttachmentFromInventory(sp.ControllingClient, itemID, attPt); |
2372 | } | 2372 | } |
2373 | 2373 | ||
2374 | return false; | 2374 | return false; |
@@ -2669,14 +2669,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
2669 | } | 2669 | } |
2670 | 2670 | ||
2671 | public virtual void SubscribeToClientAttachmentEvents(IClientAPI client) | 2671 | public virtual void SubscribeToClientAttachmentEvents(IClientAPI client) |
2672 | { | 2672 | { |
2673 | client.OnRezSingleAttachmentFromInv += RezSingleAttachment; | ||
2674 | client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachments; | 2673 | client.OnRezMultipleAttachmentsFromInv += RezMultipleAttachments; |
2675 | client.OnObjectAttach += m_sceneGraph.AttachObject; | ||
2676 | client.OnObjectDetach += m_sceneGraph.DetachObject; | 2674 | client.OnObjectDetach += m_sceneGraph.DetachObject; |
2677 | 2675 | ||
2678 | if (AttachmentsModule != null) | 2676 | if (AttachmentsModule != null) |
2677 | { | ||
2678 | client.OnRezSingleAttachmentFromInv += AttachmentsModule.RezSingleAttachmentFromInventory; | ||
2679 | client.OnObjectAttach += AttachmentsModule.AttachObject; | ||
2679 | client.OnDetachAttachmentIntoInv += AttachmentsModule.ShowDetachInUserInventory; | 2680 | client.OnDetachAttachmentIntoInv += AttachmentsModule.ShowDetachInUserInventory; |
2681 | } | ||
2680 | } | 2682 | } |
2681 | 2683 | ||
2682 | public virtual void SubscribeToClientTeleportEvents(IClientAPI client) | 2684 | public virtual void SubscribeToClientTeleportEvents(IClientAPI client) |
@@ -2723,7 +2725,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2723 | } | 2725 | } |
2724 | 2726 | ||
2725 | protected virtual void UnsubscribeToClientEvents(IClientAPI client) | 2727 | protected virtual void UnsubscribeToClientEvents(IClientAPI client) |
2726 | { | 2728 | { |
2727 | } | 2729 | } |
2728 | 2730 | ||
2729 | /// <summary> | 2731 | /// <summary> |
@@ -2801,7 +2803,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2801 | client.OnRezObject -= RezObject; | 2803 | client.OnRezObject -= RezObject; |
2802 | } | 2804 | } |
2803 | 2805 | ||
2804 | |||
2805 | public virtual void UnSubscribeToClientInventoryEvents(IClientAPI client) | 2806 | public virtual void UnSubscribeToClientInventoryEvents(IClientAPI client) |
2806 | { | 2807 | { |
2807 | client.OnCreateNewInventoryItem -= CreateNewInventoryItem; | 2808 | client.OnCreateNewInventoryItem -= CreateNewInventoryItem; |
@@ -2824,14 +2825,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
2824 | } | 2825 | } |
2825 | 2826 | ||
2826 | public virtual void UnSubscribeToClientAttachmentEvents(IClientAPI client) | 2827 | public virtual void UnSubscribeToClientAttachmentEvents(IClientAPI client) |
2827 | { | 2828 | { |
2828 | client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachments; | 2829 | client.OnRezMultipleAttachmentsFromInv -= RezMultipleAttachments; |
2829 | client.OnRezSingleAttachmentFromInv -= RezSingleAttachment; | ||
2830 | client.OnObjectAttach -= m_sceneGraph.AttachObject; | ||
2831 | client.OnObjectDetach -= m_sceneGraph.DetachObject; | 2830 | client.OnObjectDetach -= m_sceneGraph.DetachObject; |
2832 | 2831 | ||
2833 | if (AttachmentsModule != null) | 2832 | if (AttachmentsModule != null) |
2833 | { | ||
2834 | client.OnRezSingleAttachmentFromInv -= AttachmentsModule.RezSingleAttachmentFromInventory; | ||
2835 | client.OnObjectAttach -= AttachmentsModule.AttachObject; | ||
2834 | client.OnDetachAttachmentIntoInv -= AttachmentsModule.ShowDetachInUserInventory; | 2836 | client.OnDetachAttachmentIntoInv -= AttachmentsModule.ShowDetachInUserInventory; |
2837 | } | ||
2835 | } | 2838 | } |
2836 | 2839 | ||
2837 | public virtual void UnSubscribeToClientTeleportEvents(IClientAPI client) | 2840 | public virtual void UnSubscribeToClientTeleportEvents(IClientAPI client) |
@@ -3559,7 +3562,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3559 | { | 3562 | { |
3560 | foreach (var parcel in AllParcels()) | 3563 | foreach (var parcel in AllParcels()) |
3561 | { | 3564 | { |
3562 | if( parcel.ContainsPoint((int)x,(int)y)) | 3565 | if (parcel.ContainsPoint((int)x,(int)y)) |
3563 | { | 3566 | { |
3564 | return parcel; | 3567 | return parcel; |
3565 | } | 3568 | } |
@@ -4998,7 +5001,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
4998 | private Vector3 GetPositionAtAvatarHeightOrGroundHeight(ScenePresence avatar, float x, float y) | 5001 | private Vector3 GetPositionAtAvatarHeightOrGroundHeight(ScenePresence avatar, float x, float y) |
4999 | { | 5002 | { |
5000 | Vector3 ground = GetPositionAtGround(x, y); | 5003 | Vector3 ground = GetPositionAtGround(x, y); |
5001 | if( avatar.AbsolutePosition.Z > ground.Z) | 5004 | if (avatar.AbsolutePosition.Z > ground.Z) |
5002 | { | 5005 | { |
5003 | ground.Z = avatar.AbsolutePosition.Z; | 5006 | ground.Z = avatar.AbsolutePosition.Z; |
5004 | } | 5007 | } |
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 4e41b07..db70d6a 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs | |||
@@ -510,94 +510,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
510 | } | 510 | } |
511 | } | 511 | } |
512 | 512 | ||
513 | /// <summary> | ||
514 | /// Event Handling routine for Attach Object | ||
515 | /// </summary> | ||
516 | /// <param name="remoteClient"></param> | ||
517 | /// <param name="objectLocalID"></param> | ||
518 | /// <param name="AttachmentPt"></param> | ||
519 | /// <param name="rot"></param> | ||
520 | protected internal void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, bool silent) | ||
521 | { | ||
522 | // If we can't take it, we can't attach it! | ||
523 | SceneObjectPart part = m_parentScene.GetSceneObjectPart(objectLocalID); | ||
524 | if (part == null) | ||
525 | return; | ||
526 | |||
527 | if (!m_parentScene.Permissions.CanTakeObject(part.UUID, remoteClient.AgentId)) | ||
528 | return; | ||
529 | |||
530 | // Calls attach with a Zero position | ||
531 | if (m_parentScene.AttachmentsModule.AttachObject(remoteClient, objectLocalID, AttachmentPt, rot, Vector3.Zero, false)) | ||
532 | { | ||
533 | m_parentScene.SendAttachEvent(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); | ||
534 | |||
535 | // Save avatar attachment information | ||
536 | ScenePresence presence; | ||
537 | if (m_parentScene.AvatarFactory != null && m_parentScene.TryGetAvatar(remoteClient.AgentId, out presence)) | ||
538 | { | ||
539 | m_log.Info( | ||
540 | "[SCENE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId | ||
541 | + ", AttachmentPoint: " + AttachmentPt); | ||
542 | |||
543 | m_parentScene.AvatarFactory.UpdateDatabase(remoteClient.AgentId, presence.Appearance); | ||
544 | } | ||
545 | } | ||
546 | } | ||
547 | |||
548 | /// <summary> | ||
549 | /// Rez an attachment | ||
550 | /// </summary> | ||
551 | /// <param name="remoteClient"></param> | ||
552 | /// <param name="itemID"></param> | ||
553 | /// <param name="AttachmentPt"></param> | ||
554 | /// <returns>The scene object that was attached. Null if the scene object could not be found</returns> | ||
555 | public SceneObjectGroup RezSingleAttachment(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) | ||
556 | { | ||
557 | IInventoryAccessModule invAccess = m_parentScene.RequestModuleInterface<IInventoryAccessModule>(); | ||
558 | if (invAccess != null) | ||
559 | { | ||
560 | SceneObjectGroup objatt = invAccess.RezObject(remoteClient, | ||
561 | itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, | ||
562 | false, false, remoteClient.AgentId, true); | ||
563 | |||
564 | // m_log.DebugFormat( | ||
565 | // "[SCENE GRAPH]: Retrieved single object {0} for attachment to {1} on point {2}", | ||
566 | // objatt.Name, remoteClient.Name, AttachmentPt); | ||
567 | |||
568 | if (objatt != null) | ||
569 | { | ||
570 | bool tainted = false; | ||
571 | if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint()) | ||
572 | tainted = true; | ||
573 | |||
574 | m_parentScene.AttachmentsModule.AttachObject( | ||
575 | remoteClient, objatt.LocalId, AttachmentPt, Quaternion.Identity, objatt.AbsolutePosition, false); | ||
576 | //objatt.ScheduleGroupForFullUpdate(); | ||
577 | |||
578 | if (tainted) | ||
579 | objatt.HasGroupChanged = true; | ||
580 | |||
581 | // Fire after attach, so we don't get messy perms dialogs | ||
582 | // 3 == AttachedRez | ||
583 | objatt.CreateScriptInstances(0, true, m_parentScene.DefaultScriptEngine, 3); | ||
584 | |||
585 | // Do this last so that event listeners have access to all the effects of the attachment | ||
586 | m_parentScene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, remoteClient.AgentId); | ||
587 | } | ||
588 | else | ||
589 | { | ||
590 | m_log.WarnFormat( | ||
591 | "[SCENE GRAPH]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", | ||
592 | itemID, remoteClient.Name, AttachmentPt); | ||
593 | } | ||
594 | |||
595 | return objatt; | ||
596 | } | ||
597 | |||
598 | return null; | ||
599 | } | ||
600 | |||
601 | protected internal ScenePresence CreateAndAddChildScenePresence(IClientAPI client, AvatarAppearance appearance) | 513 | protected internal ScenePresence CreateAndAddChildScenePresence(IClientAPI client, AvatarAppearance appearance) |
602 | { | 514 | { |
603 | ScenePresence newAvatar = null; | 515 | ScenePresence newAvatar = null; |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 6c4b39d..d083119 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -645,7 +645,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
645 | ApplyPhysics(m_scene.m_physicalPrim); | 645 | ApplyPhysics(m_scene.m_physicalPrim); |
646 | 646 | ||
647 | // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled | 647 | // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled |
648 | // for the same object with very different properties. The caller must schedule the update. | 648 | // for the same object with very different properties. The caller must schedule the update. |
649 | //ScheduleGroupForFullUpdate(); | 649 | //ScheduleGroupForFullUpdate(); |
650 | } | 650 | } |
651 | 651 | ||
@@ -2185,11 +2185,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2185 | /// Immediately send a full update for this scene object. | 2185 | /// Immediately send a full update for this scene object. |
2186 | /// </summary> | 2186 | /// </summary> |
2187 | public void SendGroupFullUpdate() | 2187 | public void SendGroupFullUpdate() |
2188 | { | 2188 | { |
2189 | if (IsDeleted) | 2189 | if (IsDeleted) |
2190 | return; | 2190 | return; |
2191 | 2191 | ||
2192 | // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); | 2192 | // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); |
2193 | 2193 | ||
2194 | RootPart.SendFullUpdateToAllClients(); | 2194 | RootPart.SendFullUpdateToAllClients(); |
2195 | 2195 | ||
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index c8ac014..48e34ee 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -2060,6 +2060,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2060 | { | 2060 | { |
2061 | m_lastColliders.Remove(localID); | 2061 | m_lastColliders.Remove(localID); |
2062 | } | 2062 | } |
2063 | |||
2063 | if (m_parentGroup == null) | 2064 | if (m_parentGroup == null) |
2064 | return; | 2065 | return; |
2065 | if (m_parentGroup.IsDeleted) | 2066 | if (m_parentGroup.IsDeleted) |
@@ -2855,7 +2856,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2855 | { | 2856 | { |
2856 | SendFullUpdateToClient(remoteClient, clientFlags); | 2857 | SendFullUpdateToClient(remoteClient, clientFlags); |
2857 | } | 2858 | } |
2858 | } | 2859 | } |
2859 | 2860 | ||
2860 | /// <summary> | 2861 | /// <summary> |
2861 | /// Send a full update for this part to all clients. | 2862 | /// Send a full update for this part to all clients. |
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index d8f93d7..24179a9 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -686,7 +686,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
686 | 686 | ||
687 | UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid); | 687 | UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid); |
688 | 688 | ||
689 | m_userLevel = account.UserLevel; | 689 | if (account != null) |
690 | m_userLevel = account.UserLevel; | ||
690 | 691 | ||
691 | IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); | 692 | IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); |
692 | if (gm != null) | 693 | if (gm != null) |
@@ -3957,7 +3958,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3957 | { | 3958 | { |
3958 | if (null == m_appearance) | 3959 | if (null == m_appearance) |
3959 | { | 3960 | { |
3960 | m_log.WarnFormat("[ATTACHMENT] Appearance has not been initialized for agent {0}", UUID); | 3961 | m_log.WarnFormat("[ATTACHMENT]: Appearance has not been initialized for agent {0}", UUID); |
3961 | return; | 3962 | return; |
3962 | } | 3963 | } |
3963 | 3964 | ||
@@ -3981,12 +3982,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3981 | try | 3982 | try |
3982 | { | 3983 | { |
3983 | // Rez from inventory | 3984 | // Rez from inventory |
3984 | UUID asset = m_scene.RezSingleAttachment(ControllingClient, | 3985 | UUID asset |
3985 | itemID, (uint)p); | 3986 | = m_scene.AttachmentsModule.RezSingleAttachmentFromInventory(ControllingClient, itemID, (uint)p); |
3986 | |||
3987 | m_log.InfoFormat("[ATTACHMENT]: Rezzed attachment in point {0} from item {1} and asset {2} ({3})", | ||
3988 | p, itemID, assetID, asset); | ||
3989 | 3987 | ||
3988 | m_log.InfoFormat( | ||
3989 | "[ATTACHMENT]: Rezzed attachment in point {0} from item {1} and asset {2} ({3})", | ||
3990 | p, itemID, assetID, asset); | ||
3990 | } | 3991 | } |
3991 | catch (Exception e) | 3992 | catch (Exception e) |
3992 | { | 3993 | { |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index b50d4ca..78f2ae3 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 | |||
86 | public void TestDeleteSceneObjectAsync() | 86 | public void TestDeleteSceneObjectAsync() |
87 | { | 87 | { |
88 | TestHelper.InMethod(); | 88 | TestHelper.InMethod(); |
89 | //log4net.Config.XmlConfigurator.Configure(); | ||
89 | 90 | ||
90 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); | 91 | UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); |
91 | 92 | ||
@@ -97,15 +98,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
97 | 98 | ||
98 | SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene); | 99 | SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene); |
99 | 100 | ||
100 | try | 101 | IClientAPI client = SceneSetupHelpers.AddRootAgent(scene, agentId); |
101 | { | 102 | scene.DeRezObject(client, part.LocalId, UUID.Zero, DeRezAction.Delete, UUID.Zero); |
102 | IClientAPI client = SceneSetupHelpers.AddRootAgent(scene, agentId); | 103 | |
103 | scene.DeRezObject(client, part.LocalId, UUID.Zero, DeRezAction.Delete, UUID.Zero); | ||
104 | } | ||
105 | catch (Exception e) | ||
106 | { | ||
107 | Console.WriteLine("Exception: " + e.StackTrace); | ||
108 | } | ||
109 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | 104 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); |
110 | 105 | ||
111 | Assert.That(retrievedPart, Is.Not.Null); | 106 | Assert.That(retrievedPart, Is.Not.Null); |
diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs index 198962b..f13c323 100644 --- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs +++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs | |||
@@ -108,12 +108,11 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
108 | private bool[] m_colliderarr = new bool[11]; | 108 | private bool[] m_colliderarr = new bool[11]; |
109 | private bool[] m_colliderGroundarr = new bool[11]; | 109 | private bool[] m_colliderGroundarr = new bool[11]; |
110 | 110 | ||
111 | |||
112 | |||
113 | private BulletDotNETScene m_parent_scene; | 111 | private BulletDotNETScene m_parent_scene; |
114 | 112 | ||
115 | public int m_eventsubscription = 0; | 113 | public int m_eventsubscription = 0; |
116 | // private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate(); | 114 | private CollisionEventUpdate CollisionEventsThisFrame = null; |
115 | private int m_requestedUpdateFrequency = 0; | ||
117 | 116 | ||
118 | 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) | 117 | 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) |
119 | { | 118 | { |
@@ -212,7 +211,8 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
212 | m_mass = Mass; | 211 | m_mass = Mass; |
213 | 212 | ||
214 | Body = new btRigidBody(m_mass, m_bodyMotionState, Shell); | 213 | Body = new btRigidBody(m_mass, m_bodyMotionState, Shell); |
215 | Body.setUserPointer(new IntPtr((int)Body.Handle)); | 214 | // this is used for self identification. User localID instead of body handle |
215 | Body.setUserPointer(new IntPtr((int)m_localID)); | ||
216 | 216 | ||
217 | if (ClosestCastResult != null) | 217 | if (ClosestCastResult != null) |
218 | ClosestCastResult.Dispose(); | 218 | ClosestCastResult.Dispose(); |
@@ -716,6 +716,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
716 | public override void SubscribeEvents(int ms) | 716 | public override void SubscribeEvents(int ms) |
717 | { | 717 | { |
718 | m_eventsubscription = ms; | 718 | m_eventsubscription = ms; |
719 | m_requestedUpdateFrequency = ms; | ||
719 | m_parent_scene.addCollisionEventReporting(this); | 720 | m_parent_scene.addCollisionEventReporting(this); |
720 | } | 721 | } |
721 | 722 | ||
@@ -723,6 +724,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
723 | { | 724 | { |
724 | m_parent_scene.remCollisionEventReporting(this); | 725 | m_parent_scene.remCollisionEventReporting(this); |
725 | m_eventsubscription = 0; | 726 | m_eventsubscription = 0; |
727 | m_requestedUpdateFrequency = 0; | ||
726 | } | 728 | } |
727 | 729 | ||
728 | public override bool SubscribedEvents() | 730 | public override bool SubscribedEvents() |
@@ -732,6 +734,29 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
732 | return false; | 734 | return false; |
733 | } | 735 | } |
734 | 736 | ||
737 | public void AddCollision(uint collideWith, ContactPoint contact) | ||
738 | { | ||
739 | if (CollisionEventsThisFrame == null) | ||
740 | { | ||
741 | CollisionEventsThisFrame = new CollisionEventUpdate(); | ||
742 | } | ||
743 | CollisionEventsThisFrame.addCollider(collideWith, contact); | ||
744 | } | ||
745 | |||
746 | public void SendCollisions() | ||
747 | { | ||
748 | if (m_eventsubscription >= m_requestedUpdateFrequency) | ||
749 | { | ||
750 | if (CollisionEventsThisFrame != null) | ||
751 | { | ||
752 | base.SendCollisionUpdate(CollisionEventsThisFrame); | ||
753 | } | ||
754 | CollisionEventsThisFrame = new CollisionEventUpdate(); | ||
755 | m_eventsubscription = 0; | ||
756 | } | ||
757 | return; | ||
758 | } | ||
759 | |||
735 | internal void Dispose() | 760 | internal void Dispose() |
736 | { | 761 | { |
737 | if (Body.isInWorld()) | 762 | if (Body.isInWorld()) |
diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs index 920ed96..dc3229a 100644 --- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs +++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs | |||
@@ -154,7 +154,8 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
154 | private Vector3 _target_velocity; | 154 | private Vector3 _target_velocity; |
155 | 155 | ||
156 | public int m_eventsubscription; | 156 | public int m_eventsubscription; |
157 | // private CollisionEventUpdate CollisionEventsThisFrame = null; | 157 | private int m_requestedUpdateFrequency = 0; |
158 | private CollisionEventUpdate CollisionEventsThisFrame = null; | ||
158 | 159 | ||
159 | public volatile bool childPrim; | 160 | public volatile bool childPrim; |
160 | 161 | ||
@@ -595,6 +596,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
595 | public override void SubscribeEvents(int ms) | 596 | public override void SubscribeEvents(int ms) |
596 | { | 597 | { |
597 | m_eventsubscription = ms; | 598 | m_eventsubscription = ms; |
599 | m_requestedUpdateFrequency = ms; | ||
598 | _parent_scene.addCollisionEventReporting(this); | 600 | _parent_scene.addCollisionEventReporting(this); |
599 | } | 601 | } |
600 | 602 | ||
@@ -602,6 +604,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
602 | { | 604 | { |
603 | _parent_scene.remCollisionEventReporting(this); | 605 | _parent_scene.remCollisionEventReporting(this); |
604 | m_eventsubscription = 0; | 606 | m_eventsubscription = 0; |
607 | m_requestedUpdateFrequency = 0; | ||
605 | } | 608 | } |
606 | 609 | ||
607 | public override bool SubscribedEvents() | 610 | public override bool SubscribedEvents() |
@@ -611,7 +614,28 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
611 | 614 | ||
612 | #endregion | 615 | #endregion |
613 | 616 | ||
617 | public void AddCollision(uint collideWith, ContactPoint contact) | ||
618 | { | ||
619 | if (CollisionEventsThisFrame == null) | ||
620 | { | ||
621 | CollisionEventsThisFrame = new CollisionEventUpdate(); | ||
622 | } | ||
623 | CollisionEventsThisFrame.addCollider(collideWith, contact); | ||
624 | } | ||
614 | 625 | ||
626 | public void SendCollisions() | ||
627 | { | ||
628 | if (m_eventsubscription >= m_requestedUpdateFrequency) | ||
629 | { | ||
630 | if (CollisionEventsThisFrame != null) | ||
631 | { | ||
632 | base.SendCollisionUpdate(CollisionEventsThisFrame); | ||
633 | } | ||
634 | CollisionEventsThisFrame = null; | ||
635 | // m_eventsubscription = 0; | ||
636 | } | ||
637 | return; | ||
638 | } | ||
615 | 639 | ||
616 | internal void Dispose() | 640 | internal void Dispose() |
617 | { | 641 | { |
@@ -759,7 +783,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
759 | { | 783 | { |
760 | if (m_taintadd) | 784 | if (m_taintadd) |
761 | { | 785 | { |
762 | m_log.Debug("[PHYSICS]: TaintAdd"); | 786 | // m_log.Debug("[PHYSICS]: TaintAdd"); |
763 | changeadd(timestep); | 787 | changeadd(timestep); |
764 | } | 788 | } |
765 | 789 | ||
@@ -771,7 +795,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
771 | SetBody(Mass); | 795 | SetBody(Mass); |
772 | else | 796 | else |
773 | SetBody(0); | 797 | SetBody(0); |
774 | m_log.Debug("[PHYSICS]: GEOM_DOESNT_EXSIT"); | 798 | // m_log.Debug("[PHYSICS]: GEOM_DOESNT_EXSIT"); |
775 | } | 799 | } |
776 | 800 | ||
777 | if (prim_geom.Handle == IntPtr.Zero) | 801 | if (prim_geom.Handle == IntPtr.Zero) |
@@ -782,31 +806,31 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
782 | SetBody(Mass); | 806 | SetBody(Mass); |
783 | else | 807 | else |
784 | SetBody(0); | 808 | SetBody(0); |
785 | m_log.Debug("[PHYSICS]: GEOM_DOESNT_EXSIT"); | 809 | // m_log.Debug("[PHYSICS]: GEOM_DOESNT_EXSIT"); |
786 | 810 | ||
787 | } | 811 | } |
788 | 812 | ||
789 | if (!_position.ApproxEquals(m_taintposition, 0f)) | 813 | if (!_position.ApproxEquals(m_taintposition, 0f)) |
790 | { | 814 | { |
791 | m_log.Debug("[PHYSICS]: TaintMove"); | 815 | // m_log.Debug("[PHYSICS]: TaintMove"); |
792 | changemove(timestep); | 816 | changemove(timestep); |
793 | } | 817 | } |
794 | if (m_taintrot != _orientation) | 818 | if (m_taintrot != _orientation) |
795 | { | 819 | { |
796 | m_log.Debug("[PHYSICS]: TaintRotate"); | 820 | // m_log.Debug("[PHYSICS]: TaintRotate"); |
797 | rotate(timestep); | 821 | rotate(timestep); |
798 | } // | 822 | } // |
799 | 823 | ||
800 | if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent)) | 824 | if (m_taintPhysics != m_isphysical && !(m_taintparent != _parent)) |
801 | { | 825 | { |
802 | m_log.Debug("[PHYSICS]: TaintPhysics"); | 826 | // m_log.Debug("[PHYSICS]: TaintPhysics"); |
803 | changePhysicsStatus(timestep); | 827 | changePhysicsStatus(timestep); |
804 | } | 828 | } |
805 | // | 829 | // |
806 | 830 | ||
807 | if (!_size.ApproxEquals(m_taintsize, 0f)) | 831 | if (!_size.ApproxEquals(m_taintsize, 0f)) |
808 | { | 832 | { |
809 | m_log.Debug("[PHYSICS]: TaintSize"); | 833 | // m_log.Debug("[PHYSICS]: TaintSize"); |
810 | changesize(timestep); | 834 | changesize(timestep); |
811 | } | 835 | } |
812 | 836 | ||
@@ -814,43 +838,43 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
814 | 838 | ||
815 | if (m_taintshape) | 839 | if (m_taintshape) |
816 | { | 840 | { |
817 | m_log.Debug("[PHYSICS]: TaintShape"); | 841 | // m_log.Debug("[PHYSICS]: TaintShape"); |
818 | changeshape(timestep); | 842 | changeshape(timestep); |
819 | } // | 843 | } // |
820 | 844 | ||
821 | if (m_taintforce) | 845 | if (m_taintforce) |
822 | { | 846 | { |
823 | m_log.Debug("[PHYSICS]: TaintForce"); | 847 | // m_log.Debug("[PHYSICS]: TaintForce"); |
824 | changeAddForce(timestep); | 848 | changeAddForce(timestep); |
825 | } | 849 | } |
826 | if (m_taintaddangularforce) | 850 | if (m_taintaddangularforce) |
827 | { | 851 | { |
828 | m_log.Debug("[PHYSICS]: TaintAngularForce"); | 852 | // m_log.Debug("[PHYSICS]: TaintAngularForce"); |
829 | changeAddAngularForce(timestep); | 853 | changeAddAngularForce(timestep); |
830 | } | 854 | } |
831 | if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f)) | 855 | if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f)) |
832 | { | 856 | { |
833 | m_log.Debug("[PHYSICS]: TaintTorque"); | 857 | // m_log.Debug("[PHYSICS]: TaintTorque"); |
834 | changeSetTorque(timestep); | 858 | changeSetTorque(timestep); |
835 | } | 859 | } |
836 | if (m_taintdisable) | 860 | if (m_taintdisable) |
837 | { | 861 | { |
838 | m_log.Debug("[PHYSICS]: TaintDisable"); | 862 | // m_log.Debug("[PHYSICS]: TaintDisable"); |
839 | changedisable(timestep); | 863 | changedisable(timestep); |
840 | } | 864 | } |
841 | if (m_taintselected != m_isSelected) | 865 | if (m_taintselected != m_isSelected) |
842 | { | 866 | { |
843 | m_log.Debug("[PHYSICS]: TaintSelected"); | 867 | // m_log.Debug("[PHYSICS]: TaintSelected"); |
844 | changeSelectedStatus(timestep); | 868 | changeSelectedStatus(timestep); |
845 | } | 869 | } |
846 | if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f)) | 870 | if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f)) |
847 | { | 871 | { |
848 | m_log.Debug("[PHYSICS]: TaintVelocity"); | 872 | // m_log.Debug("[PHYSICS]: TaintVelocity"); |
849 | changevelocity(timestep); | 873 | changevelocity(timestep); |
850 | } | 874 | } |
851 | if (m_taintparent != _parent) | 875 | if (m_taintparent != _parent) |
852 | { | 876 | { |
853 | m_log.Debug("[PHYSICS]: TaintLink"); | 877 | // m_log.Debug("[PHYSICS]: TaintLink"); |
854 | changelink(timestep); | 878 | changelink(timestep); |
855 | } | 879 | } |
856 | if (m_taintCollidesWater != m_collidesWater) | 880 | if (m_taintCollidesWater != m_collidesWater) |
@@ -859,7 +883,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
859 | } | 883 | } |
860 | if (!m_angularlock.ApproxEquals(m_taintAngularLock, 0)) | 884 | if (!m_angularlock.ApproxEquals(m_taintAngularLock, 0)) |
861 | { | 885 | { |
862 | m_log.Debug("[PHYSICS]: TaintAngularLock"); | 886 | // m_log.Debug("[PHYSICS]: TaintAngularLock"); |
863 | changeAngularLock(timestep); | 887 | changeAngularLock(timestep); |
864 | } | 888 | } |
865 | if (m_taintremove) | 889 | if (m_taintremove) |
@@ -917,7 +941,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
917 | private void changemove(float timestep) | 941 | private void changemove(float timestep) |
918 | { | 942 | { |
919 | 943 | ||
920 | m_log.Debug("[PHYSICS]: _________ChangeMove"); | 944 | // m_log.Debug("[PHYSICS]: _________ChangeMove"); |
921 | if (!m_isphysical) | 945 | if (!m_isphysical) |
922 | { | 946 | { |
923 | tempTransform2 = Body.getWorldTransform(); | 947 | tempTransform2 = Body.getWorldTransform(); |
@@ -977,7 +1001,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
977 | 1001 | ||
978 | private void rotate(float timestep) | 1002 | private void rotate(float timestep) |
979 | { | 1003 | { |
980 | m_log.Debug("[PHYSICS]: _________ChangeRotate"); | 1004 | // m_log.Debug("[PHYSICS]: _________ChangeRotate"); |
981 | tempTransform2 = Body.getWorldTransform(); | 1005 | tempTransform2 = Body.getWorldTransform(); |
982 | tempOrientation2 = new btQuaternion(_orientation.X, _orientation.Y, _orientation.Z, _orientation.W); | 1006 | tempOrientation2 = new btQuaternion(_orientation.X, _orientation.Y, _orientation.Z, _orientation.W); |
983 | tempTransform2.setRotation(tempOrientation2); | 1007 | tempTransform2.setRotation(tempOrientation2); |
@@ -1000,7 +1024,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
1000 | //Body = null; | 1024 | //Body = null; |
1001 | // TODO: dispose parts that make up body | 1025 | // TODO: dispose parts that make up body |
1002 | } | 1026 | } |
1003 | m_log.Debug("[PHYSICS]: _________ChangePhysics"); | 1027 | // m_log.Debug("[PHYSICS]: _________ChangePhysics"); |
1004 | 1028 | ||
1005 | ProcessGeomCreation(); | 1029 | ProcessGeomCreation(); |
1006 | 1030 | ||
@@ -1092,7 +1116,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
1092 | // TODO: dispose parts that make up body | 1116 | // TODO: dispose parts that make up body |
1093 | } | 1117 | } |
1094 | 1118 | ||
1095 | m_log.Debug("[PHYSICS]: _________ChangeSize"); | 1119 | // m_log.Debug("[PHYSICS]: _________ChangeSize"); |
1096 | SetCollisionShape(null); | 1120 | SetCollisionShape(null); |
1097 | // Construction of new prim | 1121 | // Construction of new prim |
1098 | ProcessGeomCreation(); | 1122 | ProcessGeomCreation(); |
@@ -1297,13 +1321,13 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
1297 | // TODO: throw new NotImplementedException(); | 1321 | // TODO: throw new NotImplementedException(); |
1298 | if (m_taintselected) | 1322 | if (m_taintselected) |
1299 | { | 1323 | { |
1300 | Body.setCollisionFlags((int)ContactFlags.CF_NO_CONTACT_RESPONSE); | 1324 | // Body.setCollisionFlags((int)ContactFlags.CF_NO_CONTACT_RESPONSE); |
1301 | disableBodySoft(); | 1325 | disableBodySoft(); |
1302 | 1326 | ||
1303 | } | 1327 | } |
1304 | else | 1328 | else |
1305 | { | 1329 | { |
1306 | Body.setCollisionFlags(0 | (int)ContactFlags.CF_CUSTOM_MATERIAL_CALLBACK); | 1330 | // Body.setCollisionFlags(0 | (int)ContactFlags.CF_CUSTOM_MATERIAL_CALLBACK); |
1307 | enableBodySoft(); | 1331 | enableBodySoft(); |
1308 | } | 1332 | } |
1309 | m_isSelected = m_taintselected; | 1333 | m_isSelected = m_taintselected; |
@@ -1605,6 +1629,11 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
1605 | enableBodySoft(); | 1629 | enableBodySoft(); |
1606 | } | 1630 | } |
1607 | */ | 1631 | */ |
1632 | if (!Body.isActive()) | ||
1633 | { | ||
1634 | Body.clearForces(); | ||
1635 | enableBodySoft(); | ||
1636 | } | ||
1608 | // 35x10 = 350n times the mass per second applied maximum. | 1637 | // 35x10 = 350n times the mass per second applied maximum. |
1609 | 1638 | ||
1610 | float nmax = 35f * m_mass; | 1639 | float nmax = 35f * m_mass; |
@@ -1632,6 +1661,12 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
1632 | Body.applyCentralImpulse(tempAddForce); | 1661 | Body.applyCentralImpulse(tempAddForce); |
1633 | } | 1662 | } |
1634 | } | 1663 | } |
1664 | else | ||
1665 | { | ||
1666 | // if no forces on the prim, make sure everything is zero | ||
1667 | Body.clearForces(); | ||
1668 | enableBodySoft(); | ||
1669 | } | ||
1635 | } | 1670 | } |
1636 | else | 1671 | else |
1637 | { | 1672 | { |
@@ -1985,7 +2020,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
1985 | 2020 | ||
1986 | public void CreateGeom(IntPtr m_targetSpace, IMesh p_mesh) | 2021 | public void CreateGeom(IntPtr m_targetSpace, IMesh p_mesh) |
1987 | { | 2022 | { |
1988 | m_log.Debug("[PHYSICS]: _________CreateGeom"); | 2023 | // m_log.Debug("[PHYSICS]: _________CreateGeom"); |
1989 | if (p_mesh != null) | 2024 | if (p_mesh != null) |
1990 | { | 2025 | { |
1991 | //_mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); | 2026 | //_mesh = _parent_scene.mesher.CreateMesh(m_primName, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); |
@@ -2042,7 +2077,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
2042 | // TODO: Set Collision Body Mesh | 2077 | // TODO: Set Collision Body Mesh |
2043 | // This sleeper is there to moderate how long it takes between | 2078 | // This sleeper is there to moderate how long it takes between |
2044 | // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object | 2079 | // setting up the mesh and pre-processing it when we get rapid fire mesh requests on a single object |
2045 | m_log.Debug("_________SetMesh"); | 2080 | // m_log.Debug("_________SetMesh"); |
2046 | Thread.Sleep(10); | 2081 | Thread.Sleep(10); |
2047 | 2082 | ||
2048 | //Kill Body so that mesh can re-make the geom | 2083 | //Kill Body so that mesh can re-make the geom |
@@ -2159,7 +2194,14 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
2159 | 2194 | ||
2160 | // Body = new btRigidBody(mass, tempMotionState1, prim_geom); | 2195 | // Body = new btRigidBody(mass, tempMotionState1, prim_geom); |
2161 | //else | 2196 | //else |
2162 | Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); | 2197 | // Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); |
2198 | if (Body == null) | ||
2199 | { | ||
2200 | Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); | ||
2201 | // add localID so we can later map bullet object back to OpenSim object | ||
2202 | Body.setUserPointer(new IntPtr((int)m_localID)); | ||
2203 | } | ||
2204 | |||
2163 | 2205 | ||
2164 | if (prim_geom is btGImpactMeshShape) | 2206 | if (prim_geom is btGImpactMeshShape) |
2165 | { | 2207 | { |
@@ -2250,7 +2292,13 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
2250 | 2292 | ||
2251 | // Body = new btRigidBody(mass, tempMotionState1, prim_geom); | 2293 | // Body = new btRigidBody(mass, tempMotionState1, prim_geom); |
2252 | //else | 2294 | //else |
2253 | Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); | 2295 | // Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); |
2296 | if (Body == null) | ||
2297 | { | ||
2298 | Body = new btRigidBody(mass, tempMotionState1, prim_geom, tempInertia1); | ||
2299 | // each body has the localID stored into it so we can identify collision objects | ||
2300 | Body.setUserPointer(new IntPtr((int)m_localID)); | ||
2301 | } | ||
2254 | 2302 | ||
2255 | if (prim_geom is btGImpactMeshShape) | 2303 | if (prim_geom is btGImpactMeshShape) |
2256 | { | 2304 | { |
diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs index 9e048ab..85e34c1 100644 --- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs +++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs | |||
@@ -47,7 +47,9 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
47 | // private string m_sceneIdentifier = string.Empty; | 47 | // private string m_sceneIdentifier = string.Empty; |
48 | 48 | ||
49 | private List<BulletDotNETCharacter> m_characters = new List<BulletDotNETCharacter>(); | 49 | private List<BulletDotNETCharacter> m_characters = new List<BulletDotNETCharacter>(); |
50 | private Dictionary<uint, BulletDotNETCharacter> m_charactersLocalID = new Dictionary<uint, BulletDotNETCharacter>(); | ||
50 | private List<BulletDotNETPrim> m_prims = new List<BulletDotNETPrim>(); | 51 | private List<BulletDotNETPrim> m_prims = new List<BulletDotNETPrim>(); |
52 | private Dictionary<uint, BulletDotNETPrim> m_primsLocalID = new Dictionary<uint, BulletDotNETPrim>(); | ||
51 | private List<BulletDotNETPrim> m_activePrims = new List<BulletDotNETPrim>(); | 53 | private List<BulletDotNETPrim> m_activePrims = new List<BulletDotNETPrim>(); |
52 | private List<PhysicsActor> m_taintedActors = new List<PhysicsActor>(); | 54 | private List<PhysicsActor> m_taintedActors = new List<PhysicsActor>(); |
53 | private btDiscreteDynamicsWorld m_world; | 55 | private btDiscreteDynamicsWorld m_world; |
@@ -134,7 +136,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
134 | m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); | 136 | m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); |
135 | m_world = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration); | 137 | m_world = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration); |
136 | m_world.setGravity(m_gravity); | 138 | m_world.setGravity(m_gravity); |
137 | //EnableCollisionInterface(); | 139 | EnableCollisionInterface(); |
138 | 140 | ||
139 | 141 | ||
140 | } | 142 | } |
@@ -145,7 +147,16 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
145 | avCapRadius, avStandupTensor, avDensity, | 147 | avCapRadius, avStandupTensor, avDensity, |
146 | avHeightFudgeFactor, avMovementDivisorWalk, | 148 | avHeightFudgeFactor, avMovementDivisorWalk, |
147 | avMovementDivisorRun); | 149 | avMovementDivisorRun); |
148 | m_characters.Add(chr); | 150 | try |
151 | { | ||
152 | m_characters.Add(chr); | ||
153 | m_charactersLocalID.Add(chr.m_localID, chr); | ||
154 | } | ||
155 | catch | ||
156 | { | ||
157 | // noop if it's already there | ||
158 | m_log.Debug("[PHYSICS] BulletDotNet: adding duplicate avatar localID"); | ||
159 | } | ||
149 | AddPhysicsActorTaint(chr); | 160 | AddPhysicsActorTaint(chr); |
150 | return chr; | 161 | return chr; |
151 | } | 162 | } |
@@ -154,6 +165,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
154 | { | 165 | { |
155 | BulletDotNETCharacter chr = (BulletDotNETCharacter) actor; | 166 | BulletDotNETCharacter chr = (BulletDotNETCharacter) actor; |
156 | 167 | ||
168 | m_charactersLocalID.Remove(chr.m_localID); | ||
157 | m_characters.Remove(chr); | 169 | m_characters.Remove(chr); |
158 | m_world.removeRigidBody(chr.Body); | 170 | m_world.removeRigidBody(chr.Body); |
159 | m_world.removeCollisionObject(chr.Body); | 171 | m_world.removeCollisionObject(chr.Body); |
@@ -279,7 +291,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
279 | prim.Move(timeStep); | 291 | prim.Move(timeStep); |
280 | } | 292 | } |
281 | } | 293 | } |
282 | float steps = m_world.stepSimulation(timeStep * 1000, 10, WorldTimeComp); | 294 | float steps = m_world.stepSimulation(timeStep, 10, WorldTimeComp); |
283 | 295 | ||
284 | foreach (BulletDotNETCharacter chr in m_characters) | 296 | foreach (BulletDotNETCharacter chr in m_characters) |
285 | { | 297 | { |
@@ -296,20 +308,67 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
296 | } | 308 | } |
297 | if (m_CollisionInterface != null) | 309 | if (m_CollisionInterface != null) |
298 | { | 310 | { |
299 | List<int> collisions = m_CollisionInterface.GetContactList(); | 311 | List<BulletDotNETPrim> primsWithCollisions = new List<BulletDotNETPrim>(); |
300 | lock (collisions) | 312 | List<BulletDotNETCharacter> charactersWithCollisions = new List<BulletDotNETCharacter>(); |
313 | |||
314 | // get the collisions that happened this tick | ||
315 | List<BulletDotNET.ContactAddedCallbackHandler.ContactInfo> collisions = m_CollisionInterface.GetContactList(); | ||
316 | // passed back the localID of the prim so we can associate the prim | ||
317 | foreach (BulletDotNET.ContactAddedCallbackHandler.ContactInfo ci in collisions) | ||
301 | { | 318 | { |
302 | foreach (int pvalue in collisions) | 319 | // ContactPoint = { contactPoint, contactNormal, penetrationDepth } |
303 | { | 320 | ContactPoint contact = new ContactPoint(new Vector3(ci.pX, ci.pY, ci.pZ), |
304 | System.Console.Write(string.Format("{0} ", pvalue)); | 321 | new Vector3(ci.nX, ci.nY, ci.nZ), ci.depth); |
305 | } | 322 | |
323 | ProcessContact(ci.contact, ci.contactWith, contact, ref primsWithCollisions, ref charactersWithCollisions); | ||
324 | ProcessContact(ci.contactWith, ci.contact, contact, ref primsWithCollisions, ref charactersWithCollisions); | ||
325 | |||
306 | } | 326 | } |
307 | m_CollisionInterface.Clear(); | 327 | m_CollisionInterface.Clear(); |
308 | 328 | // for those prims and characters that had collisions cause collision events | |
329 | foreach (BulletDotNETPrim bdnp in primsWithCollisions) | ||
330 | { | ||
331 | bdnp.SendCollisions(); | ||
332 | } | ||
333 | foreach (BulletDotNETCharacter bdnc in charactersWithCollisions) | ||
334 | { | ||
335 | bdnc.SendCollisions(); | ||
336 | } | ||
309 | } | 337 | } |
310 | return steps; | 338 | return steps; |
311 | } | 339 | } |
312 | 340 | ||
341 | private void ProcessContact(uint cont, uint contWith, ContactPoint contact, | ||
342 | ref List<BulletDotNETPrim> primsWithCollisions, | ||
343 | ref List<BulletDotNETCharacter> charactersWithCollisions) | ||
344 | { | ||
345 | BulletDotNETPrim bdnp; | ||
346 | // collisions with a normal prim? | ||
347 | if (m_primsLocalID.TryGetValue(cont, out bdnp)) | ||
348 | { | ||
349 | // Added collision event to the prim. This creates a pile of events | ||
350 | // that will be sent to any subscribed listeners. | ||
351 | bdnp.AddCollision(contWith, contact); | ||
352 | if (!primsWithCollisions.Contains(bdnp)) | ||
353 | { | ||
354 | primsWithCollisions.Add(bdnp); | ||
355 | } | ||
356 | } | ||
357 | else | ||
358 | { | ||
359 | BulletDotNETCharacter bdnc; | ||
360 | // if not a prim, maybe it's one of the characters | ||
361 | if (m_charactersLocalID.TryGetValue(cont, out bdnc)) | ||
362 | { | ||
363 | bdnc.AddCollision(contWith, contact); | ||
364 | if (!charactersWithCollisions.Contains(bdnc)) | ||
365 | { | ||
366 | charactersWithCollisions.Add(bdnc); | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | } | ||
371 | |||
313 | public override void GetResults() | 372 | public override void GetResults() |
314 | { | 373 | { |
315 | 374 | ||
@@ -387,6 +446,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
387 | m_terrainTransform = new btTransform(QuatIdentity, m_terrainPosition); | 446 | m_terrainTransform = new btTransform(QuatIdentity, m_terrainPosition); |
388 | m_terrainMotionState = new btDefaultMotionState(m_terrainTransform); | 447 | m_terrainMotionState = new btDefaultMotionState(m_terrainTransform); |
389 | TerrainBody = new btRigidBody(0, m_terrainMotionState, m_terrainShape); | 448 | TerrainBody = new btRigidBody(0, m_terrainMotionState, m_terrainShape); |
449 | TerrainBody.setUserPointer((IntPtr)0); | ||
390 | m_world.addRigidBody(TerrainBody); | 450 | m_world.addRigidBody(TerrainBody); |
391 | 451 | ||
392 | 452 | ||
@@ -459,6 +519,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
459 | { | 519 | { |
460 | lock (m_prims) | 520 | lock (m_prims) |
461 | { | 521 | { |
522 | m_primsLocalID.Clear(); | ||
462 | foreach (BulletDotNETPrim prim in m_prims) | 523 | foreach (BulletDotNETPrim prim in m_prims) |
463 | { | 524 | { |
464 | if (prim.Body != null) | 525 | if (prim.Body != null) |
@@ -513,6 +574,7 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
513 | m_world.removeRigidBody(body); | 574 | m_world.removeRigidBody(body); |
514 | } | 575 | } |
515 | remActivePrim(prm); | 576 | remActivePrim(prm); |
577 | m_primsLocalID.Remove(prm.m_localID); | ||
516 | m_prims.Remove(prm); | 578 | m_prims.Remove(prm); |
517 | } | 579 | } |
518 | 580 | ||
@@ -686,9 +748,18 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
686 | { | 748 | { |
687 | if (!m_prims.Contains(pPrim)) | 749 | if (!m_prims.Contains(pPrim)) |
688 | { | 750 | { |
689 | m_prims.Add(pPrim); | 751 | try |
752 | { | ||
753 | m_prims.Add(pPrim); | ||
754 | m_primsLocalID.Add(pPrim.m_localID, pPrim); | ||
755 | } | ||
756 | catch | ||
757 | { | ||
758 | // noop if it's already there | ||
759 | m_log.Debug("[PHYSICS] BulletDotNet: adding duplicate prim localID"); | ||
760 | } | ||
690 | m_world.addRigidBody(pPrim.Body); | 761 | m_world.addRigidBody(pPrim.Body); |
691 | m_log.Debug("ADDED"); | 762 | // m_log.Debug("[PHYSICS] added prim to scene"); |
692 | } | 763 | } |
693 | } | 764 | } |
694 | } | 765 | } |
@@ -696,8 +767,8 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin | |||
696 | { | 767 | { |
697 | if (m_CollisionInterface == null) | 768 | if (m_CollisionInterface == null) |
698 | { | 769 | { |
699 | m_CollisionInterface = new ContactAddedCallbackHandler(); | 770 | m_CollisionInterface = new ContactAddedCallbackHandler(m_world); |
700 | m_world.SetCollisionAddedCallback(m_CollisionInterface); | 771 | // m_world.SetCollisionAddedCallback(m_CollisionInterface); |
701 | } | 772 | } |
702 | } | 773 | } |
703 | 774 | ||
diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs index 2a213c3..6e9654b 100644 --- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs +++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs | |||
@@ -1,2202 +1,2201 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors | 2 | * Copyright (c) Contributors |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSimulator Project nor the | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Text; | 30 | using System.Text; |
31 | using System.IO; | 31 | using System.IO; |
32 | 32 | ||
33 | namespace PrimMesher | 33 | namespace PrimMesher |
34 | { | 34 | { |
35 | public struct Quat | 35 | public struct Quat |
36 | { | 36 | { |
37 | /// <summary>X value</summary> | 37 | /// <summary>X value</summary> |
38 | public float X; | 38 | public float X; |
39 | /// <summary>Y value</summary> | 39 | /// <summary>Y value</summary> |
40 | public float Y; | 40 | public float Y; |
41 | /// <summary>Z value</summary> | 41 | /// <summary>Z value</summary> |
42 | public float Z; | 42 | public float Z; |
43 | /// <summary>W value</summary> | 43 | /// <summary>W value</summary> |
44 | public float W; | 44 | public float W; |
45 | 45 | ||
46 | public Quat(float x, float y, float z, float w) | 46 | public Quat(float x, float y, float z, float w) |
47 | { | 47 | { |
48 | X = x; | 48 | X = x; |
49 | Y = y; | 49 | Y = y; |
50 | Z = z; | 50 | Z = z; |
51 | W = w; | 51 | W = w; |
52 | } | 52 | } |
53 | 53 | ||
54 | public Quat(Coord axis, float angle) | 54 | public Quat(Coord axis, float angle) |
55 | { | 55 | { |
56 | axis = axis.Normalize(); | 56 | axis = axis.Normalize(); |
57 | 57 | ||
58 | angle *= 0.5f; | 58 | angle *= 0.5f; |
59 | float c = (float)Math.Cos(angle); | 59 | float c = (float)Math.Cos(angle); |
60 | float s = (float)Math.Sin(angle); | 60 | float s = (float)Math.Sin(angle); |
61 | 61 | ||
62 | X = axis.X * s; | 62 | X = axis.X * s; |
63 | Y = axis.Y * s; | 63 | Y = axis.Y * s; |
64 | Z = axis.Z * s; | 64 | Z = axis.Z * s; |
65 | W = c; | 65 | W = c; |
66 | 66 | ||
67 | Normalize(); | 67 | Normalize(); |
68 | } | 68 | } |
69 | 69 | ||
70 | public float Length() | 70 | public float Length() |
71 | { | 71 | { |
72 | return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); | 72 | return (float)Math.Sqrt(X * X + Y * Y + Z * Z + W * W); |
73 | } | 73 | } |
74 | 74 | ||
75 | public Quat Normalize() | 75 | public Quat Normalize() |
76 | { | 76 | { |
77 | const float MAG_THRESHOLD = 0.0000001f; | 77 | const float MAG_THRESHOLD = 0.0000001f; |
78 | float mag = Length(); | 78 | float mag = Length(); |
79 | 79 | ||
80 | // Catch very small rounding errors when normalizing | 80 | // Catch very small rounding errors when normalizing |
81 | if (mag > MAG_THRESHOLD) | 81 | if (mag > MAG_THRESHOLD) |
82 | { | 82 | { |
83 | float oomag = 1f / mag; | 83 | float oomag = 1f / mag; |
84 | X *= oomag; | 84 | X *= oomag; |
85 | Y *= oomag; | 85 | Y *= oomag; |
86 | Z *= oomag; | 86 | Z *= oomag; |
87 | W *= oomag; | 87 | W *= oomag; |
88 | } | 88 | } |
89 | else | 89 | else |
90 | { | 90 | { |
91 | X = 0f; | 91 | X = 0f; |
92 | Y = 0f; | 92 | Y = 0f; |
93 | Z = 0f; | 93 | Z = 0f; |
94 | W = 1f; | 94 | W = 1f; |
95 | } | 95 | } |
96 | 96 | ||
97 | return this; | 97 | return this; |
98 | } | 98 | } |
99 | 99 | ||
100 | public static Quat operator *(Quat q1, Quat q2) | 100 | public static Quat operator *(Quat q1, Quat q2) |
101 | { | 101 | { |
102 | float x = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y; | 102 | float x = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y; |
103 | float y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X; | 103 | float y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X; |
104 | float z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W; | 104 | float z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W; |
105 | float w = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z; | 105 | float w = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z; |
106 | return new Quat(x, y, z, w); | 106 | return new Quat(x, y, z, w); |
107 | } | 107 | } |
108 | 108 | ||
109 | public override string ToString() | 109 | public override string ToString() |
110 | { | 110 | { |
111 | return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">"; | 111 | return "< X: " + this.X.ToString() + ", Y: " + this.Y.ToString() + ", Z: " + this.Z.ToString() + ", W: " + this.W.ToString() + ">"; |
112 | } | 112 | } |
113 | } | 113 | } |
114 | 114 | ||
115 | public struct Coord | 115 | public struct Coord |
116 | { | 116 | { |
117 | public float X; | 117 | public float X; |
118 | public float Y; | 118 | public float Y; |
119 | public float Z; | 119 | public float Z; |
120 | 120 | ||
121 | public Coord(float x, float y, float z) | 121 | public Coord(float x, float y, float z) |
122 | { | 122 | { |
123 | this.X = x; | 123 | this.X = x; |
124 | this.Y = y; | 124 | this.Y = y; |
125 | this.Z = z; | 125 | this.Z = z; |
126 | } | 126 | } |
127 | 127 | ||
128 | public float Length() | 128 | public float Length() |
129 | { | 129 | { |
130 | return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z); | 130 | return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z); |
131 | } | 131 | } |
132 | 132 | ||
133 | public Coord Invert() | 133 | public Coord Invert() |
134 | { | 134 | { |
135 | this.X = -this.X; | 135 | this.X = -this.X; |
136 | this.Y = -this.Y; | 136 | this.Y = -this.Y; |
137 | this.Z = -this.Z; | 137 | this.Z = -this.Z; |
138 | 138 | ||
139 | return this; | 139 | return this; |
140 | } | 140 | } |
141 | 141 | ||
142 | public Coord Normalize() | 142 | public Coord Normalize() |
143 | { | 143 | { |
144 | const float MAG_THRESHOLD = 0.0000001f; | 144 | const float MAG_THRESHOLD = 0.0000001f; |
145 | float mag = Length(); | 145 | float mag = Length(); |
146 | 146 | ||
147 | // Catch very small rounding errors when normalizing | 147 | // Catch very small rounding errors when normalizing |
148 | if (mag > MAG_THRESHOLD) | 148 | if (mag > MAG_THRESHOLD) |
149 | { | 149 | { |
150 | float oomag = 1.0f / mag; | 150 | float oomag = 1.0f / mag; |
151 | this.X *= oomag; | 151 | this.X *= oomag; |
152 | this.Y *= oomag; | 152 | this.Y *= oomag; |
153 | this.Z *= oomag; | 153 | this.Z *= oomag; |
154 | } | 154 | } |
155 | else | 155 | else |
156 | { | 156 | { |
157 | this.X = 0.0f; | 157 | this.X = 0.0f; |
158 | this.Y = 0.0f; | 158 | this.Y = 0.0f; |
159 | this.Z = 0.0f; | 159 | this.Z = 0.0f; |
160 | } | 160 | } |
161 | 161 | ||
162 | return this; | 162 | return this; |
163 | } | 163 | } |
164 | 164 | ||
165 | public override string ToString() | 165 | public override string ToString() |
166 | { | 166 | { |
167 | return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString(); | 167 | return this.X.ToString() + " " + this.Y.ToString() + " " + this.Z.ToString(); |
168 | } | 168 | } |
169 | 169 | ||
170 | public static Coord Cross(Coord c1, Coord c2) | 170 | public static Coord Cross(Coord c1, Coord c2) |
171 | { | 171 | { |
172 | return new Coord( | 172 | return new Coord( |
173 | c1.Y * c2.Z - c2.Y * c1.Z, | 173 | c1.Y * c2.Z - c2.Y * c1.Z, |
174 | c1.Z * c2.X - c2.Z * c1.X, | 174 | c1.Z * c2.X - c2.Z * c1.X, |
175 | c1.X * c2.Y - c2.X * c1.Y | 175 | c1.X * c2.Y - c2.X * c1.Y |
176 | ); | 176 | ); |
177 | } | 177 | } |
178 | 178 | ||
179 | public static Coord operator +(Coord v, Coord a) | 179 | public static Coord operator +(Coord v, Coord a) |
180 | { | 180 | { |
181 | return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z); | 181 | return new Coord(v.X + a.X, v.Y + a.Y, v.Z + a.Z); |
182 | } | 182 | } |
183 | 183 | ||
184 | public static Coord operator *(Coord v, Coord m) | 184 | public static Coord operator *(Coord v, Coord m) |
185 | { | 185 | { |
186 | return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z); | 186 | return new Coord(v.X * m.X, v.Y * m.Y, v.Z * m.Z); |
187 | } | 187 | } |
188 | 188 | ||
189 | public static Coord operator *(Coord v, Quat q) | 189 | public static Coord operator *(Coord v, Quat q) |
190 | { | 190 | { |
191 | // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/ | 191 | // From http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/ |
192 | 192 | ||
193 | Coord c2 = new Coord(0.0f, 0.0f, 0.0f); | 193 | Coord c2 = new Coord(0.0f, 0.0f, 0.0f); |
194 | 194 | ||
195 | c2.X = q.W * q.W * v.X + | 195 | c2.X = q.W * q.W * v.X + |
196 | 2f * q.Y * q.W * v.Z - | 196 | 2f * q.Y * q.W * v.Z - |
197 | 2f * q.Z * q.W * v.Y + | 197 | 2f * q.Z * q.W * v.Y + |
198 | q.X * q.X * v.X + | 198 | q.X * q.X * v.X + |
199 | 2f * q.Y * q.X * v.Y + | 199 | 2f * q.Y * q.X * v.Y + |
200 | 2f * q.Z * q.X * v.Z - | 200 | 2f * q.Z * q.X * v.Z - |
201 | q.Z * q.Z * v.X - | 201 | q.Z * q.Z * v.X - |
202 | q.Y * q.Y * v.X; | 202 | q.Y * q.Y * v.X; |
203 | 203 | ||
204 | c2.Y = | 204 | c2.Y = |
205 | 2f * q.X * q.Y * v.X + | 205 | 2f * q.X * q.Y * v.X + |
206 | q.Y * q.Y * v.Y + | 206 | q.Y * q.Y * v.Y + |
207 | 2f * q.Z * q.Y * v.Z + | 207 | 2f * q.Z * q.Y * v.Z + |
208 | 2f * q.W * q.Z * v.X - | 208 | 2f * q.W * q.Z * v.X - |
209 | q.Z * q.Z * v.Y + | 209 | q.Z * q.Z * v.Y + |
210 | q.W * q.W * v.Y - | 210 | q.W * q.W * v.Y - |
211 | 2f * q.X * q.W * v.Z - | 211 | 2f * q.X * q.W * v.Z - |
212 | q.X * q.X * v.Y; | 212 | q.X * q.X * v.Y; |
213 | 213 | ||
214 | c2.Z = | 214 | c2.Z = |
215 | 2f * q.X * q.Z * v.X + | 215 | 2f * q.X * q.Z * v.X + |
216 | 2f * q.Y * q.Z * v.Y + | 216 | 2f * q.Y * q.Z * v.Y + |
217 | q.Z * q.Z * v.Z - | 217 | q.Z * q.Z * v.Z - |
218 | 2f * q.W * q.Y * v.X - | 218 | 2f * q.W * q.Y * v.X - |
219 | q.Y * q.Y * v.Z + | 219 | q.Y * q.Y * v.Z + |
220 | 2f * q.W * q.X * v.Y - | 220 | 2f * q.W * q.X * v.Y - |
221 | q.X * q.X * v.Z + | 221 | q.X * q.X * v.Z + |
222 | q.W * q.W * v.Z; | 222 | q.W * q.W * v.Z; |
223 | 223 | ||
224 | return c2; | 224 | return c2; |
225 | } | 225 | } |
226 | } | 226 | } |
227 | 227 | ||
228 | public struct UVCoord | 228 | public struct UVCoord |
229 | { | 229 | { |
230 | public float U; | 230 | public float U; |
231 | public float V; | 231 | public float V; |
232 | 232 | ||
233 | 233 | ||
234 | public UVCoord(float u, float v) | 234 | public UVCoord(float u, float v) |
235 | { | 235 | { |
236 | this.U = u; | 236 | this.U = u; |
237 | this.V = v; | 237 | this.V = v; |
238 | } | 238 | } |
239 | } | 239 | } |
240 | 240 | ||
241 | public struct Face | 241 | public struct Face |
242 | { | 242 | { |
243 | public int primFace; | 243 | public int primFace; |
244 | 244 | ||
245 | // vertices | 245 | // vertices |
246 | public int v1; | 246 | public int v1; |
247 | public int v2; | 247 | public int v2; |
248 | public int v3; | 248 | public int v3; |
249 | 249 | ||
250 | //normals | 250 | //normals |
251 | public int n1; | 251 | public int n1; |
252 | public int n2; | 252 | public int n2; |
253 | public int n3; | 253 | public int n3; |
254 | 254 | ||
255 | // uvs | 255 | // uvs |
256 | public int uv1; | 256 | public int uv1; |
257 | public int uv2; | 257 | public int uv2; |
258 | public int uv3; | 258 | public int uv3; |
259 | 259 | ||
260 | 260 | ||
261 | public Face(int v1, int v2, int v3) | 261 | public Face(int v1, int v2, int v3) |
262 | { | 262 | { |
263 | primFace = 0; | 263 | primFace = 0; |
264 | 264 | ||
265 | this.v1 = v1; | 265 | this.v1 = v1; |
266 | this.v2 = v2; | 266 | this.v2 = v2; |
267 | this.v3 = v3; | 267 | this.v3 = v3; |
268 | 268 | ||
269 | this.n1 = 0; | 269 | this.n1 = 0; |
270 | this.n2 = 0; | 270 | this.n2 = 0; |
271 | this.n3 = 0; | 271 | this.n3 = 0; |
272 | 272 | ||
273 | this.uv1 = 0; | 273 | this.uv1 = 0; |
274 | this.uv2 = 0; | 274 | this.uv2 = 0; |
275 | this.uv3 = 0; | 275 | this.uv3 = 0; |
276 | 276 | ||
277 | } | 277 | } |
278 | 278 | ||
279 | public Face(int v1, int v2, int v3, int n1, int n2, int n3) | 279 | public Face(int v1, int v2, int v3, int n1, int n2, int n3) |
280 | { | 280 | { |
281 | primFace = 0; | 281 | primFace = 0; |
282 | 282 | ||
283 | this.v1 = v1; | 283 | this.v1 = v1; |
284 | this.v2 = v2; | 284 | this.v2 = v2; |
285 | this.v3 = v3; | 285 | this.v3 = v3; |
286 | 286 | ||
287 | this.n1 = n1; | 287 | this.n1 = n1; |
288 | this.n2 = n2; | 288 | this.n2 = n2; |
289 | this.n3 = n3; | 289 | this.n3 = n3; |
290 | 290 | ||
291 | this.uv1 = 0; | 291 | this.uv1 = 0; |
292 | this.uv2 = 0; | 292 | this.uv2 = 0; |
293 | this.uv3 = 0; | 293 | this.uv3 = 0; |
294 | } | 294 | } |
295 | 295 | ||
296 | public Coord SurfaceNormal(List<Coord> coordList) | 296 | public Coord SurfaceNormal(List<Coord> coordList) |
297 | { | 297 | { |
298 | Coord c1 = coordList[this.v1]; | 298 | Coord c1 = coordList[this.v1]; |
299 | Coord c2 = coordList[this.v2]; | 299 | Coord c2 = coordList[this.v2]; |
300 | Coord c3 = coordList[this.v3]; | 300 | Coord c3 = coordList[this.v3]; |
301 | 301 | ||
302 | Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); | 302 | Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); |
303 | Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); | 303 | Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); |
304 | 304 | ||
305 | return Coord.Cross(edge1, edge2).Normalize(); | 305 | return Coord.Cross(edge1, edge2).Normalize(); |
306 | } | 306 | } |
307 | } | 307 | } |
308 | 308 | ||
309 | public struct ViewerFace | 309 | public struct ViewerFace |
310 | { | 310 | { |
311 | public int primFaceNumber; | 311 | public int primFaceNumber; |
312 | 312 | ||
313 | public Coord v1; | 313 | public Coord v1; |
314 | public Coord v2; | 314 | public Coord v2; |
315 | public Coord v3; | 315 | public Coord v3; |
316 | 316 | ||
317 | public int coordIndex1; | 317 | public int coordIndex1; |
318 | public int coordIndex2; | 318 | public int coordIndex2; |
319 | public int coordIndex3; | 319 | public int coordIndex3; |
320 | 320 | ||
321 | public Coord n1; | 321 | public Coord n1; |
322 | public Coord n2; | 322 | public Coord n2; |
323 | public Coord n3; | 323 | public Coord n3; |
324 | 324 | ||
325 | public UVCoord uv1; | 325 | public UVCoord uv1; |
326 | public UVCoord uv2; | 326 | public UVCoord uv2; |
327 | public UVCoord uv3; | 327 | public UVCoord uv3; |
328 | 328 | ||
329 | public ViewerFace(int primFaceNumber) | 329 | public ViewerFace(int primFaceNumber) |
330 | { | 330 | { |
331 | this.primFaceNumber = primFaceNumber; | 331 | this.primFaceNumber = primFaceNumber; |
332 | 332 | ||
333 | this.v1 = new Coord(); | 333 | this.v1 = new Coord(); |
334 | this.v2 = new Coord(); | 334 | this.v2 = new Coord(); |
335 | this.v3 = new Coord(); | 335 | this.v3 = new Coord(); |
336 | 336 | ||
337 | this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet | 337 | this.coordIndex1 = this.coordIndex2 = this.coordIndex3 = -1; // -1 means not assigned yet |
338 | 338 | ||
339 | this.n1 = new Coord(); | 339 | this.n1 = new Coord(); |
340 | this.n2 = new Coord(); | 340 | this.n2 = new Coord(); |
341 | this.n3 = new Coord(); | 341 | this.n3 = new Coord(); |
342 | 342 | ||
343 | this.uv1 = new UVCoord(); | 343 | this.uv1 = new UVCoord(); |
344 | this.uv2 = new UVCoord(); | 344 | this.uv2 = new UVCoord(); |
345 | this.uv3 = new UVCoord(); | 345 | this.uv3 = new UVCoord(); |
346 | } | 346 | } |
347 | 347 | ||
348 | public void Scale(float x, float y, float z) | 348 | public void Scale(float x, float y, float z) |
349 | { | 349 | { |
350 | this.v1.X *= x; | 350 | this.v1.X *= x; |
351 | this.v1.Y *= y; | 351 | this.v1.Y *= y; |
352 | this.v1.Z *= z; | 352 | this.v1.Z *= z; |
353 | 353 | ||
354 | this.v2.X *= x; | 354 | this.v2.X *= x; |
355 | this.v2.Y *= y; | 355 | this.v2.Y *= y; |
356 | this.v2.Z *= z; | 356 | this.v2.Z *= z; |
357 | 357 | ||
358 | this.v3.X *= x; | 358 | this.v3.X *= x; |
359 | this.v3.Y *= y; | 359 | this.v3.Y *= y; |
360 | this.v3.Z *= z; | 360 | this.v3.Z *= z; |
361 | } | 361 | } |
362 | 362 | ||
363 | public void AddPos(float x, float y, float z) | 363 | public void AddPos(float x, float y, float z) |
364 | { | 364 | { |
365 | this.v1.X += x; | 365 | this.v1.X += x; |
366 | this.v2.X += x; | 366 | this.v2.X += x; |
367 | this.v3.X += x; | 367 | this.v3.X += x; |
368 | 368 | ||
369 | this.v1.Y += y; | 369 | this.v1.Y += y; |
370 | this.v2.Y += y; | 370 | this.v2.Y += y; |
371 | this.v3.Y += y; | 371 | this.v3.Y += y; |
372 | 372 | ||
373 | this.v1.Z += z; | 373 | this.v1.Z += z; |
374 | this.v2.Z += z; | 374 | this.v2.Z += z; |
375 | this.v3.Z += z; | 375 | this.v3.Z += z; |
376 | } | 376 | } |
377 | 377 | ||
378 | public void AddRot(Quat q) | 378 | public void AddRot(Quat q) |
379 | { | 379 | { |
380 | this.v1 *= q; | 380 | this.v1 *= q; |
381 | this.v2 *= q; | 381 | this.v2 *= q; |
382 | this.v3 *= q; | 382 | this.v3 *= q; |
383 | 383 | ||
384 | this.n1 *= q; | 384 | this.n1 *= q; |
385 | this.n2 *= q; | 385 | this.n2 *= q; |
386 | this.n3 *= q; | 386 | this.n3 *= q; |
387 | } | 387 | } |
388 | 388 | ||
389 | public void CalcSurfaceNormal() | 389 | public void CalcSurfaceNormal() |
390 | { | 390 | { |
391 | 391 | ||
392 | Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z); | 392 | Coord edge1 = new Coord(this.v2.X - this.v1.X, this.v2.Y - this.v1.Y, this.v2.Z - this.v1.Z); |
393 | Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z); | 393 | Coord edge2 = new Coord(this.v3.X - this.v1.X, this.v3.Y - this.v1.Y, this.v3.Z - this.v1.Z); |
394 | 394 | ||
395 | this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize(); | 395 | this.n1 = this.n2 = this.n3 = Coord.Cross(edge1, edge2).Normalize(); |
396 | } | 396 | } |
397 | } | 397 | } |
398 | 398 | ||
399 | internal struct Angle | 399 | internal struct Angle |
400 | { | 400 | { |
401 | internal float angle; | 401 | internal float angle; |
402 | internal float X; | 402 | internal float X; |
403 | internal float Y; | 403 | internal float Y; |
404 | 404 | ||
405 | internal Angle(float angle, float x, float y) | 405 | internal Angle(float angle, float x, float y) |
406 | { | 406 | { |
407 | this.angle = angle; | 407 | this.angle = angle; |
408 | this.X = x; | 408 | this.X = x; |
409 | this.Y = y; | 409 | this.Y = y; |
410 | } | 410 | } |
411 | } | 411 | } |
412 | 412 | ||
413 | internal class AngleList | 413 | internal class AngleList |
414 | { | 414 | { |
415 | private float iX, iY; // intersection point | 415 | private float iX, iY; // intersection point |
416 | 416 | ||
417 | private static Angle[] angles3 = | 417 | private static Angle[] angles3 = |
418 | { | 418 | { |
419 | new Angle(0.0f, 1.0f, 0.0f), | 419 | new Angle(0.0f, 1.0f, 0.0f), |
420 | new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), | 420 | new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), |
421 | new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), | 421 | new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), |
422 | new Angle(1.0f, 1.0f, 0.0f) | 422 | new Angle(1.0f, 1.0f, 0.0f) |
423 | }; | 423 | }; |
424 | 424 | ||
425 | private static Coord[] normals3 = | 425 | private static Coord[] normals3 = |
426 | { | 426 | { |
427 | new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(), | 427 | new Coord(0.25f, 0.4330127019f, 0.0f).Normalize(), |
428 | new Coord(-0.5f, 0.0f, 0.0f).Normalize(), | 428 | new Coord(-0.5f, 0.0f, 0.0f).Normalize(), |
429 | new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(), | 429 | new Coord(0.25f, -0.4330127019f, 0.0f).Normalize(), |
430 | new Coord(0.25f, 0.4330127019f, 0.0f).Normalize() | 430 | new Coord(0.25f, 0.4330127019f, 0.0f).Normalize() |
431 | }; | 431 | }; |
432 | 432 | ||
433 | private static Angle[] angles4 = | 433 | private static Angle[] angles4 = |
434 | { | 434 | { |
435 | new Angle(0.0f, 1.0f, 0.0f), | 435 | new Angle(0.0f, 1.0f, 0.0f), |
436 | new Angle(0.25f, 0.0f, 1.0f), | 436 | new Angle(0.25f, 0.0f, 1.0f), |
437 | new Angle(0.5f, -1.0f, 0.0f), | 437 | new Angle(0.5f, -1.0f, 0.0f), |
438 | new Angle(0.75f, 0.0f, -1.0f), | 438 | new Angle(0.75f, 0.0f, -1.0f), |
439 | new Angle(1.0f, 1.0f, 0.0f) | 439 | new Angle(1.0f, 1.0f, 0.0f) |
440 | }; | 440 | }; |
441 | 441 | ||
442 | private static Coord[] normals4 = | 442 | private static Coord[] normals4 = |
443 | { | 443 | { |
444 | new Coord(0.5f, 0.5f, 0.0f).Normalize(), | 444 | new Coord(0.5f, 0.5f, 0.0f).Normalize(), |
445 | new Coord(-0.5f, 0.5f, 0.0f).Normalize(), | 445 | new Coord(-0.5f, 0.5f, 0.0f).Normalize(), |
446 | new Coord(-0.5f, -0.5f, 0.0f).Normalize(), | 446 | new Coord(-0.5f, -0.5f, 0.0f).Normalize(), |
447 | new Coord(0.5f, -0.5f, 0.0f).Normalize(), | 447 | new Coord(0.5f, -0.5f, 0.0f).Normalize(), |
448 | new Coord(0.5f, 0.5f, 0.0f).Normalize() | 448 | new Coord(0.5f, 0.5f, 0.0f).Normalize() |
449 | }; | 449 | }; |
450 | 450 | ||
451 | private static Angle[] angles24 = | 451 | private static Angle[] angles24 = |
452 | { | 452 | { |
453 | new Angle(0.0f, 1.0f, 0.0f), | 453 | new Angle(0.0f, 1.0f, 0.0f), |
454 | new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f), | 454 | new Angle(0.041666666666666664f, 0.96592582628906831f, 0.25881904510252074f), |
455 | new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f), | 455 | new Angle(0.083333333333333329f, 0.86602540378443871f, 0.5f), |
456 | new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f), | 456 | new Angle(0.125f, 0.70710678118654757f, 0.70710678118654746f), |
457 | new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f), | 457 | new Angle(0.16666666666666667f, 0.5f, 0.8660254037844386f), |
458 | new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f), | 458 | new Angle(0.20833333333333331f, 0.25881904510252096f, 0.9659258262890682f), |
459 | new Angle(0.25f, 0.0f, 1.0f), | 459 | new Angle(0.25f, 0.0f, 1.0f), |
460 | new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f), | 460 | new Angle(0.29166666666666663f, -0.25881904510252063f, 0.96592582628906831f), |
461 | new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), | 461 | new Angle(0.33333333333333333f, -0.5f, 0.86602540378443871f), |
462 | new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f), | 462 | new Angle(0.375f, -0.70710678118654746f, 0.70710678118654757f), |
463 | new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f), | 463 | new Angle(0.41666666666666663f, -0.86602540378443849f, 0.5f), |
464 | new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f), | 464 | new Angle(0.45833333333333331f, -0.9659258262890682f, 0.25881904510252102f), |
465 | new Angle(0.5f, -1.0f, 0.0f), | 465 | new Angle(0.5f, -1.0f, 0.0f), |
466 | new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f), | 466 | new Angle(0.54166666666666663f, -0.96592582628906842f, -0.25881904510252035f), |
467 | new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f), | 467 | new Angle(0.58333333333333326f, -0.86602540378443882f, -0.5f), |
468 | new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f), | 468 | new Angle(0.62499999999999989f, -0.70710678118654791f, -0.70710678118654713f), |
469 | new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), | 469 | new Angle(0.66666666666666667f, -0.5f, -0.86602540378443837f), |
470 | new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f), | 470 | new Angle(0.70833333333333326f, -0.25881904510252152f, -0.96592582628906809f), |
471 | new Angle(0.75f, 0.0f, -1.0f), | 471 | new Angle(0.75f, 0.0f, -1.0f), |
472 | new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f), | 472 | new Angle(0.79166666666666663f, 0.2588190451025203f, -0.96592582628906842f), |
473 | new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f), | 473 | new Angle(0.83333333333333326f, 0.5f, -0.86602540378443904f), |
474 | new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f), | 474 | new Angle(0.875f, 0.70710678118654735f, -0.70710678118654768f), |
475 | new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f), | 475 | new Angle(0.91666666666666663f, 0.86602540378443837f, -0.5f), |
476 | new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f), | 476 | new Angle(0.95833333333333326f, 0.96592582628906809f, -0.25881904510252157f), |
477 | new Angle(1.0f, 1.0f, 0.0f) | 477 | new Angle(1.0f, 1.0f, 0.0f) |
478 | }; | 478 | }; |
479 | 479 | ||
480 | private Angle interpolatePoints(float newPoint, Angle p1, Angle p2) | 480 | private Angle interpolatePoints(float newPoint, Angle p1, Angle p2) |
481 | { | 481 | { |
482 | float m = (newPoint - p1.angle) / (p2.angle - p1.angle); | 482 | float m = (newPoint - p1.angle) / (p2.angle - p1.angle); |
483 | return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y)); | 483 | return new Angle(newPoint, p1.X + m * (p2.X - p1.X), p1.Y + m * (p2.Y - p1.Y)); |
484 | } | 484 | } |
485 | 485 | ||
486 | private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) | 486 | private void intersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) |
487 | { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ | 487 | { // ref: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ |
488 | double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); | 488 | double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); |
489 | double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); | 489 | double uaNumerator = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); |
490 | 490 | ||
491 | if (denom != 0.0) | 491 | if (denom != 0.0) |
492 | { | 492 | { |
493 | double ua = uaNumerator / denom; | 493 | double ua = uaNumerator / denom; |
494 | iX = (float)(x1 + ua * (x2 - x1)); | 494 | iX = (float)(x1 + ua * (x2 - x1)); |
495 | iY = (float)(y1 + ua * (y2 - y1)); | 495 | iY = (float)(y1 + ua * (y2 - y1)); |
496 | } | 496 | } |
497 | } | 497 | } |
498 | 498 | ||
499 | internal List<Angle> angles; | 499 | internal List<Angle> angles; |
500 | internal List<Coord> normals; | 500 | internal List<Coord> normals; |
501 | 501 | ||
502 | internal void makeAngles(int sides, float startAngle, float stopAngle) | 502 | internal void makeAngles(int sides, float startAngle, float stopAngle) |
503 | { | 503 | { |
504 | angles = new List<Angle>(); | 504 | angles = new List<Angle>(); |
505 | normals = new List<Coord>(); | 505 | normals = new List<Coord>(); |
506 | 506 | ||
507 | double twoPi = System.Math.PI * 2.0; | 507 | double twoPi = System.Math.PI * 2.0; |
508 | float twoPiInv = 1.0f / (float)twoPi; | 508 | float twoPiInv = 1.0f / (float)twoPi; |
509 | 509 | ||
510 | if (sides < 1) | 510 | if (sides < 1) |
511 | throw new Exception("number of sides not greater than zero"); | 511 | throw new Exception("number of sides not greater than zero"); |
512 | if (stopAngle <= startAngle) | 512 | if (stopAngle <= startAngle) |
513 | throw new Exception("stopAngle not greater than startAngle"); | 513 | throw new Exception("stopAngle not greater than startAngle"); |
514 | 514 | ||
515 | if ((sides == 3 || sides == 4 || sides == 24)) | 515 | if ((sides == 3 || sides == 4 || sides == 24)) |
516 | { | 516 | { |
517 | startAngle *= twoPiInv; | 517 | startAngle *= twoPiInv; |
518 | stopAngle *= twoPiInv; | 518 | stopAngle *= twoPiInv; |
519 | 519 | ||
520 | Angle[] sourceAngles; | 520 | Angle[] sourceAngles; |
521 | if (sides == 3) | 521 | if (sides == 3) |
522 | sourceAngles = angles3; | 522 | sourceAngles = angles3; |
523 | else if (sides == 4) | 523 | else if (sides == 4) |
524 | sourceAngles = angles4; | 524 | sourceAngles = angles4; |
525 | else sourceAngles = angles24; | 525 | else sourceAngles = angles24; |
526 | 526 | ||
527 | int startAngleIndex = (int)(startAngle * sides); | 527 | int startAngleIndex = (int)(startAngle * sides); |
528 | int endAngleIndex = sourceAngles.Length - 1; | 528 | int endAngleIndex = sourceAngles.Length - 1; |
529 | if (stopAngle < 1.0f) | 529 | if (stopAngle < 1.0f) |
530 | endAngleIndex = (int)(stopAngle * sides) + 1; | 530 | endAngleIndex = (int)(stopAngle * sides) + 1; |
531 | if (endAngleIndex == startAngleIndex) | 531 | if (endAngleIndex == startAngleIndex) |
532 | endAngleIndex++; | 532 | endAngleIndex++; |
533 | 533 | ||
534 | for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++) | 534 | for (int angleIndex = startAngleIndex; angleIndex < endAngleIndex + 1; angleIndex++) |
535 | { | 535 | { |
536 | angles.Add(sourceAngles[angleIndex]); | 536 | angles.Add(sourceAngles[angleIndex]); |
537 | if (sides == 3) | 537 | if (sides == 3) |
538 | normals.Add(normals3[angleIndex]); | 538 | normals.Add(normals3[angleIndex]); |
539 | else if (sides == 4) | 539 | else if (sides == 4) |
540 | normals.Add(normals4[angleIndex]); | 540 | normals.Add(normals4[angleIndex]); |
541 | } | 541 | } |
542 | 542 | ||
543 | if (startAngle > 0.0f) | 543 | if (startAngle > 0.0f) |
544 | angles[0] = interpolatePoints(startAngle, angles[0], angles[1]); | 544 | angles[0] = interpolatePoints(startAngle, angles[0], angles[1]); |
545 | 545 | ||
546 | if (stopAngle < 1.0f) | 546 | if (stopAngle < 1.0f) |
547 | { | 547 | { |
548 | int lastAngleIndex = angles.Count - 1; | 548 | int lastAngleIndex = angles.Count - 1; |
549 | angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]); | 549 | angles[lastAngleIndex] = interpolatePoints(stopAngle, angles[lastAngleIndex - 1], angles[lastAngleIndex]); |
550 | } | 550 | } |
551 | } | 551 | } |
552 | else | 552 | else |
553 | { | 553 | { |
554 | double stepSize = twoPi / sides; | 554 | double stepSize = twoPi / sides; |
555 | 555 | ||
556 | int startStep = (int)(startAngle / stepSize); | 556 | int startStep = (int)(startAngle / stepSize); |
557 | double angle = stepSize * startStep; | 557 | double angle = stepSize * startStep; |
558 | int step = startStep; | 558 | int step = startStep; |
559 | double stopAngleTest = stopAngle; | 559 | double stopAngleTest = stopAngle; |
560 | if (stopAngle < twoPi) | 560 | if (stopAngle < twoPi) |
561 | { | 561 | { |
562 | stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1); | 562 | stopAngleTest = stepSize * ((int)(stopAngle / stepSize) + 1); |
563 | if (stopAngleTest < stopAngle) | 563 | if (stopAngleTest < stopAngle) |
564 | stopAngleTest += stepSize; | 564 | stopAngleTest += stepSize; |
565 | if (stopAngleTest > twoPi) | 565 | if (stopAngleTest > twoPi) |
566 | stopAngleTest = twoPi; | 566 | stopAngleTest = twoPi; |
567 | } | 567 | } |
568 | 568 | ||
569 | while (angle <= stopAngleTest) | 569 | while (angle <= stopAngleTest) |
570 | { | 570 | { |
571 | Angle newAngle; | 571 | Angle newAngle; |
572 | newAngle.angle = (float)angle; | 572 | newAngle.angle = (float)angle; |
573 | newAngle.X = (float)System.Math.Cos(angle); | 573 | newAngle.X = (float)System.Math.Cos(angle); |
574 | newAngle.Y = (float)System.Math.Sin(angle); | 574 | newAngle.Y = (float)System.Math.Sin(angle); |
575 | angles.Add(newAngle); | 575 | angles.Add(newAngle); |
576 | step += 1; | 576 | step += 1; |
577 | angle = stepSize * step; | 577 | angle = stepSize * step; |
578 | } | 578 | } |
579 | 579 | ||
580 | if (startAngle > angles[0].angle) | 580 | if (startAngle > angles[0].angle) |
581 | { | 581 | { |
582 | Angle newAngle; | 582 | Angle newAngle; |
583 | 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)); | 583 | 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)); |
584 | newAngle.angle = startAngle; | 584 | newAngle.angle = startAngle; |
585 | newAngle.X = iX; | 585 | newAngle.X = iX; |
586 | newAngle.Y = iY; | 586 | newAngle.Y = iY; |
587 | angles[0] = newAngle; | 587 | angles[0] = newAngle; |
588 | } | 588 | } |
589 | 589 | ||
590 | int index = angles.Count - 1; | 590 | int index = angles.Count - 1; |
591 | if (stopAngle < angles[index].angle) | 591 | if (stopAngle < angles[index].angle) |
592 | { | 592 | { |
593 | Angle newAngle; | 593 | Angle newAngle; |
594 | 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)); | 594 | 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)); |
595 | newAngle.angle = stopAngle; | 595 | newAngle.angle = stopAngle; |
596 | newAngle.X = iX; | 596 | newAngle.X = iX; |
597 | newAngle.Y = iY; | 597 | newAngle.Y = iY; |
598 | angles[index] = newAngle; | 598 | angles[index] = newAngle; |
599 | } | 599 | } |
600 | } | 600 | } |
601 | } | 601 | } |
602 | } | 602 | } |
603 | 603 | ||
604 | /// <summary> | 604 | /// <summary> |
605 | /// generates a profile for extrusion | 605 | /// generates a profile for extrusion |
606 | /// </summary> | 606 | /// </summary> |
607 | internal class Profile | 607 | internal class Profile |
608 | { | 608 | { |
609 | private const float twoPi = 2.0f * (float)Math.PI; | 609 | private const float twoPi = 2.0f * (float)Math.PI; |
610 | 610 | ||
611 | internal string errorMessage = null; | 611 | internal string errorMessage = null; |
612 | 612 | ||
613 | internal List<Coord> coords; | 613 | internal List<Coord> coords; |
614 | internal List<Face> faces; | 614 | internal List<Face> faces; |
615 | internal List<Coord> vertexNormals; | 615 | internal List<Coord> vertexNormals; |
616 | internal List<float> us; | 616 | internal List<float> us; |
617 | internal List<UVCoord> faceUVs; | 617 | internal List<UVCoord> faceUVs; |
618 | internal List<int> faceNumbers; | 618 | internal List<int> faceNumbers; |
619 | 619 | ||
620 | // use these for making individual meshes for each prim face | 620 | // use these for making individual meshes for each prim face |
621 | internal List<int> outerCoordIndices = null; | 621 | internal List<int> outerCoordIndices = null; |
622 | internal List<int> hollowCoordIndices = null; | 622 | internal List<int> hollowCoordIndices = null; |
623 | internal List<int> cut1CoordIndices = null; | 623 | internal List<int> cut1CoordIndices = null; |
624 | internal List<int> cut2CoordIndices = null; | 624 | internal List<int> cut2CoordIndices = null; |
625 | 625 | ||
626 | internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); | 626 | internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); |
627 | internal Coord cutNormal1 = new Coord(); | 627 | internal Coord cutNormal1 = new Coord(); |
628 | internal Coord cutNormal2 = new Coord(); | 628 | internal Coord cutNormal2 = new Coord(); |
629 | 629 | ||
630 | internal int numOuterVerts = 0; | 630 | internal int numOuterVerts = 0; |
631 | internal int numHollowVerts = 0; | 631 | internal int numHollowVerts = 0; |
632 | 632 | ||
633 | internal bool calcVertexNormals = false; | 633 | internal bool calcVertexNormals = false; |
634 | internal int bottomFaceNumber = 0; | 634 | internal int bottomFaceNumber = 0; |
635 | internal int numPrimFaces = 0; | 635 | internal int numPrimFaces = 0; |
636 | 636 | ||
637 | internal Profile() | 637 | internal Profile() |
638 | { | 638 | { |
639 | this.coords = new List<Coord>(); | 639 | this.coords = new List<Coord>(); |
640 | this.faces = new List<Face>(); | 640 | this.faces = new List<Face>(); |
641 | this.vertexNormals = new List<Coord>(); | 641 | this.vertexNormals = new List<Coord>(); |
642 | this.us = new List<float>(); | 642 | this.us = new List<float>(); |
643 | this.faceUVs = new List<UVCoord>(); | 643 | this.faceUVs = new List<UVCoord>(); |
644 | this.faceNumbers = new List<int>(); | 644 | this.faceNumbers = new List<int>(); |
645 | } | 645 | } |
646 | 646 | ||
647 | internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) | 647 | internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) |
648 | { | 648 | { |
649 | this.calcVertexNormals = calcVertexNormals; | 649 | this.calcVertexNormals = calcVertexNormals; |
650 | this.coords = new List<Coord>(); | 650 | this.coords = new List<Coord>(); |
651 | this.faces = new List<Face>(); | 651 | this.faces = new List<Face>(); |
652 | this.vertexNormals = new List<Coord>(); | 652 | this.vertexNormals = new List<Coord>(); |
653 | this.us = new List<float>(); | 653 | this.us = new List<float>(); |
654 | this.faceUVs = new List<UVCoord>(); | 654 | this.faceUVs = new List<UVCoord>(); |
655 | this.faceNumbers = new List<int>(); | 655 | this.faceNumbers = new List<int>(); |
656 | 656 | ||
657 | Coord center = new Coord(0.0f, 0.0f, 0.0f); | 657 | Coord center = new Coord(0.0f, 0.0f, 0.0f); |
658 | //bool hasCenter = false; | 658 | //bool hasCenter = false; |
659 | 659 | ||
660 | List<Coord> hollowCoords = new List<Coord>(); | 660 | List<Coord> hollowCoords = new List<Coord>(); |
661 | List<Coord> hollowNormals = new List<Coord>(); | 661 | List<Coord> hollowNormals = new List<Coord>(); |
662 | List<float> hollowUs = new List<float>(); | 662 | List<float> hollowUs = new List<float>(); |
663 | 663 | ||
664 | if (calcVertexNormals) | 664 | if (calcVertexNormals) |
665 | { | 665 | { |
666 | this.outerCoordIndices = new List<int>(); | 666 | this.outerCoordIndices = new List<int>(); |
667 | this.hollowCoordIndices = new List<int>(); | 667 | this.hollowCoordIndices = new List<int>(); |
668 | this.cut1CoordIndices = new List<int>(); | 668 | this.cut1CoordIndices = new List<int>(); |
669 | this.cut2CoordIndices = new List<int>(); | 669 | this.cut2CoordIndices = new List<int>(); |
670 | } | 670 | } |
671 | 671 | ||
672 | bool hasHollow = (hollow > 0.0f); | 672 | bool hasHollow = (hollow > 0.0f); |
673 | 673 | ||
674 | bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f); | 674 | bool hasProfileCut = (profileStart > 0.0f || profileEnd < 1.0f); |
675 | 675 | ||
676 | AngleList angles = new AngleList(); | 676 | AngleList angles = new AngleList(); |
677 | AngleList hollowAngles = new AngleList(); | 677 | AngleList hollowAngles = new AngleList(); |
678 | 678 | ||
679 | float xScale = 0.5f; | 679 | float xScale = 0.5f; |
680 | float yScale = 0.5f; | 680 | float yScale = 0.5f; |
681 | if (sides == 4) // corners of a square are sqrt(2) from center | 681 | if (sides == 4) // corners of a square are sqrt(2) from center |
682 | { | 682 | { |
683 | xScale = 0.707f; | 683 | xScale = 0.707f; |
684 | yScale = 0.707f; | 684 | yScale = 0.707f; |
685 | } | 685 | } |
686 | 686 | ||
687 | float startAngle = profileStart * twoPi; | 687 | float startAngle = profileStart * twoPi; |
688 | float stopAngle = profileEnd * twoPi; | 688 | float stopAngle = profileEnd * twoPi; |
689 | 689 | ||
690 | try { angles.makeAngles(sides, startAngle, stopAngle); } | 690 | try { angles.makeAngles(sides, startAngle, stopAngle); } |
691 | catch (Exception ex) | 691 | catch (Exception ex) |
692 | { | 692 | { |
693 | 693 | ||
694 | errorMessage = "makeAngles failed: Exception: " + ex.ToString() | 694 | errorMessage = "makeAngles failed: Exception: " + ex.ToString() |
695 | + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); | 695 | + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); |
696 | 696 | ||
697 | return; | 697 | return; |
698 | } | 698 | } |
699 | 699 | ||
700 | this.numOuterVerts = angles.angles.Count; | 700 | this.numOuterVerts = angles.angles.Count; |
701 | 701 | ||
702 | // flag to create as few triangles as possible for 3 or 4 side profile | 702 | // flag to create as few triangles as possible for 3 or 4 side profile |
703 | bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut); | 703 | bool simpleFace = (sides < 5 && !hasHollow && !hasProfileCut); |
704 | 704 | ||
705 | if (hasHollow) | 705 | if (hasHollow) |
706 | { | 706 | { |
707 | if (sides == hollowSides) | 707 | if (sides == hollowSides) |
708 | hollowAngles = angles; | 708 | hollowAngles = angles; |
709 | else | 709 | else |
710 | { | 710 | { |
711 | try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); } | 711 | try { hollowAngles.makeAngles(hollowSides, startAngle, stopAngle); } |
712 | catch (Exception ex) | 712 | catch (Exception ex) |
713 | { | 713 | { |
714 | errorMessage = "makeAngles failed: Exception: " + ex.ToString() | 714 | errorMessage = "makeAngles failed: Exception: " + ex.ToString() |
715 | + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); | 715 | + "\nsides: " + sides.ToString() + " startAngle: " + startAngle.ToString() + " stopAngle: " + stopAngle.ToString(); |
716 | 716 | ||
717 | return; | 717 | return; |
718 | } | 718 | } |
719 | } | 719 | } |
720 | this.numHollowVerts = hollowAngles.angles.Count; | 720 | this.numHollowVerts = hollowAngles.angles.Count; |
721 | } | 721 | } |
722 | else if (!simpleFace) | 722 | else if (!simpleFace) |
723 | { | 723 | { |
724 | this.coords.Add(center); | 724 | this.coords.Add(center); |
725 | //hasCenter = true; | 725 | //hasCenter = true; |
726 | if (this.calcVertexNormals) | 726 | if (this.calcVertexNormals) |
727 | this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); | 727 | this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); |
728 | this.us.Add(0.0f); | 728 | this.us.Add(0.0f); |
729 | } | 729 | } |
730 | 730 | ||
731 | float z = 0.0f; | 731 | float z = 0.0f; |
732 | 732 | ||
733 | Angle angle; | 733 | Angle angle; |
734 | Coord newVert = new Coord(); | 734 | Coord newVert = new Coord(); |
735 | if (hasHollow && hollowSides != sides) | 735 | if (hasHollow && hollowSides != sides) |
736 | { | 736 | { |
737 | int numHollowAngles = hollowAngles.angles.Count; | 737 | int numHollowAngles = hollowAngles.angles.Count; |
738 | for (int i = 0; i < numHollowAngles; i++) | 738 | for (int i = 0; i < numHollowAngles; i++) |
739 | { | 739 | { |
740 | angle = hollowAngles.angles[i]; | 740 | angle = hollowAngles.angles[i]; |
741 | newVert.X = hollow * xScale * angle.X; | 741 | newVert.X = hollow * xScale * angle.X; |
742 | newVert.Y = hollow * yScale * angle.Y; | 742 | newVert.Y = hollow * yScale * angle.Y; |
743 | newVert.Z = z; | 743 | newVert.Z = z; |
744 | 744 | ||
745 | hollowCoords.Add(newVert); | 745 | hollowCoords.Add(newVert); |
746 | if (this.calcVertexNormals) | 746 | if (this.calcVertexNormals) |
747 | { | 747 | { |
748 | if (hollowSides < 5) | 748 | if (hollowSides < 5) |
749 | hollowNormals.Add(hollowAngles.normals[i].Invert()); | 749 | hollowNormals.Add(hollowAngles.normals[i].Invert()); |
750 | else | 750 | else |
751 | hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); | 751 | hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); |
752 | 752 | ||
753 | hollowUs.Add(angle.angle * hollow); | 753 | hollowUs.Add(angle.angle * hollow); |
754 | } | 754 | } |
755 | } | 755 | } |
756 | } | 756 | } |
757 | 757 | ||
758 | int index = 0; | 758 | int index = 0; |
759 | int numAngles = angles.angles.Count; | 759 | int numAngles = angles.angles.Count; |
760 | 760 | ||
761 | for (int i = 0; i < numAngles; i++) | 761 | for (int i = 0; i < numAngles; i++) |
762 | { | 762 | { |
763 | angle = angles.angles[i]; | 763 | angle = angles.angles[i]; |
764 | newVert.X = angle.X * xScale; | 764 | newVert.X = angle.X * xScale; |
765 | newVert.Y = angle.Y * yScale; | 765 | newVert.Y = angle.Y * yScale; |
766 | newVert.Z = z; | 766 | newVert.Z = z; |
767 | this.coords.Add(newVert); | 767 | this.coords.Add(newVert); |
768 | if (this.calcVertexNormals) | 768 | if (this.calcVertexNormals) |
769 | { | 769 | { |
770 | this.outerCoordIndices.Add(this.coords.Count - 1); | 770 | this.outerCoordIndices.Add(this.coords.Count - 1); |
771 | 771 | ||
772 | if (sides < 5) | 772 | if (sides < 5) |
773 | { | 773 | { |
774 | this.vertexNormals.Add(angles.normals[i]); | 774 | this.vertexNormals.Add(angles.normals[i]); |
775 | float u = angle.angle; | 775 | float u = angle.angle; |
776 | this.us.Add(u); | 776 | this.us.Add(u); |
777 | } | 777 | } |
778 | else | 778 | else |
779 | { | 779 | { |
780 | this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f)); | 780 | this.vertexNormals.Add(new Coord(angle.X, angle.Y, 0.0f)); |
781 | this.us.Add(angle.angle); | 781 | this.us.Add(angle.angle); |
782 | } | 782 | } |
783 | } | 783 | } |
784 | 784 | ||
785 | if (hasHollow) | 785 | if (hasHollow) |
786 | { | 786 | { |
787 | if (hollowSides == sides) | 787 | if (hollowSides == sides) |
788 | { | 788 | { |
789 | newVert.X *= hollow; | 789 | newVert.X *= hollow; |
790 | newVert.Y *= hollow; | 790 | newVert.Y *= hollow; |
791 | newVert.Z = z; | 791 | newVert.Z = z; |
792 | hollowCoords.Add(newVert); | 792 | hollowCoords.Add(newVert); |
793 | if (this.calcVertexNormals) | 793 | if (this.calcVertexNormals) |
794 | { | 794 | { |
795 | if (sides < 5) | 795 | if (sides < 5) |
796 | { | 796 | { |
797 | hollowNormals.Add(angles.normals[i].Invert()); | 797 | hollowNormals.Add(angles.normals[i].Invert()); |
798 | } | 798 | } |
799 | 799 | ||
800 | else | 800 | else |
801 | hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); | 801 | hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); |
802 | 802 | ||
803 | hollowUs.Add(angle.angle * hollow); | 803 | hollowUs.Add(angle.angle * hollow); |
804 | } | 804 | } |
805 | } | 805 | } |
806 | } | 806 | } |
807 | else if (!simpleFace && createFaces && angle.angle > 0.0001f) | 807 | else if (!simpleFace && createFaces && angle.angle > 0.0001f) |
808 | { | 808 | { |
809 | Face newFace = new Face(); | 809 | Face newFace = new Face(); |
810 | newFace.v1 = 0; | 810 | newFace.v1 = 0; |
811 | newFace.v2 = index; | 811 | newFace.v2 = index; |
812 | newFace.v3 = index + 1; | 812 | newFace.v3 = index + 1; |
813 | 813 | ||
814 | this.faces.Add(newFace); | 814 | this.faces.Add(newFace); |
815 | } | 815 | } |
816 | index += 1; | 816 | index += 1; |
817 | } | 817 | } |
818 | 818 | ||
819 | if (hasHollow) | 819 | if (hasHollow) |
820 | { | 820 | { |
821 | hollowCoords.Reverse(); | 821 | hollowCoords.Reverse(); |
822 | if (this.calcVertexNormals) | 822 | if (this.calcVertexNormals) |
823 | { | 823 | { |
824 | hollowNormals.Reverse(); | 824 | hollowNormals.Reverse(); |
825 | hollowUs.Reverse(); | 825 | hollowUs.Reverse(); |
826 | } | 826 | } |
827 | 827 | ||
828 | if (createFaces) | 828 | if (createFaces) |
829 | { | 829 | { |
830 | int numOuterVerts = this.coords.Count; | 830 | //int numOuterVerts = this.coords.Count; |
831 | int numHollowVerts = hollowCoords.Count; | 831 | //numOuterVerts = this.coords.Count; |
832 | int numTotalVerts = numOuterVerts + numHollowVerts; | 832 | //int numHollowVerts = hollowCoords.Count; |
833 | 833 | int numTotalVerts = this.numOuterVerts + this.numHollowVerts; | |
834 | if (numOuterVerts == numHollowVerts) | 834 | |
835 | { | 835 | if (this.numOuterVerts == this.numHollowVerts) |
836 | Face newFace = new Face(); | 836 | { |
837 | 837 | Face newFace = new Face(); | |
838 | for (int coordIndex = 0; coordIndex < numOuterVerts - 1; coordIndex++) | 838 | |
839 | { | 839 | for (int coordIndex = 0; coordIndex < this.numOuterVerts - 1; coordIndex++) |
840 | newFace.v1 = coordIndex; | 840 | { |
841 | newFace.v2 = coordIndex + 1; | 841 | newFace.v1 = coordIndex; |
842 | newFace.v3 = numTotalVerts - coordIndex - 1; | 842 | newFace.v2 = coordIndex + 1; |
843 | this.faces.Add(newFace); | 843 | newFace.v3 = numTotalVerts - coordIndex - 1; |
844 | 844 | this.faces.Add(newFace); | |
845 | newFace.v1 = coordIndex + 1; | 845 | |
846 | newFace.v2 = numTotalVerts - coordIndex - 2; | 846 | newFace.v1 = coordIndex + 1; |
847 | newFace.v3 = numTotalVerts - coordIndex - 1; | 847 | newFace.v2 = numTotalVerts - coordIndex - 2; |
848 | this.faces.Add(newFace); | 848 | newFace.v3 = numTotalVerts - coordIndex - 1; |
849 | } | 849 | this.faces.Add(newFace); |
850 | } | 850 | } |
851 | else | 851 | } |
852 | { | 852 | else |
853 | if (numOuterVerts < numHollowVerts) | 853 | { |
854 | { | 854 | if (this.numOuterVerts < this.numHollowVerts) |
855 | Face newFace = new Face(); | 855 | { |
856 | int j = 0; // j is the index for outer vertices | 856 | Face newFace = new Face(); |
857 | int maxJ = numOuterVerts - 1; | 857 | int j = 0; // j is the index for outer vertices |
858 | for (int i = 0; i < numHollowVerts; i++) // i is the index for inner vertices | 858 | int maxJ = this.numOuterVerts - 1; |
859 | { | 859 | for (int i = 0; i < this.numHollowVerts; i++) // i is the index for inner vertices |
860 | if (j < maxJ) | 860 | { |
861 | if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f) | 861 | if (j < maxJ) |
862 | { | 862 | if (angles.angles[j + 1].angle - hollowAngles.angles[i].angle < hollowAngles.angles[i].angle - angles.angles[j].angle + 0.000001f) |
863 | newFace.v1 = numTotalVerts - i - 1; | 863 | { |
864 | newFace.v2 = j; | 864 | newFace.v1 = numTotalVerts - i - 1; |
865 | newFace.v3 = j + 1; | 865 | newFace.v2 = j; |
866 | 866 | newFace.v3 = j + 1; | |
867 | this.faces.Add(newFace); | 867 | |
868 | j += 1; | 868 | this.faces.Add(newFace); |
869 | } | 869 | j += 1; |
870 | 870 | } | |
871 | newFace.v1 = j; | 871 | |
872 | newFace.v2 = numTotalVerts - i - 2; | 872 | newFace.v1 = j; |
873 | newFace.v3 = numTotalVerts - i - 1; | 873 | newFace.v2 = numTotalVerts - i - 2; |
874 | 874 | newFace.v3 = numTotalVerts - i - 1; | |
875 | this.faces.Add(newFace); | 875 | |
876 | } | 876 | this.faces.Add(newFace); |
877 | } | 877 | } |
878 | else // numHollowVerts < numOuterVerts | 878 | } |
879 | { | 879 | else // numHollowVerts < numOuterVerts |
880 | Face newFace = new Face(); | 880 | { |
881 | int j = 0; // j is the index for inner vertices | 881 | Face newFace = new Face(); |
882 | int maxJ = numHollowVerts - 1; | 882 | int j = 0; // j is the index for inner vertices |
883 | for (int i = 0; i < numOuterVerts; i++) | 883 | int maxJ = this.numHollowVerts - 1; |
884 | { | 884 | for (int i = 0; i < this.numOuterVerts; i++) |
885 | if (j < maxJ) | 885 | { |
886 | if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f) | 886 | if (j < maxJ) |
887 | { | 887 | if (hollowAngles.angles[j + 1].angle - angles.angles[i].angle < angles.angles[i].angle - hollowAngles.angles[j].angle + 0.000001f) |
888 | newFace.v1 = i; | 888 | { |
889 | newFace.v2 = numTotalVerts - j - 2; | 889 | newFace.v1 = i; |
890 | newFace.v3 = numTotalVerts - j - 1; | 890 | newFace.v2 = numTotalVerts - j - 2; |
891 | 891 | newFace.v3 = numTotalVerts - j - 1; | |
892 | this.faces.Add(newFace); | 892 | |
893 | j += 1; | 893 | this.faces.Add(newFace); |
894 | } | 894 | j += 1; |
895 | 895 | } | |
896 | newFace.v1 = numTotalVerts - j - 1; | 896 | |
897 | newFace.v2 = i; | 897 | newFace.v1 = numTotalVerts - j - 1; |
898 | newFace.v3 = i + 1; | 898 | newFace.v2 = i; |
899 | 899 | newFace.v3 = i + 1; | |
900 | this.faces.Add(newFace); | 900 | |
901 | } | 901 | this.faces.Add(newFace); |
902 | } | 902 | } |
903 | } | 903 | } |
904 | } | 904 | } |
905 | 905 | } | |
906 | if (calcVertexNormals) | 906 | |
907 | { | 907 | if (calcVertexNormals) |
908 | foreach (Coord hc in hollowCoords) | 908 | { |
909 | { | 909 | foreach (Coord hc in hollowCoords) |
910 | this.coords.Add(hc); | 910 | { |
911 | hollowCoordIndices.Add(this.coords.Count - 1); | 911 | this.coords.Add(hc); |
912 | } | 912 | hollowCoordIndices.Add(this.coords.Count - 1); |
913 | } | 913 | } |
914 | else | 914 | } |
915 | this.coords.AddRange(hollowCoords); | 915 | else |
916 | 916 | this.coords.AddRange(hollowCoords); | |
917 | if (this.calcVertexNormals) | 917 | |
918 | { | 918 | if (this.calcVertexNormals) |
919 | this.vertexNormals.AddRange(hollowNormals); | 919 | { |
920 | this.us.AddRange(hollowUs); | 920 | this.vertexNormals.AddRange(hollowNormals); |
921 | 921 | this.us.AddRange(hollowUs); | |
922 | } | 922 | |
923 | } | 923 | } |
924 | 924 | } | |
925 | if (simpleFace && createFaces) | 925 | |
926 | { | 926 | if (simpleFace && createFaces) |
927 | if (sides == 3) | 927 | { |
928 | this.faces.Add(new Face(0, 1, 2)); | 928 | if (sides == 3) |
929 | else if (sides == 4) | 929 | this.faces.Add(new Face(0, 1, 2)); |
930 | { | 930 | else if (sides == 4) |
931 | this.faces.Add(new Face(0, 1, 2)); | 931 | { |
932 | this.faces.Add(new Face(0, 2, 3)); | 932 | this.faces.Add(new Face(0, 1, 2)); |
933 | } | 933 | this.faces.Add(new Face(0, 2, 3)); |
934 | } | 934 | } |
935 | 935 | } | |
936 | if (calcVertexNormals && hasProfileCut) | 936 | |
937 | { | 937 | if (calcVertexNormals && hasProfileCut) |
938 | if (hasHollow) | 938 | { |
939 | { | 939 | if (hasHollow) |
940 | int lastOuterVertIndex = this.numOuterVerts - 1; | 940 | { |
941 | 941 | int lastOuterVertIndex = this.numOuterVerts - 1; | |
942 | this.cut1CoordIndices.Add(0); | 942 | |
943 | this.cut1CoordIndices.Add(this.coords.Count - 1); | 943 | this.cut1CoordIndices.Add(0); |
944 | 944 | this.cut1CoordIndices.Add(this.coords.Count - 1); | |
945 | this.cut2CoordIndices.Add(lastOuterVertIndex + 1); | 945 | |
946 | this.cut2CoordIndices.Add(lastOuterVertIndex); | 946 | this.cut2CoordIndices.Add(lastOuterVertIndex + 1); |
947 | 947 | this.cut2CoordIndices.Add(lastOuterVertIndex); | |
948 | this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y; | 948 | |
949 | this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X); | 949 | this.cutNormal1.X = this.coords[0].Y - this.coords[this.coords.Count - 1].Y; |
950 | 950 | this.cutNormal1.Y = -(this.coords[0].X - this.coords[this.coords.Count - 1].X); | |
951 | this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y; | 951 | |
952 | this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X); | 952 | this.cutNormal2.X = this.coords[lastOuterVertIndex + 1].Y - this.coords[lastOuterVertIndex].Y; |
953 | } | 953 | this.cutNormal2.Y = -(this.coords[lastOuterVertIndex + 1].X - this.coords[lastOuterVertIndex].X); |
954 | 954 | } | |
955 | else | 955 | |
956 | { | 956 | else |
957 | this.cutNormal1.X = this.vertexNormals[1].Y; | 957 | { |
958 | this.cutNormal1.Y = -this.vertexNormals[1].X; | 958 | this.cutNormal1.X = this.vertexNormals[1].Y; |
959 | 959 | this.cutNormal1.Y = -this.vertexNormals[1].X; | |
960 | this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y; | 960 | |
961 | this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X; | 961 | this.cutNormal2.X = -this.vertexNormals[this.vertexNormals.Count - 2].Y; |
962 | 962 | this.cutNormal2.Y = this.vertexNormals[this.vertexNormals.Count - 2].X; | |
963 | } | 963 | |
964 | this.cutNormal1.Normalize(); | 964 | } |
965 | this.cutNormal2.Normalize(); | 965 | this.cutNormal1.Normalize(); |
966 | } | 966 | this.cutNormal2.Normalize(); |
967 | 967 | } | |
968 | this.MakeFaceUVs(); | 968 | |
969 | 969 | this.MakeFaceUVs(); | |
970 | hollowCoords = null; | 970 | |
971 | hollowNormals = null; | 971 | hollowCoords = null; |
972 | hollowUs = null; | 972 | hollowNormals = null; |
973 | 973 | hollowUs = null; | |
974 | if (calcVertexNormals) | 974 | |
975 | { // calculate prim face numbers | 975 | if (calcVertexNormals) |
976 | 976 | { // calculate prim face numbers | |
977 | // face number order is top, outer, hollow, bottom, start cut, end cut | 977 | |
978 | // I know it's ugly but so is the whole concept of prim face numbers | 978 | // face number order is top, outer, hollow, bottom, start cut, end cut |
979 | 979 | // I know it's ugly but so is the whole concept of prim face numbers | |
980 | int faceNum = 1; // start with outer faces | 980 | |
981 | int startVert = hasProfileCut && !hasHollow ? 1 : 0; | 981 | int faceNum = 1; // start with outer faces |
982 | if (startVert > 0) | 982 | int startVert = hasProfileCut && !hasHollow ? 1 : 0; |
983 | this.faceNumbers.Add(-1); | 983 | if (startVert > 0) |
984 | for (int i = 0; i < numOuterVerts - 1; i++) | 984 | this.faceNumbers.Add(-1); |
985 | this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum); | 985 | for (int i = 0; i < this.numOuterVerts - 1; i++) |
986 | 986 | this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum); | |
987 | //if (!hasHollow && !hasProfileCut) | 987 | |
988 | // this.bottomFaceNumber = faceNum++; | 988 | //if (!hasHollow && !hasProfileCut) |
989 | 989 | // this.bottomFaceNumber = faceNum++; | |
990 | this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++); | 990 | |
991 | 991 | this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++); | |
992 | if (sides > 4 && (hasHollow || hasProfileCut)) | 992 | |
993 | faceNum++; | 993 | if (sides > 4 && (hasHollow || hasProfileCut)) |
994 | 994 | faceNum++; | |
995 | if (hasHollow) | 995 | |
996 | { | 996 | if (hasHollow) |
997 | for (int i = 0; i < numHollowVerts; i++) | 997 | { |
998 | this.faceNumbers.Add(faceNum); | 998 | for (int i = 0; i < this.numHollowVerts; i++) |
999 | 999 | this.faceNumbers.Add(faceNum); | |
1000 | faceNum++; | 1000 | |
1001 | } | 1001 | faceNum++; |
1002 | //if (hasProfileCut || hasHollow) | 1002 | } |
1003 | // this.bottomFaceNumber = faceNum++; | 1003 | //if (hasProfileCut || hasHollow) |
1004 | this.bottomFaceNumber = faceNum++; | 1004 | // this.bottomFaceNumber = faceNum++; |
1005 | 1005 | this.bottomFaceNumber = faceNum++; | |
1006 | if (hasHollow && hasProfileCut) | 1006 | |
1007 | this.faceNumbers.Add(faceNum++); | 1007 | if (hasHollow && hasProfileCut) |
1008 | for (int i = 0; i < this.faceNumbers.Count; i++) | 1008 | this.faceNumbers.Add(faceNum++); |
1009 | if (this.faceNumbers[i] == -1) | 1009 | for (int i = 0; i < this.faceNumbers.Count; i++) |
1010 | this.faceNumbers[i] = faceNum++; | 1010 | if (this.faceNumbers[i] == -1) |
1011 | 1011 | this.faceNumbers[i] = faceNum++; | |
1012 | 1012 | ||
1013 | this.numPrimFaces = faceNum; | 1013 | |
1014 | } | 1014 | this.numPrimFaces = faceNum; |
1015 | 1015 | } | |
1016 | } | 1016 | |
1017 | 1017 | } | |
1018 | internal void MakeFaceUVs() | 1018 | |
1019 | { | 1019 | internal void MakeFaceUVs() |
1020 | this.faceUVs = new List<UVCoord>(); | 1020 | { |
1021 | foreach (Coord c in this.coords) | 1021 | this.faceUVs = new List<UVCoord>(); |
1022 | this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y))); | 1022 | foreach (Coord c in this.coords) |
1023 | } | 1023 | this.faceUVs.Add(new UVCoord(0.5f + c.X, 0.5f - c.Y)); |
1024 | 1024 | } | |
1025 | internal Profile Copy() | 1025 | |
1026 | { | 1026 | internal Profile Copy() |
1027 | return this.Copy(true); | 1027 | { |
1028 | } | 1028 | return this.Copy(true); |
1029 | 1029 | } | |
1030 | internal Profile Copy(bool needFaces) | 1030 | |
1031 | { | 1031 | internal Profile Copy(bool needFaces) |
1032 | Profile copy = new Profile(); | 1032 | { |
1033 | 1033 | Profile copy = new Profile(); | |
1034 | copy.coords.AddRange(this.coords); | 1034 | |
1035 | copy.faceUVs.AddRange(this.faceUVs); | 1035 | copy.coords.AddRange(this.coords); |
1036 | 1036 | copy.faceUVs.AddRange(this.faceUVs); | |
1037 | if (needFaces) | 1037 | |
1038 | copy.faces.AddRange(this.faces); | 1038 | if (needFaces) |
1039 | if ((copy.calcVertexNormals = this.calcVertexNormals) == true) | 1039 | copy.faces.AddRange(this.faces); |
1040 | { | 1040 | if ((copy.calcVertexNormals = this.calcVertexNormals) == true) |
1041 | copy.vertexNormals.AddRange(this.vertexNormals); | 1041 | { |
1042 | copy.faceNormal = this.faceNormal; | 1042 | copy.vertexNormals.AddRange(this.vertexNormals); |
1043 | copy.cutNormal1 = this.cutNormal1; | 1043 | copy.faceNormal = this.faceNormal; |
1044 | copy.cutNormal2 = this.cutNormal2; | 1044 | copy.cutNormal1 = this.cutNormal1; |
1045 | copy.us.AddRange(this.us); | 1045 | copy.cutNormal2 = this.cutNormal2; |
1046 | copy.faceNumbers.AddRange(this.faceNumbers); | 1046 | copy.us.AddRange(this.us); |
1047 | 1047 | copy.faceNumbers.AddRange(this.faceNumbers); | |
1048 | copy.cut1CoordIndices = new List<int>(this.cut1CoordIndices); | 1048 | |
1049 | copy.cut2CoordIndices = new List<int>(this.cut2CoordIndices); | 1049 | copy.cut1CoordIndices = new List<int>(this.cut1CoordIndices); |
1050 | copy.hollowCoordIndices = new List<int>(this.hollowCoordIndices); | 1050 | copy.cut2CoordIndices = new List<int>(this.cut2CoordIndices); |
1051 | copy.outerCoordIndices = new List<int>(this.outerCoordIndices); | 1051 | copy.hollowCoordIndices = new List<int>(this.hollowCoordIndices); |
1052 | } | 1052 | copy.outerCoordIndices = new List<int>(this.outerCoordIndices); |
1053 | copy.numOuterVerts = this.numOuterVerts; | 1053 | } |
1054 | copy.numHollowVerts = this.numHollowVerts; | 1054 | copy.numOuterVerts = this.numOuterVerts; |
1055 | 1055 | copy.numHollowVerts = this.numHollowVerts; | |
1056 | return copy; | 1056 | |
1057 | } | 1057 | return copy; |
1058 | 1058 | } | |
1059 | internal void AddPos(Coord v) | 1059 | |
1060 | { | 1060 | internal void AddPos(Coord v) |
1061 | this.AddPos(v.X, v.Y, v.Z); | 1061 | { |
1062 | } | 1062 | this.AddPos(v.X, v.Y, v.Z); |
1063 | 1063 | } | |
1064 | internal void AddPos(float x, float y, float z) | 1064 | |
1065 | { | 1065 | internal void AddPos(float x, float y, float z) |
1066 | int i; | 1066 | { |
1067 | int numVerts = this.coords.Count; | 1067 | int i; |
1068 | Coord vert; | 1068 | int numVerts = this.coords.Count; |
1069 | 1069 | Coord vert; | |
1070 | for (i = 0; i < numVerts; i++) | 1070 | |
1071 | { | 1071 | for (i = 0; i < numVerts; i++) |
1072 | vert = this.coords[i]; | 1072 | { |
1073 | vert.X += x; | 1073 | vert = this.coords[i]; |
1074 | vert.Y += y; | 1074 | vert.X += x; |
1075 | vert.Z += z; | 1075 | vert.Y += y; |
1076 | this.coords[i] = vert; | 1076 | vert.Z += z; |
1077 | } | 1077 | this.coords[i] = vert; |
1078 | } | 1078 | } |
1079 | 1079 | } | |
1080 | internal void AddRot(Quat q) | 1080 | |
1081 | { | 1081 | internal void AddRot(Quat q) |
1082 | int i; | 1082 | { |
1083 | int numVerts = this.coords.Count; | 1083 | int i; |
1084 | 1084 | int numVerts = this.coords.Count; | |
1085 | for (i = 0; i < numVerts; i++) | 1085 | |
1086 | this.coords[i] *= q; | 1086 | for (i = 0; i < numVerts; i++) |
1087 | 1087 | this.coords[i] *= q; | |
1088 | if (this.calcVertexNormals) | 1088 | |
1089 | { | 1089 | if (this.calcVertexNormals) |
1090 | int numNormals = this.vertexNormals.Count; | 1090 | { |
1091 | for (i = 0; i < numNormals; i++) | 1091 | int numNormals = this.vertexNormals.Count; |
1092 | this.vertexNormals[i] *= q; | 1092 | for (i = 0; i < numNormals; i++) |
1093 | 1093 | this.vertexNormals[i] *= q; | |
1094 | this.faceNormal *= q; | 1094 | |
1095 | this.cutNormal1 *= q; | 1095 | this.faceNormal *= q; |
1096 | this.cutNormal2 *= q; | 1096 | this.cutNormal1 *= q; |
1097 | 1097 | this.cutNormal2 *= q; | |
1098 | } | 1098 | |
1099 | } | 1099 | } |
1100 | 1100 | } | |
1101 | internal void Scale(float x, float y) | 1101 | |
1102 | { | 1102 | internal void Scale(float x, float y) |
1103 | int i; | 1103 | { |
1104 | int numVerts = this.coords.Count; | 1104 | int i; |
1105 | Coord vert; | 1105 | int numVerts = this.coords.Count; |
1106 | 1106 | Coord vert; | |
1107 | for (i = 0; i < numVerts; i++) | 1107 | |
1108 | { | 1108 | for (i = 0; i < numVerts; i++) |
1109 | vert = this.coords[i]; | 1109 | { |
1110 | vert.X *= x; | 1110 | vert = this.coords[i]; |
1111 | vert.Y *= y; | 1111 | vert.X *= x; |
1112 | this.coords[i] = vert; | 1112 | vert.Y *= y; |
1113 | } | 1113 | this.coords[i] = vert; |
1114 | } | 1114 | } |
1115 | 1115 | } | |
1116 | /// <summary> | 1116 | |
1117 | /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices | 1117 | /// <summary> |
1118 | /// </summary> | 1118 | /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices |
1119 | internal void FlipNormals() | 1119 | /// </summary> |
1120 | { | 1120 | internal void FlipNormals() |
1121 | int i; | 1121 | { |
1122 | int numFaces = this.faces.Count; | 1122 | int i; |
1123 | Face tmpFace; | 1123 | int numFaces = this.faces.Count; |
1124 | int tmp; | 1124 | Face tmpFace; |
1125 | 1125 | int tmp; | |
1126 | for (i = 0; i < numFaces; i++) | 1126 | |
1127 | { | 1127 | for (i = 0; i < numFaces; i++) |
1128 | tmpFace = this.faces[i]; | 1128 | { |
1129 | tmp = tmpFace.v3; | 1129 | tmpFace = this.faces[i]; |
1130 | tmpFace.v3 = tmpFace.v1; | 1130 | tmp = tmpFace.v3; |
1131 | tmpFace.v1 = tmp; | 1131 | tmpFace.v3 = tmpFace.v1; |
1132 | this.faces[i] = tmpFace; | 1132 | tmpFace.v1 = tmp; |
1133 | } | 1133 | this.faces[i] = tmpFace; |
1134 | 1134 | } | |
1135 | if (this.calcVertexNormals) | 1135 | |
1136 | { | 1136 | if (this.calcVertexNormals) |
1137 | int normalCount = this.vertexNormals.Count; | 1137 | { |
1138 | if (normalCount > 0) | 1138 | int normalCount = this.vertexNormals.Count; |
1139 | { | 1139 | if (normalCount > 0) |
1140 | Coord n = this.vertexNormals[normalCount - 1]; | 1140 | { |
1141 | n.Z = -n.Z; | 1141 | Coord n = this.vertexNormals[normalCount - 1]; |
1142 | this.vertexNormals[normalCount - 1] = n; | 1142 | n.Z = -n.Z; |
1143 | } | 1143 | this.vertexNormals[normalCount - 1] = n; |
1144 | } | 1144 | } |
1145 | 1145 | } | |
1146 | this.faceNormal.X = -this.faceNormal.X; | 1146 | |
1147 | this.faceNormal.Y = -this.faceNormal.Y; | 1147 | this.faceNormal.X = -this.faceNormal.X; |
1148 | this.faceNormal.Z = -this.faceNormal.Z; | 1148 | this.faceNormal.Y = -this.faceNormal.Y; |
1149 | 1149 | this.faceNormal.Z = -this.faceNormal.Z; | |
1150 | int numfaceUVs = this.faceUVs.Count; | 1150 | |
1151 | for (i = 0; i < numfaceUVs; i++) | 1151 | int numfaceUVs = this.faceUVs.Count; |
1152 | { | 1152 | for (i = 0; i < numfaceUVs; i++) |
1153 | UVCoord uv = this.faceUVs[i]; | 1153 | { |
1154 | uv.V = 1.0f - uv.V; | 1154 | UVCoord uv = this.faceUVs[i]; |
1155 | this.faceUVs[i] = uv; | 1155 | uv.V = 1.0f - uv.V; |
1156 | } | 1156 | this.faceUVs[i] = uv; |
1157 | } | 1157 | } |
1158 | 1158 | } | |
1159 | internal void AddValue2FaceVertexIndices(int num) | 1159 | |
1160 | { | 1160 | internal void AddValue2FaceVertexIndices(int num) |
1161 | int numFaces = this.faces.Count; | 1161 | { |
1162 | Face tmpFace; | 1162 | int numFaces = this.faces.Count; |
1163 | for (int i = 0; i < numFaces; i++) | 1163 | Face tmpFace; |
1164 | { | 1164 | for (int i = 0; i < numFaces; i++) |
1165 | tmpFace = this.faces[i]; | 1165 | { |
1166 | tmpFace.v1 += num; | 1166 | tmpFace = this.faces[i]; |
1167 | tmpFace.v2 += num; | 1167 | tmpFace.v1 += num; |
1168 | tmpFace.v3 += num; | 1168 | tmpFace.v2 += num; |
1169 | 1169 | tmpFace.v3 += num; | |
1170 | this.faces[i] = tmpFace; | 1170 | |
1171 | } | 1171 | this.faces[i] = tmpFace; |
1172 | } | 1172 | } |
1173 | 1173 | } | |
1174 | internal void AddValue2FaceNormalIndices(int num) | 1174 | |
1175 | { | 1175 | internal void AddValue2FaceNormalIndices(int num) |
1176 | if (this.calcVertexNormals) | 1176 | { |
1177 | { | 1177 | if (this.calcVertexNormals) |
1178 | int numFaces = this.faces.Count; | 1178 | { |
1179 | Face tmpFace; | 1179 | int numFaces = this.faces.Count; |
1180 | for (int i = 0; i < numFaces; i++) | 1180 | Face tmpFace; |
1181 | { | 1181 | for (int i = 0; i < numFaces; i++) |
1182 | tmpFace = this.faces[i]; | 1182 | { |
1183 | tmpFace.n1 += num; | 1183 | tmpFace = this.faces[i]; |
1184 | tmpFace.n2 += num; | 1184 | tmpFace.n1 += num; |
1185 | tmpFace.n3 += num; | 1185 | tmpFace.n2 += num; |
1186 | 1186 | tmpFace.n3 += num; | |
1187 | this.faces[i] = tmpFace; | 1187 | |
1188 | } | 1188 | this.faces[i] = tmpFace; |
1189 | } | 1189 | } |
1190 | } | 1190 | } |
1191 | 1191 | } | |
1192 | internal void DumpRaw(String path, String name, String title) | 1192 | |
1193 | { | 1193 | internal void DumpRaw(String path, String name, String title) |
1194 | if (path == null) | 1194 | { |
1195 | return; | 1195 | if (path == null) |
1196 | String fileName = name + "_" + title + ".raw"; | 1196 | return; |
1197 | String completePath = System.IO.Path.Combine(path, fileName); | 1197 | String fileName = name + "_" + title + ".raw"; |
1198 | StreamWriter sw = new StreamWriter(completePath); | 1198 | String completePath = System.IO.Path.Combine(path, fileName); |
1199 | 1199 | StreamWriter sw = new StreamWriter(completePath); | |
1200 | for (int i = 0; i < this.faces.Count; i++) | 1200 | |
1201 | { | 1201 | for (int i = 0; i < this.faces.Count; i++) |
1202 | string s = this.coords[this.faces[i].v1].ToString(); | 1202 | { |
1203 | s += " " + this.coords[this.faces[i].v2].ToString(); | 1203 | string s = this.coords[this.faces[i].v1].ToString(); |
1204 | s += " " + this.coords[this.faces[i].v3].ToString(); | 1204 | s += " " + this.coords[this.faces[i].v2].ToString(); |
1205 | 1205 | s += " " + this.coords[this.faces[i].v3].ToString(); | |
1206 | sw.WriteLine(s); | 1206 | |
1207 | } | 1207 | sw.WriteLine(s); |
1208 | 1208 | } | |
1209 | sw.Close(); | 1209 | |
1210 | } | 1210 | sw.Close(); |
1211 | } | 1211 | } |
1212 | 1212 | } | |
1213 | public struct PathNode | 1213 | |
1214 | { | 1214 | public struct PathNode |
1215 | public Coord position; | 1215 | { |
1216 | public Quat rotation; | 1216 | public Coord position; |
1217 | public float xScale; | 1217 | public Quat rotation; |
1218 | public float yScale; | 1218 | public float xScale; |
1219 | public float percentOfPath; | 1219 | public float yScale; |
1220 | } | 1220 | public float percentOfPath; |
1221 | 1221 | } | |
1222 | public enum PathType { Linear = 0, Circular = 1, Flexible = 2 } | 1222 | |
1223 | 1223 | public enum PathType { Linear = 0, Circular = 1, Flexible = 2 } | |
1224 | public class Path | 1224 | |
1225 | { | 1225 | public class Path |
1226 | public List<PathNode> pathNodes = new List<PathNode>(); | 1226 | { |
1227 | 1227 | public List<PathNode> pathNodes = new List<PathNode>(); | |
1228 | public float twistBegin = 0.0f; | 1228 | |
1229 | public float twistEnd = 0.0f; | 1229 | public float twistBegin = 0.0f; |
1230 | public float topShearX = 0.0f; | 1230 | public float twistEnd = 0.0f; |
1231 | public float topShearY = 0.0f; | 1231 | public float topShearX = 0.0f; |
1232 | public float pathCutBegin = 0.0f; | 1232 | public float topShearY = 0.0f; |
1233 | public float pathCutEnd = 1.0f; | 1233 | public float pathCutBegin = 0.0f; |
1234 | public float dimpleBegin = 0.0f; | 1234 | public float pathCutEnd = 1.0f; |
1235 | public float dimpleEnd = 1.0f; | 1235 | public float dimpleBegin = 0.0f; |
1236 | public float skew = 0.0f; | 1236 | public float dimpleEnd = 1.0f; |
1237 | public float holeSizeX = 1.0f; // called pathScaleX in pbs | 1237 | public float skew = 0.0f; |
1238 | public float holeSizeY = 0.25f; | 1238 | public float holeSizeX = 1.0f; // called pathScaleX in pbs |
1239 | public float taperX = 0.0f; | 1239 | public float holeSizeY = 0.25f; |
1240 | public float taperY = 0.0f; | 1240 | public float taperX = 0.0f; |
1241 | public float radius = 0.0f; | 1241 | public float taperY = 0.0f; |
1242 | public float revolutions = 1.0f; | 1242 | public float radius = 0.0f; |
1243 | public int stepsPerRevolution = 24; | 1243 | public float revolutions = 1.0f; |
1244 | 1244 | public int stepsPerRevolution = 24; | |
1245 | private const float twoPi = 2.0f * (float)Math.PI; | 1245 | |
1246 | 1246 | private const float twoPi = 2.0f * (float)Math.PI; | |
1247 | public void Create(PathType pathType, int steps) | 1247 | |
1248 | { | 1248 | public void Create(PathType pathType, int steps) |
1249 | if (pathType == PathType.Linear || pathType == PathType.Flexible) | 1249 | { |
1250 | { | 1250 | if (pathType == PathType.Linear || pathType == PathType.Flexible) |
1251 | int step = 0; | 1251 | { |
1252 | 1252 | int step = 0; | |
1253 | float length = this.pathCutEnd - this.pathCutBegin; | 1253 | |
1254 | float twistTotal = twistEnd - twistBegin; | 1254 | float length = this.pathCutEnd - this.pathCutBegin; |
1255 | float twistTotalAbs = Math.Abs(twistTotal); | 1255 | float twistTotal = twistEnd - twistBegin; |
1256 | if (twistTotalAbs > 0.01f) | 1256 | float twistTotalAbs = Math.Abs(twistTotal); |
1257 | steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number | 1257 | if (twistTotalAbs > 0.01f) |
1258 | 1258 | steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number | |
1259 | float start = -0.5f; | 1259 | |
1260 | float stepSize = length / (float)steps; | 1260 | float start = -0.5f; |
1261 | float percentOfPathMultiplier = stepSize; | 1261 | float stepSize = length / (float)steps; |
1262 | float xOffset = 0.0f; | 1262 | float percentOfPathMultiplier = stepSize; |
1263 | float yOffset = 0.0f; | 1263 | float xOffset = 0.0f; |
1264 | float zOffset = start; | 1264 | float yOffset = 0.0f; |
1265 | float xOffsetStepIncrement = this.topShearX / steps; | 1265 | float zOffset = start; |
1266 | float yOffsetStepIncrement = this.topShearY / steps; | 1266 | float xOffsetStepIncrement = this.topShearX / steps; |
1267 | 1267 | float yOffsetStepIncrement = this.topShearY / steps; | |
1268 | float percentOfPath = this.pathCutBegin; | 1268 | |
1269 | zOffset += percentOfPath; | 1269 | float percentOfPath = this.pathCutBegin; |
1270 | 1270 | zOffset += percentOfPath; | |
1271 | // sanity checks | 1271 | |
1272 | 1272 | // sanity checks | |
1273 | bool done = false; | 1273 | |
1274 | 1274 | bool done = false; | |
1275 | while (!done) | 1275 | |
1276 | { | 1276 | while (!done) |
1277 | PathNode newNode = new PathNode(); | 1277 | { |
1278 | 1278 | PathNode newNode = new PathNode(); | |
1279 | newNode.xScale = 1.0f; | 1279 | |
1280 | if (this.taperX == 0.0f) | 1280 | newNode.xScale = 1.0f; |
1281 | newNode.xScale = 1.0f; | 1281 | if (this.taperX == 0.0f) |
1282 | else if (this.taperX > 0.0f) | 1282 | newNode.xScale = 1.0f; |
1283 | newNode.xScale = 1.0f - percentOfPath * this.taperX; | 1283 | else if (this.taperX > 0.0f) |
1284 | else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX; | 1284 | newNode.xScale = 1.0f - percentOfPath * this.taperX; |
1285 | 1285 | else newNode.xScale = 1.0f + (1.0f - percentOfPath) * this.taperX; | |
1286 | newNode.yScale = 1.0f; | 1286 | |
1287 | if (this.taperY == 0.0f) | 1287 | newNode.yScale = 1.0f; |
1288 | newNode.yScale = 1.0f; | 1288 | if (this.taperY == 0.0f) |
1289 | else if (this.taperY > 0.0f) | 1289 | newNode.yScale = 1.0f; |
1290 | newNode.yScale = 1.0f - percentOfPath * this.taperY; | 1290 | else if (this.taperY > 0.0f) |
1291 | else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY; | 1291 | newNode.yScale = 1.0f - percentOfPath * this.taperY; |
1292 | 1292 | else newNode.yScale = 1.0f + (1.0f - percentOfPath) * this.taperY; | |
1293 | float twist = twistBegin + twistTotal * percentOfPath; | 1293 | |
1294 | 1294 | float twist = twistBegin + twistTotal * percentOfPath; | |
1295 | newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); | 1295 | |
1296 | newNode.position = new Coord(xOffset, yOffset, zOffset); | 1296 | newNode.rotation = new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); |
1297 | newNode.percentOfPath = percentOfPath; | 1297 | newNode.position = new Coord(xOffset, yOffset, zOffset); |
1298 | 1298 | newNode.percentOfPath = percentOfPath; | |
1299 | pathNodes.Add(newNode); | 1299 | |
1300 | 1300 | pathNodes.Add(newNode); | |
1301 | if (step < steps) | 1301 | |
1302 | { | 1302 | if (step < steps) |
1303 | step += 1; | 1303 | { |
1304 | percentOfPath += percentOfPathMultiplier; | 1304 | step += 1; |
1305 | xOffset += xOffsetStepIncrement; | 1305 | percentOfPath += percentOfPathMultiplier; |
1306 | yOffset += yOffsetStepIncrement; | 1306 | xOffset += xOffsetStepIncrement; |
1307 | zOffset += stepSize; | 1307 | yOffset += yOffsetStepIncrement; |
1308 | if (percentOfPath > this.pathCutEnd) | 1308 | zOffset += stepSize; |
1309 | done = true; | 1309 | if (percentOfPath > this.pathCutEnd) |
1310 | } | 1310 | done = true; |
1311 | else done = true; | 1311 | } |
1312 | } | 1312 | else done = true; |
1313 | } // end of linear path code | 1313 | } |
1314 | 1314 | } // end of linear path code | |
1315 | else // pathType == Circular | 1315 | |
1316 | { | 1316 | else // pathType == Circular |
1317 | float twistTotal = twistEnd - twistBegin; | 1317 | { |
1318 | 1318 | float twistTotal = twistEnd - twistBegin; | |
1319 | // if the profile has a lot of twist, add more layers otherwise the layers may overlap | 1319 | |
1320 | // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't | 1320 | // if the profile has a lot of twist, add more layers otherwise the layers may overlap |
1321 | // accurately match the viewer | 1321 | // and the resulting mesh may be quite inaccurate. This method is arbitrary and doesn't |
1322 | float twistTotalAbs = Math.Abs(twistTotal); | 1322 | // accurately match the viewer |
1323 | if (twistTotalAbs > 0.01f) | 1323 | float twistTotalAbs = Math.Abs(twistTotal); |
1324 | { | 1324 | if (twistTotalAbs > 0.01f) |
1325 | if (twistTotalAbs > Math.PI * 1.5f) | 1325 | { |
1326 | steps *= 2; | 1326 | if (twistTotalAbs > Math.PI * 1.5f) |
1327 | if (twistTotalAbs > Math.PI * 3.0f) | 1327 | steps *= 2; |
1328 | steps *= 2; | 1328 | if (twistTotalAbs > Math.PI * 3.0f) |
1329 | } | 1329 | steps *= 2; |
1330 | 1330 | } | |
1331 | float yPathScale = this.holeSizeY * 0.5f; | 1331 | |
1332 | float pathLength = this.pathCutEnd - this.pathCutBegin; | 1332 | float yPathScale = this.holeSizeY * 0.5f; |
1333 | float totalSkew = this.skew * 2.0f * pathLength; | 1333 | float pathLength = this.pathCutEnd - this.pathCutBegin; |
1334 | float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; | 1334 | float totalSkew = this.skew * 2.0f * pathLength; |
1335 | float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); | 1335 | float skewStart = this.pathCutBegin * 2.0f * this.skew - this.skew; |
1336 | float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; | 1336 | float xOffsetTopShearXFactor = this.topShearX * (0.25f + 0.5f * (0.5f - this.holeSizeY)); |
1337 | 1337 | float yShearCompensation = 1.0f + Math.Abs(this.topShearY) * 0.25f; | |
1338 | // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end | 1338 | |
1339 | // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used | 1339 | // It's not quite clear what pushY (Y top shear) does, but subtracting it from the start and end |
1340 | // to calculate the sine for generating the path radius appears to approximate it's effects there | 1340 | // angles appears to approximate it's effects on path cut. Likewise, adding it to the angle used |
1341 | // too, but there are some subtle differences in the radius which are noticeable as the prim size | 1341 | // to calculate the sine for generating the path radius appears to approximate it's effects there |
1342 | // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on | 1342 | // too, but there are some subtle differences in the radius which are noticeable as the prim size |
1343 | // the meshes generated with this technique appear nearly identical in shape to the same prims when | 1343 | // increases and it may affect megaprims quite a bit. The effect of the Y top shear parameter on |
1344 | // displayed by the viewer. | 1344 | // the meshes generated with this technique appear nearly identical in shape to the same prims when |
1345 | 1345 | // displayed by the viewer. | |
1346 | float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; | 1346 | |
1347 | float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; | 1347 | float startAngle = (twoPi * this.pathCutBegin * this.revolutions) - this.topShearY * 0.9f; |
1348 | float stepSize = twoPi / this.stepsPerRevolution; | 1348 | float endAngle = (twoPi * this.pathCutEnd * this.revolutions) - this.topShearY * 0.9f; |
1349 | 1349 | float stepSize = twoPi / this.stepsPerRevolution; | |
1350 | int step = (int)(startAngle / stepSize); | 1350 | |
1351 | // int firstStep = step; | 1351 | int step = (int)(startAngle / stepSize); |
1352 | float angle = startAngle; | 1352 | float angle = startAngle; |
1353 | 1353 | ||
1354 | bool done = false; | 1354 | bool done = false; |
1355 | while (!done) // loop through the length of the path and add the layers | 1355 | while (!done) // loop through the length of the path and add the layers |
1356 | { | 1356 | { |
1357 | PathNode newNode = new PathNode(); | 1357 | PathNode newNode = new PathNode(); |
1358 | 1358 | ||
1359 | float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; | 1359 | float xProfileScale = (1.0f - Math.Abs(this.skew)) * this.holeSizeX; |
1360 | float yProfileScale = this.holeSizeY; | 1360 | float yProfileScale = this.holeSizeY; |
1361 | 1361 | ||
1362 | float percentOfPath = angle / (twoPi * this.revolutions); | 1362 | float percentOfPath = angle / (twoPi * this.revolutions); |
1363 | float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); | 1363 | float percentOfAngles = (angle - startAngle) / (endAngle - startAngle); |
1364 | 1364 | ||
1365 | if (this.taperX > 0.01f) | 1365 | if (this.taperX > 0.01f) |
1366 | xProfileScale *= 1.0f - percentOfPath * this.taperX; | 1366 | xProfileScale *= 1.0f - percentOfPath * this.taperX; |
1367 | else if (this.taperX < -0.01f) | 1367 | else if (this.taperX < -0.01f) |
1368 | xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; | 1368 | xProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperX; |
1369 | 1369 | ||
1370 | if (this.taperY > 0.01f) | 1370 | if (this.taperY > 0.01f) |
1371 | yProfileScale *= 1.0f - percentOfPath * this.taperY; | 1371 | yProfileScale *= 1.0f - percentOfPath * this.taperY; |
1372 | else if (this.taperY < -0.01f) | 1372 | else if (this.taperY < -0.01f) |
1373 | yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; | 1373 | yProfileScale *= 1.0f + (1.0f - percentOfPath) * this.taperY; |
1374 | 1374 | ||
1375 | newNode.xScale = xProfileScale; | 1375 | newNode.xScale = xProfileScale; |
1376 | newNode.yScale = yProfileScale; | 1376 | newNode.yScale = yProfileScale; |
1377 | 1377 | ||
1378 | float radiusScale = 1.0f; | 1378 | float radiusScale = 1.0f; |
1379 | if (this.radius > 0.001f) | 1379 | if (this.radius > 0.001f) |
1380 | radiusScale = 1.0f - this.radius * percentOfPath; | 1380 | radiusScale = 1.0f - this.radius * percentOfPath; |
1381 | else if (this.radius < 0.001f) | 1381 | else if (this.radius < 0.001f) |
1382 | radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); | 1382 | radiusScale = 1.0f + this.radius * (1.0f - percentOfPath); |
1383 | 1383 | ||
1384 | float twist = twistBegin + twistTotal * percentOfPath; | 1384 | float twist = twistBegin + twistTotal * percentOfPath; |
1385 | 1385 | ||
1386 | float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); | 1386 | float xOffset = 0.5f * (skewStart + totalSkew * percentOfAngles); |
1387 | xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; | 1387 | xOffset += (float)Math.Sin(angle) * xOffsetTopShearXFactor; |
1388 | 1388 | ||
1389 | float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; | 1389 | float yOffset = yShearCompensation * (float)Math.Cos(angle) * (0.5f - yPathScale) * radiusScale; |
1390 | 1390 | ||
1391 | float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; | 1391 | float zOffset = (float)Math.Sin(angle + this.topShearY) * (0.5f - yPathScale) * radiusScale; |
1392 | 1392 | ||
1393 | newNode.position = new Coord(xOffset, yOffset, zOffset); | 1393 | newNode.position = new Coord(xOffset, yOffset, zOffset); |
1394 | 1394 | ||
1395 | // now orient the rotation of the profile layer relative to it's position on the path | 1395 | // now orient the rotation of the profile layer relative to it's position on the path |
1396 | // adding taperY to the angle used to generate the quat appears to approximate the viewer | 1396 | // adding taperY to the angle used to generate the quat appears to approximate the viewer |
1397 | 1397 | ||
1398 | newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY); | 1398 | newNode.rotation = new Quat(new Coord(1.0f, 0.0f, 0.0f), angle + this.topShearY); |
1399 | 1399 | ||
1400 | // next apply twist rotation to the profile layer | 1400 | // next apply twist rotation to the profile layer |
1401 | if (twistTotal != 0.0f || twistBegin != 0.0f) | 1401 | if (twistTotal != 0.0f || twistBegin != 0.0f) |
1402 | newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); | 1402 | newNode.rotation *= new Quat(new Coord(0.0f, 0.0f, 1.0f), twist); |
1403 | 1403 | ||
1404 | newNode.percentOfPath = percentOfPath; | 1404 | newNode.percentOfPath = percentOfPath; |
1405 | 1405 | ||
1406 | pathNodes.Add(newNode); | 1406 | pathNodes.Add(newNode); |
1407 | 1407 | ||
1408 | // calculate terms for next iteration | 1408 | // calculate terms for next iteration |
1409 | // calculate the angle for the next iteration of the loop | 1409 | // calculate the angle for the next iteration of the loop |
1410 | 1410 | ||
1411 | if (angle >= endAngle - 0.01) | 1411 | if (angle >= endAngle - 0.01) |
1412 | done = true; | 1412 | done = true; |
1413 | else | 1413 | else |
1414 | { | 1414 | { |
1415 | step += 1; | 1415 | step += 1; |
1416 | angle = stepSize * step; | 1416 | angle = stepSize * step; |
1417 | if (angle > endAngle) | 1417 | if (angle > endAngle) |
1418 | angle = endAngle; | 1418 | angle = endAngle; |
1419 | } | 1419 | } |
1420 | } | 1420 | } |
1421 | } | 1421 | } |
1422 | } | 1422 | } |
1423 | } | 1423 | } |
1424 | 1424 | ||
1425 | public class PrimMesh | 1425 | public class PrimMesh |
1426 | { | 1426 | { |
1427 | public string errorMessage = ""; | 1427 | public string errorMessage = ""; |
1428 | private const float twoPi = 2.0f * (float)Math.PI; | 1428 | private const float twoPi = 2.0f * (float)Math.PI; |
1429 | 1429 | ||
1430 | public List<Coord> coords; | 1430 | public List<Coord> coords; |
1431 | public List<Coord> normals; | 1431 | public List<Coord> normals; |
1432 | public List<Face> faces; | 1432 | public List<Face> faces; |
1433 | 1433 | ||
1434 | public List<ViewerFace> viewerFaces; | 1434 | public List<ViewerFace> viewerFaces; |
1435 | 1435 | ||
1436 | private int sides = 4; | 1436 | private int sides = 4; |
1437 | private int hollowSides = 4; | 1437 | private int hollowSides = 4; |
1438 | private float profileStart = 0.0f; | 1438 | private float profileStart = 0.0f; |
1439 | private float profileEnd = 1.0f; | 1439 | private float profileEnd = 1.0f; |
1440 | private float hollow = 0.0f; | 1440 | private float hollow = 0.0f; |
1441 | public int twistBegin = 0; | 1441 | public int twistBegin = 0; |
1442 | public int twistEnd = 0; | 1442 | public int twistEnd = 0; |
1443 | public float topShearX = 0.0f; | 1443 | public float topShearX = 0.0f; |
1444 | public float topShearY = 0.0f; | 1444 | public float topShearY = 0.0f; |
1445 | public float pathCutBegin = 0.0f; | 1445 | public float pathCutBegin = 0.0f; |
1446 | public float pathCutEnd = 1.0f; | 1446 | public float pathCutEnd = 1.0f; |
1447 | public float dimpleBegin = 0.0f; | 1447 | public float dimpleBegin = 0.0f; |
1448 | public float dimpleEnd = 1.0f; | 1448 | public float dimpleEnd = 1.0f; |
1449 | public float skew = 0.0f; | 1449 | public float skew = 0.0f; |
1450 | public float holeSizeX = 1.0f; // called pathScaleX in pbs | 1450 | public float holeSizeX = 1.0f; // called pathScaleX in pbs |
1451 | public float holeSizeY = 0.25f; | 1451 | public float holeSizeY = 0.25f; |
1452 | public float taperX = 0.0f; | 1452 | public float taperX = 0.0f; |
1453 | public float taperY = 0.0f; | 1453 | public float taperY = 0.0f; |
1454 | public float radius = 0.0f; | 1454 | public float radius = 0.0f; |
1455 | public float revolutions = 1.0f; | 1455 | public float revolutions = 1.0f; |
1456 | public int stepsPerRevolution = 24; | 1456 | public int stepsPerRevolution = 24; |
1457 | 1457 | ||
1458 | private bool hasProfileCut = false; | 1458 | private bool hasProfileCut = false; |
1459 | private bool hasHollow = false; | 1459 | private bool hasHollow = false; |
1460 | public bool calcVertexNormals = false; | 1460 | public bool calcVertexNormals = false; |
1461 | private bool normalsProcessed = false; | 1461 | private bool normalsProcessed = false; |
1462 | public bool viewerMode = false; | 1462 | public bool viewerMode = false; |
1463 | 1463 | ||
1464 | public int numPrimFaces = 0; | 1464 | public int numPrimFaces = 0; |
1465 | 1465 | ||
1466 | /// <summary> | 1466 | /// <summary> |
1467 | /// Human readable string representation of the parameters used to create a mesh. | 1467 | /// Human readable string representation of the parameters used to create a mesh. |
1468 | /// </summary> | 1468 | /// </summary> |
1469 | /// <returns></returns> | 1469 | /// <returns></returns> |
1470 | public string ParamsToDisplayString() | 1470 | public string ParamsToDisplayString() |
1471 | { | 1471 | { |
1472 | string s = ""; | 1472 | string s = ""; |
1473 | s += "sides..................: " + this.sides.ToString(); | 1473 | s += "sides..................: " + this.sides.ToString(); |
1474 | s += "\nhollowSides..........: " + this.hollowSides.ToString(); | 1474 | s += "\nhollowSides..........: " + this.hollowSides.ToString(); |
1475 | s += "\nprofileStart.........: " + this.profileStart.ToString(); | 1475 | s += "\nprofileStart.........: " + this.profileStart.ToString(); |
1476 | s += "\nprofileEnd...........: " + this.profileEnd.ToString(); | 1476 | s += "\nprofileEnd...........: " + this.profileEnd.ToString(); |
1477 | s += "\nhollow...............: " + this.hollow.ToString(); | 1477 | s += "\nhollow...............: " + this.hollow.ToString(); |
1478 | s += "\ntwistBegin...........: " + this.twistBegin.ToString(); | 1478 | s += "\ntwistBegin...........: " + this.twistBegin.ToString(); |
1479 | s += "\ntwistEnd.............: " + this.twistEnd.ToString(); | 1479 | s += "\ntwistEnd.............: " + this.twistEnd.ToString(); |
1480 | s += "\ntopShearX............: " + this.topShearX.ToString(); | 1480 | s += "\ntopShearX............: " + this.topShearX.ToString(); |
1481 | s += "\ntopShearY............: " + this.topShearY.ToString(); | 1481 | s += "\ntopShearY............: " + this.topShearY.ToString(); |
1482 | s += "\npathCutBegin.........: " + this.pathCutBegin.ToString(); | 1482 | s += "\npathCutBegin.........: " + this.pathCutBegin.ToString(); |
1483 | s += "\npathCutEnd...........: " + this.pathCutEnd.ToString(); | 1483 | s += "\npathCutEnd...........: " + this.pathCutEnd.ToString(); |
1484 | s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString(); | 1484 | s += "\ndimpleBegin..........: " + this.dimpleBegin.ToString(); |
1485 | s += "\ndimpleEnd............: " + this.dimpleEnd.ToString(); | 1485 | s += "\ndimpleEnd............: " + this.dimpleEnd.ToString(); |
1486 | s += "\nskew.................: " + this.skew.ToString(); | 1486 | s += "\nskew.................: " + this.skew.ToString(); |
1487 | s += "\nholeSizeX............: " + this.holeSizeX.ToString(); | 1487 | s += "\nholeSizeX............: " + this.holeSizeX.ToString(); |
1488 | s += "\nholeSizeY............: " + this.holeSizeY.ToString(); | 1488 | s += "\nholeSizeY............: " + this.holeSizeY.ToString(); |
1489 | s += "\ntaperX...............: " + this.taperX.ToString(); | 1489 | s += "\ntaperX...............: " + this.taperX.ToString(); |
1490 | s += "\ntaperY...............: " + this.taperY.ToString(); | 1490 | s += "\ntaperY...............: " + this.taperY.ToString(); |
1491 | s += "\nradius...............: " + this.radius.ToString(); | 1491 | s += "\nradius...............: " + this.radius.ToString(); |
1492 | s += "\nrevolutions..........: " + this.revolutions.ToString(); | 1492 | s += "\nrevolutions..........: " + this.revolutions.ToString(); |
1493 | s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString(); | 1493 | s += "\nstepsPerRevolution...: " + this.stepsPerRevolution.ToString(); |
1494 | 1494 | ||
1495 | return s; | 1495 | return s; |
1496 | } | 1496 | } |
1497 | 1497 | ||
1498 | /// <summary> | 1498 | /// <summary> |
1499 | /// Constructs a PrimMesh object and creates the profile for extrusion. | 1499 | /// Constructs a PrimMesh object and creates the profile for extrusion. |
1500 | /// </summary> | 1500 | /// </summary> |
1501 | /// <param name="sides"></param> | 1501 | /// <param name="sides"></param> |
1502 | /// <param name="profileStart"></param> | 1502 | /// <param name="profileStart"></param> |
1503 | /// <param name="profileEnd"></param> | 1503 | /// <param name="profileEnd"></param> |
1504 | /// <param name="hollow"></param> | 1504 | /// <param name="hollow"></param> |
1505 | /// <param name="hollowSides"></param> | 1505 | /// <param name="hollowSides"></param> |
1506 | public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) | 1506 | public PrimMesh(int sides, float profileStart, float profileEnd, float hollow, int hollowSides) |
1507 | { | 1507 | { |
1508 | this.coords = new List<Coord>(); | 1508 | this.coords = new List<Coord>(); |
1509 | this.faces = new List<Face>(); | 1509 | this.faces = new List<Face>(); |
1510 | 1510 | ||
1511 | this.sides = sides; | 1511 | this.sides = sides; |
1512 | this.profileStart = profileStart; | 1512 | this.profileStart = profileStart; |
1513 | this.profileEnd = profileEnd; | 1513 | this.profileEnd = profileEnd; |
1514 | this.hollow = hollow; | 1514 | this.hollow = hollow; |
1515 | this.hollowSides = hollowSides; | 1515 | this.hollowSides = hollowSides; |
1516 | 1516 | ||
1517 | if (sides < 3) | 1517 | if (sides < 3) |
1518 | this.sides = 3; | 1518 | this.sides = 3; |
1519 | if (hollowSides < 3) | 1519 | if (hollowSides < 3) |
1520 | this.hollowSides = 3; | 1520 | this.hollowSides = 3; |
1521 | if (profileStart < 0.0f) | 1521 | if (profileStart < 0.0f) |
1522 | this.profileStart = 0.0f; | 1522 | this.profileStart = 0.0f; |
1523 | if (profileEnd > 1.0f) | 1523 | if (profileEnd > 1.0f) |
1524 | this.profileEnd = 1.0f; | 1524 | this.profileEnd = 1.0f; |
1525 | if (profileEnd < 0.02f) | 1525 | if (profileEnd < 0.02f) |
1526 | this.profileEnd = 0.02f; | 1526 | this.profileEnd = 0.02f; |
1527 | if (profileStart >= profileEnd) | 1527 | if (profileStart >= profileEnd) |
1528 | this.profileStart = profileEnd - 0.02f; | 1528 | this.profileStart = profileEnd - 0.02f; |
1529 | if (hollow > 0.99f) | 1529 | if (hollow > 0.99f) |
1530 | this.hollow = 0.99f; | 1530 | this.hollow = 0.99f; |
1531 | if (hollow < 0.0f) | 1531 | if (hollow < 0.0f) |
1532 | this.hollow = 0.0f; | 1532 | this.hollow = 0.0f; |
1533 | 1533 | ||
1534 | this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f); | 1534 | this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f); |
1535 | this.hasHollow = (this.hollow > 0.001f); | 1535 | this.hasHollow = (this.hollow > 0.001f); |
1536 | } | 1536 | } |
1537 | 1537 | ||
1538 | /// <summary> | 1538 | /// <summary> |
1539 | /// Extrudes a profile along a path. | 1539 | /// Extrudes a profile along a path. |
1540 | /// </summary> | 1540 | /// </summary> |
1541 | public void Extrude(PathType pathType) | 1541 | public void Extrude(PathType pathType) |
1542 | { | 1542 | { |
1543 | this.coords = new List<Coord>(); | 1543 | this.coords = new List<Coord>(); |
1544 | this.faces = new List<Face>(); | 1544 | this.faces = new List<Face>(); |
1545 | 1545 | ||
1546 | if (this.viewerMode) | 1546 | if (this.viewerMode) |
1547 | { | 1547 | { |
1548 | this.viewerFaces = new List<ViewerFace>(); | 1548 | this.viewerFaces = new List<ViewerFace>(); |
1549 | this.calcVertexNormals = true; | 1549 | this.calcVertexNormals = true; |
1550 | } | 1550 | } |
1551 | 1551 | ||
1552 | if (this.calcVertexNormals) | 1552 | if (this.calcVertexNormals) |
1553 | this.normals = new List<Coord>(); | 1553 | this.normals = new List<Coord>(); |
1554 | 1554 | ||
1555 | int steps = 1; | 1555 | int steps = 1; |
1556 | 1556 | ||
1557 | float length = this.pathCutEnd - this.pathCutBegin; | 1557 | float length = this.pathCutEnd - this.pathCutBegin; |
1558 | normalsProcessed = false; | 1558 | normalsProcessed = false; |
1559 | 1559 | ||
1560 | if (this.viewerMode && this.sides == 3) | 1560 | if (this.viewerMode && this.sides == 3) |
1561 | { | 1561 | { |
1562 | // prisms don't taper well so add some vertical resolution | 1562 | // prisms don't taper well so add some vertical resolution |
1563 | // other prims may benefit from this but just do prisms for now | 1563 | // other prims may benefit from this but just do prisms for now |
1564 | if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) | 1564 | if (Math.Abs(this.taperX) > 0.01 || Math.Abs(this.taperY) > 0.01) |
1565 | steps = (int)(steps * 4.5 * length); | 1565 | steps = (int)(steps * 4.5 * length); |
1566 | } | 1566 | } |
1567 | 1567 | ||
1568 | 1568 | ||
1569 | float twistBegin = this.twistBegin / 360.0f * twoPi; | 1569 | float twistBegin = this.twistBegin / 360.0f * twoPi; |
1570 | float twistEnd = this.twistEnd / 360.0f * twoPi; | 1570 | float twistEnd = this.twistEnd / 360.0f * twoPi; |
1571 | float twistTotal = twistEnd - twistBegin; | 1571 | float twistTotal = twistEnd - twistBegin; |
1572 | float twistTotalAbs = Math.Abs(twistTotal); | 1572 | float twistTotalAbs = Math.Abs(twistTotal); |
1573 | if (twistTotalAbs > 0.01f) | 1573 | if (twistTotalAbs > 0.01f) |
1574 | steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number | 1574 | steps += (int)(twistTotalAbs * 3.66); // dahlia's magic number |
1575 | 1575 | ||
1576 | float hollow = this.hollow; | 1576 | float hollow = this.hollow; |
1577 | 1577 | ||
1578 | // sanity checks | 1578 | // sanity checks |
1579 | float initialProfileRot = 0.0f; | 1579 | float initialProfileRot = 0.0f; |
1580 | if (pathType == PathType.Circular) | 1580 | if (pathType == PathType.Circular) |
1581 | { | 1581 | { |
1582 | if (this.sides == 3) | 1582 | if (this.sides == 3) |
1583 | { | 1583 | { |
1584 | initialProfileRot = (float)Math.PI; | 1584 | initialProfileRot = (float)Math.PI; |
1585 | if (this.hollowSides == 4) | 1585 | if (this.hollowSides == 4) |
1586 | { | 1586 | { |
1587 | if (hollow > 0.7f) | 1587 | if (hollow > 0.7f) |
1588 | hollow = 0.7f; | 1588 | hollow = 0.7f; |
1589 | hollow *= 0.707f; | 1589 | hollow *= 0.707f; |
1590 | } | 1590 | } |
1591 | else hollow *= 0.5f; | 1591 | else hollow *= 0.5f; |
1592 | } | 1592 | } |
1593 | else if (this.sides == 4) | 1593 | else if (this.sides == 4) |
1594 | { | 1594 | { |
1595 | initialProfileRot = 0.25f * (float)Math.PI; | 1595 | initialProfileRot = 0.25f * (float)Math.PI; |
1596 | if (this.hollowSides != 4) | 1596 | if (this.hollowSides != 4) |
1597 | hollow *= 0.707f; | 1597 | hollow *= 0.707f; |
1598 | } | 1598 | } |
1599 | else if (this.sides > 4) | 1599 | else if (this.sides > 4) |
1600 | { | 1600 | { |
1601 | initialProfileRot = (float)Math.PI; | 1601 | initialProfileRot = (float)Math.PI; |
1602 | if (this.hollowSides == 4) | 1602 | if (this.hollowSides == 4) |
1603 | { | 1603 | { |
1604 | if (hollow > 0.7f) | 1604 | if (hollow > 0.7f) |
1605 | hollow = 0.7f; | 1605 | hollow = 0.7f; |
1606 | hollow /= 0.7f; | 1606 | hollow /= 0.7f; |
1607 | } | 1607 | } |
1608 | } | 1608 | } |
1609 | } | 1609 | } |
1610 | else | 1610 | else |
1611 | { | 1611 | { |
1612 | if (this.sides == 3) | 1612 | if (this.sides == 3) |
1613 | { | 1613 | { |
1614 | if (this.hollowSides == 4) | 1614 | if (this.hollowSides == 4) |
1615 | { | 1615 | { |
1616 | if (hollow > 0.7f) | 1616 | if (hollow > 0.7f) |
1617 | hollow = 0.7f; | 1617 | hollow = 0.7f; |
1618 | hollow *= 0.707f; | 1618 | hollow *= 0.707f; |
1619 | } | 1619 | } |
1620 | else hollow *= 0.5f; | 1620 | else hollow *= 0.5f; |
1621 | } | 1621 | } |
1622 | else if (this.sides == 4) | 1622 | else if (this.sides == 4) |
1623 | { | 1623 | { |
1624 | initialProfileRot = 1.25f * (float)Math.PI; | 1624 | initialProfileRot = 1.25f * (float)Math.PI; |
1625 | if (this.hollowSides != 4) | 1625 | if (this.hollowSides != 4) |
1626 | hollow *= 0.707f; | 1626 | hollow *= 0.707f; |
1627 | } | 1627 | } |
1628 | else if (this.sides == 24 && this.hollowSides == 4) | 1628 | else if (this.sides == 24 && this.hollowSides == 4) |
1629 | hollow *= 1.414f; | 1629 | hollow *= 1.414f; |
1630 | } | 1630 | } |
1631 | 1631 | ||
1632 | Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); | 1632 | Profile profile = new Profile(this.sides, this.profileStart, this.profileEnd, hollow, this.hollowSides, true, calcVertexNormals); |
1633 | this.errorMessage = profile.errorMessage; | 1633 | this.errorMessage = profile.errorMessage; |
1634 | 1634 | ||
1635 | this.numPrimFaces = profile.numPrimFaces; | 1635 | this.numPrimFaces = profile.numPrimFaces; |
1636 | 1636 | ||
1637 | int cut1Vert = -1; | 1637 | int cut1Vert = -1; |
1638 | int cut2Vert = -1; | 1638 | int cut2Vert = -1; |
1639 | if (hasProfileCut) | 1639 | if (hasProfileCut) |
1640 | { | 1640 | { |
1641 | cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; | 1641 | cut1Vert = hasHollow ? profile.coords.Count - 1 : 0; |
1642 | cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; | 1642 | cut2Vert = hasHollow ? profile.numOuterVerts - 1 : profile.numOuterVerts; |
1643 | } | 1643 | } |
1644 | 1644 | ||
1645 | if (initialProfileRot != 0.0f) | 1645 | if (initialProfileRot != 0.0f) |
1646 | { | 1646 | { |
1647 | profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); | 1647 | profile.AddRot(new Quat(new Coord(0.0f, 0.0f, 1.0f), initialProfileRot)); |
1648 | if (viewerMode) | 1648 | if (viewerMode) |
1649 | profile.MakeFaceUVs(); | 1649 | profile.MakeFaceUVs(); |
1650 | } | 1650 | } |
1651 | 1651 | ||
1652 | Coord lastCutNormal1 = new Coord(); | 1652 | Coord lastCutNormal1 = new Coord(); |
1653 | Coord lastCutNormal2 = new Coord(); | 1653 | Coord lastCutNormal2 = new Coord(); |
1654 | float lastV = 1.0f; | 1654 | float lastV = 1.0f; |
1655 | 1655 | ||
1656 | Path path = new Path(); | 1656 | Path path = new Path(); |
1657 | path.twistBegin = twistBegin; | 1657 | path.twistBegin = twistBegin; |
1658 | path.twistEnd = twistEnd; | 1658 | path.twistEnd = twistEnd; |
1659 | path.topShearX = topShearX; | 1659 | path.topShearX = topShearX; |
1660 | path.topShearY = topShearY; | 1660 | path.topShearY = topShearY; |
1661 | path.pathCutBegin = pathCutBegin; | 1661 | path.pathCutBegin = pathCutBegin; |
1662 | path.pathCutEnd = pathCutEnd; | 1662 | path.pathCutEnd = pathCutEnd; |
1663 | path.dimpleBegin = dimpleBegin; | 1663 | path.dimpleBegin = dimpleBegin; |
1664 | path.dimpleEnd = dimpleEnd; | 1664 | path.dimpleEnd = dimpleEnd; |
1665 | path.skew = skew; | 1665 | path.skew = skew; |
1666 | path.holeSizeX = holeSizeX; | 1666 | path.holeSizeX = holeSizeX; |
1667 | path.holeSizeY = holeSizeY; | 1667 | path.holeSizeY = holeSizeY; |
1668 | path.taperX = taperX; | 1668 | path.taperX = taperX; |
1669 | path.taperY = taperY; | 1669 | path.taperY = taperY; |
1670 | path.radius = radius; | 1670 | path.radius = radius; |
1671 | path.revolutions = revolutions; | 1671 | path.revolutions = revolutions; |
1672 | path.stepsPerRevolution = stepsPerRevolution; | 1672 | path.stepsPerRevolution = stepsPerRevolution; |
1673 | 1673 | ||
1674 | path.Create(pathType, steps); | 1674 | path.Create(pathType, steps); |
1675 | 1675 | ||
1676 | bool needEndFaces = false; | 1676 | bool needEndFaces = false; |
1677 | if (pathType == PathType.Circular) | 1677 | if (pathType == PathType.Circular) |
1678 | { | 1678 | { |
1679 | needEndFaces = false; | 1679 | needEndFaces = false; |
1680 | if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) | 1680 | if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) |
1681 | needEndFaces = true; | 1681 | needEndFaces = true; |
1682 | else if (this.taperX != 0.0f || this.taperY != 0.0f) | 1682 | else if (this.taperX != 0.0f || this.taperY != 0.0f) |
1683 | needEndFaces = true; | 1683 | needEndFaces = true; |
1684 | else if (this.skew != 0.0f) | 1684 | else if (this.skew != 0.0f) |
1685 | needEndFaces = true; | 1685 | needEndFaces = true; |
1686 | else if (twistTotal != 0.0f) | 1686 | else if (twistTotal != 0.0f) |
1687 | needEndFaces = true; | 1687 | needEndFaces = true; |
1688 | else if (this.radius != 0.0f) | 1688 | else if (this.radius != 0.0f) |
1689 | needEndFaces = true; | 1689 | needEndFaces = true; |
1690 | } | 1690 | } |
1691 | else needEndFaces = true; | 1691 | else needEndFaces = true; |
1692 | 1692 | ||
1693 | for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) | 1693 | for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) |
1694 | { | 1694 | { |
1695 | PathNode node = path.pathNodes[nodeIndex]; | 1695 | PathNode node = path.pathNodes[nodeIndex]; |
1696 | Profile newLayer = profile.Copy(); | 1696 | Profile newLayer = profile.Copy(); |
1697 | newLayer.Scale(node.xScale, node.yScale); | 1697 | newLayer.Scale(node.xScale, node.yScale); |
1698 | 1698 | ||
1699 | newLayer.AddRot(node.rotation); | 1699 | newLayer.AddRot(node.rotation); |
1700 | newLayer.AddPos(node.position); | 1700 | newLayer.AddPos(node.position); |
1701 | 1701 | ||
1702 | if (needEndFaces && nodeIndex == 0) | 1702 | if (needEndFaces && nodeIndex == 0) |
1703 | { | 1703 | { |
1704 | newLayer.FlipNormals(); | 1704 | newLayer.FlipNormals(); |
1705 | 1705 | ||
1706 | // add the top faces to the viewerFaces list here | 1706 | // add the top faces to the viewerFaces list here |
1707 | if (this.viewerMode) | 1707 | if (this.viewerMode) |
1708 | { | 1708 | { |
1709 | Coord faceNormal = newLayer.faceNormal; | 1709 | Coord faceNormal = newLayer.faceNormal; |
1710 | ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber); | 1710 | ViewerFace newViewerFace = new ViewerFace(profile.bottomFaceNumber); |
1711 | int numFaces = newLayer.faces.Count; | 1711 | int numFaces = newLayer.faces.Count; |
1712 | List<Face> faces = newLayer.faces; | 1712 | List<Face> faces = newLayer.faces; |
1713 | 1713 | ||
1714 | for (int i = 0; i < numFaces; i++) | 1714 | for (int i = 0; i < numFaces; i++) |
1715 | { | 1715 | { |
1716 | Face face = faces[i]; | 1716 | Face face = faces[i]; |
1717 | newViewerFace.v1 = newLayer.coords[face.v1]; | 1717 | newViewerFace.v1 = newLayer.coords[face.v1]; |
1718 | newViewerFace.v2 = newLayer.coords[face.v2]; | 1718 | newViewerFace.v2 = newLayer.coords[face.v2]; |
1719 | newViewerFace.v3 = newLayer.coords[face.v3]; | 1719 | newViewerFace.v3 = newLayer.coords[face.v3]; |
1720 | 1720 | ||
1721 | newViewerFace.coordIndex1 = face.v1; | 1721 | newViewerFace.coordIndex1 = face.v1; |
1722 | newViewerFace.coordIndex2 = face.v2; | 1722 | newViewerFace.coordIndex2 = face.v2; |
1723 | newViewerFace.coordIndex3 = face.v3; | 1723 | newViewerFace.coordIndex3 = face.v3; |
1724 | 1724 | ||
1725 | newViewerFace.n1 = faceNormal; | 1725 | newViewerFace.n1 = faceNormal; |
1726 | newViewerFace.n2 = faceNormal; | 1726 | newViewerFace.n2 = faceNormal; |
1727 | newViewerFace.n3 = faceNormal; | 1727 | newViewerFace.n3 = faceNormal; |
1728 | 1728 | ||
1729 | newViewerFace.uv1 = newLayer.faceUVs[face.v1]; | 1729 | newViewerFace.uv1 = newLayer.faceUVs[face.v1]; |
1730 | newViewerFace.uv2 = newLayer.faceUVs[face.v2]; | 1730 | newViewerFace.uv2 = newLayer.faceUVs[face.v2]; |
1731 | newViewerFace.uv3 = newLayer.faceUVs[face.v3]; | 1731 | newViewerFace.uv3 = newLayer.faceUVs[face.v3]; |
1732 | 1732 | ||
1733 | this.viewerFaces.Add(newViewerFace); | 1733 | this.viewerFaces.Add(newViewerFace); |
1734 | } | 1734 | } |
1735 | } | 1735 | } |
1736 | } // if (nodeIndex == 0) | 1736 | } // if (nodeIndex == 0) |
1737 | 1737 | ||
1738 | // append this layer | 1738 | // append this layer |
1739 | 1739 | ||
1740 | int coordsLen = this.coords.Count; | 1740 | int coordsLen = this.coords.Count; |
1741 | // int lastCoordsLen = coordsLen; | 1741 | newLayer.AddValue2FaceVertexIndices(coordsLen); |
1742 | newLayer.AddValue2FaceVertexIndices(coordsLen); | 1742 | |
1743 | 1743 | this.coords.AddRange(newLayer.coords); | |
1744 | this.coords.AddRange(newLayer.coords); | 1744 | |
1745 | 1745 | if (this.calcVertexNormals) | |
1746 | if (this.calcVertexNormals) | 1746 | { |
1747 | { | 1747 | newLayer.AddValue2FaceNormalIndices(this.normals.Count); |
1748 | newLayer.AddValue2FaceNormalIndices(this.normals.Count); | 1748 | this.normals.AddRange(newLayer.vertexNormals); |
1749 | this.normals.AddRange(newLayer.vertexNormals); | 1749 | } |
1750 | } | 1750 | |
1751 | 1751 | if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f) | |
1752 | if (node.percentOfPath < this.pathCutBegin + 0.01f || node.percentOfPath > this.pathCutEnd - 0.01f) | 1752 | this.faces.AddRange(newLayer.faces); |
1753 | this.faces.AddRange(newLayer.faces); | 1753 | |
1754 | 1754 | // fill faces between layers | |
1755 | // fill faces between layers | 1755 | |
1756 | 1756 | int numVerts = newLayer.coords.Count; | |
1757 | int numVerts = newLayer.coords.Count; | 1757 | Face newFace = new Face(); |
1758 | Face newFace = new Face(); | 1758 | |
1759 | 1759 | if (nodeIndex > 0) | |
1760 | if (nodeIndex > 0) | 1760 | { |
1761 | { | 1761 | int startVert = coordsLen + 1; |
1762 | int startVert = coordsLen + 1; | 1762 | int endVert = this.coords.Count; |
1763 | int endVert = this.coords.Count; | 1763 | |
1764 | 1764 | if (sides < 5 || this.hasProfileCut || hollow > 0.0f) | |
1765 | if (sides < 5 || this.hasProfileCut || hollow > 0.0f) | 1765 | startVert--; |
1766 | startVert--; | 1766 | |
1767 | 1767 | for (int i = startVert; i < endVert; i++) | |
1768 | for (int i = startVert; i < endVert; i++) | 1768 | { |
1769 | { | 1769 | int iNext = i + 1; |
1770 | int iNext = i + 1; | 1770 | if (i == endVert - 1) |
1771 | if (i == endVert - 1) | 1771 | iNext = startVert; |
1772 | iNext = startVert; | 1772 | |
1773 | 1773 | int whichVert = i - startVert; | |
1774 | int whichVert = i - startVert; | 1774 | |
1775 | 1775 | newFace.v1 = i; | |
1776 | newFace.v1 = i; | 1776 | newFace.v2 = i - numVerts; |
1777 | newFace.v2 = i - numVerts; | 1777 | newFace.v3 = iNext - numVerts; |
1778 | newFace.v3 = iNext - numVerts; | 1778 | this.faces.Add(newFace); |
1779 | this.faces.Add(newFace); | 1779 | |
1780 | 1780 | newFace.v2 = iNext - numVerts; | |
1781 | newFace.v2 = iNext - numVerts; | 1781 | newFace.v3 = iNext; |
1782 | newFace.v3 = iNext; | 1782 | this.faces.Add(newFace); |
1783 | this.faces.Add(newFace); | 1783 | |
1784 | 1784 | if (this.viewerMode) | |
1785 | if (this.viewerMode) | 1785 | { |
1786 | { | 1786 | // add the side faces to the list of viewerFaces here |
1787 | // add the side faces to the list of viewerFaces here | 1787 | |
1788 | 1788 | int primFaceNum = profile.faceNumbers[whichVert]; | |
1789 | int primFaceNum = profile.faceNumbers[whichVert]; | 1789 | if (!needEndFaces) |
1790 | if (!needEndFaces) | 1790 | primFaceNum -= 1; |
1791 | primFaceNum -= 1; | 1791 | |
1792 | 1792 | ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); | |
1793 | ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); | 1793 | ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); |
1794 | ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); | 1794 | |
1795 | 1795 | float u1 = newLayer.us[whichVert]; | |
1796 | float u1 = newLayer.us[whichVert]; | 1796 | float u2 = 1.0f; |
1797 | float u2 = 1.0f; | 1797 | if (whichVert < newLayer.us.Count - 1) |
1798 | if (whichVert < newLayer.us.Count - 1) | 1798 | u2 = newLayer.us[whichVert + 1]; |
1799 | u2 = newLayer.us[whichVert + 1]; | 1799 | |
1800 | 1800 | if (whichVert == cut1Vert || whichVert == cut2Vert) | |
1801 | if (whichVert == cut1Vert || whichVert == cut2Vert) | 1801 | { |
1802 | { | 1802 | u1 = 0.0f; |
1803 | u1 = 0.0f; | 1803 | u2 = 1.0f; |
1804 | u2 = 1.0f; | 1804 | } |
1805 | } | 1805 | else if (sides < 5) |
1806 | else if (sides < 5) | 1806 | { |
1807 | { | 1807 | if (whichVert < profile.numOuterVerts) |
1808 | if (whichVert < profile.numOuterVerts) | 1808 | { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled |
1809 | { // boxes and prisms have one texture face per side of the prim, so the U values have to be scaled | 1809 | // to reflect the entire texture width |
1810 | // to reflect the entire texture width | 1810 | u1 *= sides; |
1811 | u1 *= sides; | 1811 | u2 *= sides; |
1812 | u2 *= sides; | 1812 | u2 -= (int)u1; |
1813 | u2 -= (int)u1; | 1813 | u1 -= (int)u1; |
1814 | u1 -= (int)u1; | 1814 | if (u2 < 0.1f) |
1815 | if (u2 < 0.1f) | 1815 | u2 = 1.0f; |
1816 | u2 = 1.0f; | 1816 | } |
1817 | } | 1817 | else if (whichVert > profile.coords.Count - profile.numHollowVerts - 1) |
1818 | else if (whichVert > profile.coords.Count - profile.numHollowVerts - 1) | 1818 | { |
1819 | { | 1819 | u1 *= 2.0f; |
1820 | u1 *= 2.0f; | 1820 | u2 *= 2.0f; |
1821 | u2 *= 2.0f; | 1821 | } |
1822 | } | 1822 | } |
1823 | } | 1823 | |
1824 | 1824 | newViewerFace1.uv1.U = u1; | |
1825 | newViewerFace1.uv1.U = u1; | 1825 | newViewerFace1.uv2.U = u1; |
1826 | newViewerFace1.uv2.U = u1; | 1826 | newViewerFace1.uv3.U = u2; |
1827 | newViewerFace1.uv3.U = u2; | 1827 | |
1828 | 1828 | newViewerFace1.uv1.V = 1.0f - node.percentOfPath; | |
1829 | newViewerFace1.uv1.V = 1.0f - node.percentOfPath; | 1829 | newViewerFace1.uv2.V = lastV; |
1830 | newViewerFace1.uv2.V = lastV; | 1830 | newViewerFace1.uv3.V = lastV; |
1831 | newViewerFace1.uv3.V = lastV; | 1831 | |
1832 | 1832 | newViewerFace2.uv1.U = u1; | |
1833 | newViewerFace2.uv1.U = u1; | 1833 | newViewerFace2.uv2.U = u2; |
1834 | newViewerFace2.uv2.U = u2; | 1834 | newViewerFace2.uv3.U = u2; |
1835 | newViewerFace2.uv3.U = u2; | 1835 | |
1836 | 1836 | newViewerFace2.uv1.V = 1.0f - node.percentOfPath; | |
1837 | newViewerFace2.uv1.V = 1.0f - node.percentOfPath; | 1837 | newViewerFace2.uv2.V = lastV; |
1838 | newViewerFace2.uv2.V = lastV; | 1838 | newViewerFace2.uv3.V = 1.0f - node.percentOfPath; |
1839 | newViewerFace2.uv3.V = 1.0f - node.percentOfPath; | 1839 | |
1840 | 1840 | newViewerFace1.v1 = this.coords[i]; | |
1841 | newViewerFace1.v1 = this.coords[i]; | 1841 | newViewerFace1.v2 = this.coords[i - numVerts]; |
1842 | newViewerFace1.v2 = this.coords[i - numVerts]; | 1842 | newViewerFace1.v3 = this.coords[iNext - numVerts]; |
1843 | newViewerFace1.v3 = this.coords[iNext - numVerts]; | 1843 | |
1844 | 1844 | newViewerFace2.v1 = this.coords[i]; | |
1845 | newViewerFace2.v1 = this.coords[i]; | 1845 | newViewerFace2.v2 = this.coords[iNext - numVerts]; |
1846 | newViewerFace2.v2 = this.coords[iNext - numVerts]; | 1846 | newViewerFace2.v3 = this.coords[iNext]; |
1847 | newViewerFace2.v3 = this.coords[iNext]; | 1847 | |
1848 | 1848 | newViewerFace1.coordIndex1 = i; | |
1849 | newViewerFace1.coordIndex1 = i; | 1849 | newViewerFace1.coordIndex2 = i - numVerts; |
1850 | newViewerFace1.coordIndex2 = i - numVerts; | 1850 | newViewerFace1.coordIndex3 = iNext - numVerts; |
1851 | newViewerFace1.coordIndex3 = iNext - numVerts; | 1851 | |
1852 | 1852 | newViewerFace2.coordIndex1 = i; | |
1853 | newViewerFace2.coordIndex1 = i; | 1853 | newViewerFace2.coordIndex2 = iNext - numVerts; |
1854 | newViewerFace2.coordIndex2 = iNext - numVerts; | 1854 | newViewerFace2.coordIndex3 = iNext; |
1855 | newViewerFace2.coordIndex3 = iNext; | 1855 | |
1856 | 1856 | // profile cut faces | |
1857 | // profile cut faces | 1857 | if (whichVert == cut1Vert) |
1858 | if (whichVert == cut1Vert) | 1858 | { |
1859 | { | 1859 | newViewerFace1.n1 = newLayer.cutNormal1; |
1860 | newViewerFace1.n1 = newLayer.cutNormal1; | 1860 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; |
1861 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; | 1861 | |
1862 | 1862 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; | |
1863 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal1; | 1863 | newViewerFace2.n2 = lastCutNormal1; |
1864 | newViewerFace2.n2 = lastCutNormal1; | 1864 | } |
1865 | } | 1865 | else if (whichVert == cut2Vert) |
1866 | else if (whichVert == cut2Vert) | 1866 | { |
1867 | { | 1867 | newViewerFace1.n1 = newLayer.cutNormal2; |
1868 | newViewerFace1.n1 = newLayer.cutNormal2; | 1868 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; |
1869 | newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; | 1869 | |
1870 | 1870 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; | |
1871 | newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; | 1871 | newViewerFace2.n2 = lastCutNormal2; |
1872 | newViewerFace2.n2 = lastCutNormal2; | 1872 | } |
1873 | } | 1873 | |
1874 | 1874 | else // outer and hollow faces | |
1875 | else // outer and hollow faces | 1875 | { |
1876 | { | 1876 | if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) |
1877 | if ((sides < 5 && whichVert < newLayer.numOuterVerts) || (hollowSides < 5 && whichVert >= newLayer.numOuterVerts)) | 1877 | { // looks terrible when path is twisted... need vertex normals here |
1878 | { // looks terrible when path is twisted... need vertex normals here | 1878 | newViewerFace1.CalcSurfaceNormal(); |
1879 | newViewerFace1.CalcSurfaceNormal(); | 1879 | newViewerFace2.CalcSurfaceNormal(); |
1880 | newViewerFace2.CalcSurfaceNormal(); | 1880 | } |
1881 | } | 1881 | else |
1882 | else | 1882 | { |
1883 | { | 1883 | newViewerFace1.n1 = this.normals[i]; |
1884 | newViewerFace1.n1 = this.normals[i]; | 1884 | newViewerFace1.n2 = this.normals[i - numVerts]; |
1885 | newViewerFace1.n2 = this.normals[i - numVerts]; | 1885 | newViewerFace1.n3 = this.normals[iNext - numVerts]; |
1886 | newViewerFace1.n3 = this.normals[iNext - numVerts]; | 1886 | |
1887 | 1887 | newViewerFace2.n1 = this.normals[i]; | |
1888 | newViewerFace2.n1 = this.normals[i]; | 1888 | newViewerFace2.n2 = this.normals[iNext - numVerts]; |
1889 | newViewerFace2.n2 = this.normals[iNext - numVerts]; | 1889 | newViewerFace2.n3 = this.normals[iNext]; |
1890 | newViewerFace2.n3 = this.normals[iNext]; | 1890 | } |
1891 | } | 1891 | } |
1892 | } | 1892 | |
1893 | 1893 | this.viewerFaces.Add(newViewerFace1); | |
1894 | this.viewerFaces.Add(newViewerFace1); | 1894 | this.viewerFaces.Add(newViewerFace2); |
1895 | this.viewerFaces.Add(newViewerFace2); | 1895 | |
1896 | 1896 | } | |
1897 | } | 1897 | } |
1898 | } | 1898 | } |
1899 | } | 1899 | |
1900 | 1900 | lastCutNormal1 = newLayer.cutNormal1; | |
1901 | lastCutNormal1 = newLayer.cutNormal1; | 1901 | lastCutNormal2 = newLayer.cutNormal2; |
1902 | lastCutNormal2 = newLayer.cutNormal2; | 1902 | lastV = 1.0f - node.percentOfPath; |
1903 | lastV = 1.0f - node.percentOfPath; | 1903 | |
1904 | 1904 | if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode) | |
1905 | if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode) | 1905 | { |
1906 | { | 1906 | // add the top faces to the viewerFaces list here |
1907 | // add the top faces to the viewerFaces list here | 1907 | Coord faceNormal = newLayer.faceNormal; |
1908 | Coord faceNormal = newLayer.faceNormal; | 1908 | ViewerFace newViewerFace = new ViewerFace(); |
1909 | ViewerFace newViewerFace = new ViewerFace(); | 1909 | newViewerFace.primFaceNumber = 0; |
1910 | newViewerFace.primFaceNumber = 0; | 1910 | int numFaces = newLayer.faces.Count; |
1911 | int numFaces = newLayer.faces.Count; | 1911 | List<Face> faces = newLayer.faces; |
1912 | List<Face> faces = newLayer.faces; | 1912 | |
1913 | 1913 | for (int i = 0; i < numFaces; i++) | |
1914 | for (int i = 0; i < numFaces; i++) | 1914 | { |
1915 | { | 1915 | Face face = faces[i]; |
1916 | Face face = faces[i]; | 1916 | newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; |
1917 | newViewerFace.v1 = newLayer.coords[face.v1 - coordsLen]; | 1917 | newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; |
1918 | newViewerFace.v2 = newLayer.coords[face.v2 - coordsLen]; | 1918 | newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; |
1919 | newViewerFace.v3 = newLayer.coords[face.v3 - coordsLen]; | 1919 | |
1920 | 1920 | newViewerFace.coordIndex1 = face.v1 - coordsLen; | |
1921 | newViewerFace.coordIndex1 = face.v1 - coordsLen; | 1921 | newViewerFace.coordIndex2 = face.v2 - coordsLen; |
1922 | newViewerFace.coordIndex2 = face.v2 - coordsLen; | 1922 | newViewerFace.coordIndex3 = face.v3 - coordsLen; |
1923 | newViewerFace.coordIndex3 = face.v3 - coordsLen; | 1923 | |
1924 | 1924 | newViewerFace.n1 = faceNormal; | |
1925 | newViewerFace.n1 = faceNormal; | 1925 | newViewerFace.n2 = faceNormal; |
1926 | newViewerFace.n2 = faceNormal; | 1926 | newViewerFace.n3 = faceNormal; |
1927 | newViewerFace.n3 = faceNormal; | 1927 | |
1928 | 1928 | newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; | |
1929 | newViewerFace.uv1 = newLayer.faceUVs[face.v1 - coordsLen]; | 1929 | newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; |
1930 | newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; | 1930 | newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; |
1931 | newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; | 1931 | |
1932 | 1932 | this.viewerFaces.Add(newViewerFace); | |
1933 | this.viewerFaces.Add(newViewerFace); | 1933 | } |
1934 | } | 1934 | } |
1935 | } | 1935 | |
1936 | 1936 | ||
1937 | 1937 | } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) | |
1938 | } // for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) | 1938 | |
1939 | 1939 | } | |
1940 | } | 1940 | |
1941 | 1941 | ||
1942 | 1942 | /// <summary> | |
1943 | /// <summary> | 1943 | /// DEPRICATED - use Extrude(PathType.Linear) instead |
1944 | /// DEPRICATED - use Extrude(PathType.Linear) instead | 1944 | /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. |
1945 | /// Extrudes a profile along a straight line path. Used for prim types box, cylinder, and prism. | 1945 | /// </summary> |
1946 | /// </summary> | 1946 | /// |
1947 | /// | 1947 | public void ExtrudeLinear() |
1948 | public void ExtrudeLinear() | 1948 | { |
1949 | { | 1949 | this.Extrude(PathType.Linear); |
1950 | this.Extrude(PathType.Linear); | 1950 | } |
1951 | } | 1951 | |
1952 | 1952 | ||
1953 | 1953 | /// <summary> | |
1954 | /// <summary> | 1954 | /// DEPRICATED - use Extrude(PathType.Circular) instead |
1955 | /// DEPRICATED - use Extrude(PathType.Circular) instead | 1955 | /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. |
1956 | /// Extrude a profile into a circular path prim mesh. Used for prim types torus, tube, and ring. | 1956 | /// </summary> |
1957 | /// </summary> | 1957 | /// |
1958 | /// | 1958 | public void ExtrudeCircular() |
1959 | public void ExtrudeCircular() | 1959 | { |
1960 | { | 1960 | this.Extrude(PathType.Circular); |
1961 | this.Extrude(PathType.Circular); | 1961 | } |
1962 | } | 1962 | |
1963 | 1963 | ||
1964 | 1964 | private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) | |
1965 | private Coord SurfaceNormal(Coord c1, Coord c2, Coord c3) | 1965 | { |
1966 | { | 1966 | Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); |
1967 | Coord edge1 = new Coord(c2.X - c1.X, c2.Y - c1.Y, c2.Z - c1.Z); | 1967 | Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); |
1968 | Coord edge2 = new Coord(c3.X - c1.X, c3.Y - c1.Y, c3.Z - c1.Z); | 1968 | |
1969 | 1969 | Coord normal = Coord.Cross(edge1, edge2); | |
1970 | Coord normal = Coord.Cross(edge1, edge2); | 1970 | |
1971 | 1971 | normal.Normalize(); | |
1972 | normal.Normalize(); | 1972 | |
1973 | 1973 | return normal; | |
1974 | return normal; | 1974 | } |
1975 | } | 1975 | |
1976 | 1976 | private Coord SurfaceNormal(Face face) | |
1977 | private Coord SurfaceNormal(Face face) | 1977 | { |
1978 | { | 1978 | return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]); |
1979 | return SurfaceNormal(this.coords[face.v1], this.coords[face.v2], this.coords[face.v3]); | 1979 | } |
1980 | } | 1980 | |
1981 | 1981 | /// <summary> | |
1982 | /// <summary> | 1982 | /// Calculate the surface normal for a face in the list of faces |
1983 | /// Calculate the surface normal for a face in the list of faces | 1983 | /// </summary> |
1984 | /// </summary> | 1984 | /// <param name="faceIndex"></param> |
1985 | /// <param name="faceIndex"></param> | 1985 | /// <returns></returns> |
1986 | /// <returns></returns> | 1986 | public Coord SurfaceNormal(int faceIndex) |
1987 | public Coord SurfaceNormal(int faceIndex) | 1987 | { |
1988 | { | 1988 | int numFaces = this.faces.Count; |
1989 | int numFaces = this.faces.Count; | 1989 | if (faceIndex < 0 || faceIndex >= numFaces) |
1990 | if (faceIndex < 0 || faceIndex >= numFaces) | 1990 | throw new Exception("faceIndex out of range"); |
1991 | throw new Exception("faceIndex out of range"); | 1991 | |
1992 | 1992 | return SurfaceNormal(this.faces[faceIndex]); | |
1993 | return SurfaceNormal(this.faces[faceIndex]); | 1993 | } |
1994 | } | 1994 | |
1995 | 1995 | /// <summary> | |
1996 | /// <summary> | 1996 | /// Duplicates a PrimMesh object. All object properties are copied by value, including lists. |
1997 | /// Duplicates a PrimMesh object. All object properties are copied by value, including lists. | 1997 | /// </summary> |
1998 | /// </summary> | 1998 | /// <returns></returns> |
1999 | /// <returns></returns> | 1999 | public PrimMesh Copy() |
2000 | public PrimMesh Copy() | 2000 | { |
2001 | { | 2001 | PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides); |
2002 | PrimMesh copy = new PrimMesh(this.sides, this.profileStart, this.profileEnd, this.hollow, this.hollowSides); | 2002 | copy.twistBegin = this.twistBegin; |
2003 | copy.twistBegin = this.twistBegin; | 2003 | copy.twistEnd = this.twistEnd; |
2004 | copy.twistEnd = this.twistEnd; | 2004 | copy.topShearX = this.topShearX; |
2005 | copy.topShearX = this.topShearX; | 2005 | copy.topShearY = this.topShearY; |
2006 | copy.topShearY = this.topShearY; | 2006 | copy.pathCutBegin = this.pathCutBegin; |
2007 | copy.pathCutBegin = this.pathCutBegin; | 2007 | copy.pathCutEnd = this.pathCutEnd; |
2008 | copy.pathCutEnd = this.pathCutEnd; | 2008 | copy.dimpleBegin = this.dimpleBegin; |
2009 | copy.dimpleBegin = this.dimpleBegin; | 2009 | copy.dimpleEnd = this.dimpleEnd; |
2010 | copy.dimpleEnd = this.dimpleEnd; | 2010 | copy.skew = this.skew; |
2011 | copy.skew = this.skew; | 2011 | copy.holeSizeX = this.holeSizeX; |
2012 | copy.holeSizeX = this.holeSizeX; | 2012 | copy.holeSizeY = this.holeSizeY; |
2013 | copy.holeSizeY = this.holeSizeY; | 2013 | copy.taperX = this.taperX; |
2014 | copy.taperX = this.taperX; | 2014 | copy.taperY = this.taperY; |
2015 | copy.taperY = this.taperY; | 2015 | copy.radius = this.radius; |
2016 | copy.radius = this.radius; | 2016 | copy.revolutions = this.revolutions; |
2017 | copy.revolutions = this.revolutions; | 2017 | copy.stepsPerRevolution = this.stepsPerRevolution; |
2018 | copy.stepsPerRevolution = this.stepsPerRevolution; | 2018 | copy.calcVertexNormals = this.calcVertexNormals; |
2019 | copy.calcVertexNormals = this.calcVertexNormals; | 2019 | copy.normalsProcessed = this.normalsProcessed; |
2020 | copy.normalsProcessed = this.normalsProcessed; | 2020 | copy.viewerMode = this.viewerMode; |
2021 | copy.viewerMode = this.viewerMode; | 2021 | copy.numPrimFaces = this.numPrimFaces; |
2022 | copy.numPrimFaces = this.numPrimFaces; | 2022 | copy.errorMessage = this.errorMessage; |
2023 | copy.errorMessage = this.errorMessage; | 2023 | |
2024 | 2024 | copy.coords = new List<Coord>(this.coords); | |
2025 | copy.coords = new List<Coord>(this.coords); | 2025 | copy.faces = new List<Face>(this.faces); |
2026 | copy.faces = new List<Face>(this.faces); | 2026 | copy.viewerFaces = new List<ViewerFace>(this.viewerFaces); |
2027 | copy.viewerFaces = new List<ViewerFace>(this.viewerFaces); | 2027 | copy.normals = new List<Coord>(this.normals); |
2028 | copy.normals = new List<Coord>(this.normals); | 2028 | |
2029 | 2029 | return copy; | |
2030 | return copy; | 2030 | } |
2031 | } | 2031 | |
2032 | 2032 | /// <summary> | |
2033 | /// <summary> | 2033 | /// Calculate surface normals for all of the faces in the list of faces in this mesh |
2034 | /// Calculate surface normals for all of the faces in the list of faces in this mesh | 2034 | /// </summary> |
2035 | /// </summary> | 2035 | public void CalcNormals() |
2036 | public void CalcNormals() | 2036 | { |
2037 | { | 2037 | if (normalsProcessed) |
2038 | if (normalsProcessed) | 2038 | return; |
2039 | return; | 2039 | |
2040 | 2040 | normalsProcessed = true; | |
2041 | normalsProcessed = true; | 2041 | |
2042 | 2042 | int numFaces = faces.Count; | |
2043 | int numFaces = faces.Count; | 2043 | |
2044 | 2044 | if (!this.calcVertexNormals) | |
2045 | if (!this.calcVertexNormals) | 2045 | this.normals = new List<Coord>(); |
2046 | this.normals = new List<Coord>(); | 2046 | |
2047 | 2047 | for (int i = 0; i < numFaces; i++) | |
2048 | for (int i = 0; i < numFaces; i++) | 2048 | { |
2049 | { | 2049 | Face face = faces[i]; |
2050 | Face face = faces[i]; | 2050 | |
2051 | 2051 | this.normals.Add(SurfaceNormal(i).Normalize()); | |
2052 | this.normals.Add(SurfaceNormal(i).Normalize()); | 2052 | |
2053 | 2053 | int normIndex = normals.Count - 1; | |
2054 | int normIndex = normals.Count - 1; | 2054 | face.n1 = normIndex; |
2055 | face.n1 = normIndex; | 2055 | face.n2 = normIndex; |
2056 | face.n2 = normIndex; | 2056 | face.n3 = normIndex; |
2057 | face.n3 = normIndex; | 2057 | |
2058 | 2058 | this.faces[i] = face; | |
2059 | this.faces[i] = face; | 2059 | } |
2060 | } | 2060 | } |
2061 | } | 2061 | |
2062 | 2062 | /// <summary> | |
2063 | /// <summary> | 2063 | /// Adds a value to each XYZ vertex coordinate in the mesh |
2064 | /// Adds a value to each XYZ vertex coordinate in the mesh | 2064 | /// </summary> |
2065 | /// </summary> | 2065 | /// <param name="x"></param> |
2066 | /// <param name="x"></param> | 2066 | /// <param name="y"></param> |
2067 | /// <param name="y"></param> | 2067 | /// <param name="z"></param> |
2068 | /// <param name="z"></param> | 2068 | public void AddPos(float x, float y, float z) |
2069 | public void AddPos(float x, float y, float z) | 2069 | { |
2070 | { | 2070 | int i; |
2071 | int i; | 2071 | int numVerts = this.coords.Count; |
2072 | int numVerts = this.coords.Count; | 2072 | Coord vert; |
2073 | Coord vert; | 2073 | |
2074 | 2074 | for (i = 0; i < numVerts; i++) | |
2075 | for (i = 0; i < numVerts; i++) | 2075 | { |
2076 | { | 2076 | vert = this.coords[i]; |
2077 | vert = this.coords[i]; | 2077 | vert.X += x; |
2078 | vert.X += x; | 2078 | vert.Y += y; |
2079 | vert.Y += y; | 2079 | vert.Z += z; |
2080 | vert.Z += z; | 2080 | this.coords[i] = vert; |
2081 | this.coords[i] = vert; | 2081 | } |
2082 | } | 2082 | |
2083 | 2083 | if (this.viewerFaces != null) | |
2084 | if (this.viewerFaces != null) | 2084 | { |
2085 | { | 2085 | int numViewerFaces = this.viewerFaces.Count; |
2086 | int numViewerFaces = this.viewerFaces.Count; | 2086 | |
2087 | 2087 | for (i = 0; i < numViewerFaces; i++) | |
2088 | for (i = 0; i < numViewerFaces; i++) | 2088 | { |
2089 | { | 2089 | ViewerFace v = this.viewerFaces[i]; |
2090 | ViewerFace v = this.viewerFaces[i]; | 2090 | v.AddPos(x, y, z); |
2091 | v.AddPos(x, y, z); | 2091 | this.viewerFaces[i] = v; |
2092 | this.viewerFaces[i] = v; | 2092 | } |
2093 | } | 2093 | } |
2094 | } | 2094 | } |
2095 | } | 2095 | |
2096 | 2096 | /// <summary> | |
2097 | /// <summary> | 2097 | /// Rotates the mesh |
2098 | /// Rotates the mesh | 2098 | /// </summary> |
2099 | /// </summary> | 2099 | /// <param name="q"></param> |
2100 | /// <param name="q"></param> | 2100 | public void AddRot(Quat q) |
2101 | public void AddRot(Quat q) | 2101 | { |
2102 | { | 2102 | int i; |
2103 | int i; | 2103 | int numVerts = this.coords.Count; |
2104 | int numVerts = this.coords.Count; | 2104 | |
2105 | 2105 | for (i = 0; i < numVerts; i++) | |
2106 | for (i = 0; i < numVerts; i++) | 2106 | this.coords[i] *= q; |
2107 | this.coords[i] *= q; | 2107 | |
2108 | 2108 | if (this.normals != null) | |
2109 | if (this.normals != null) | 2109 | { |
2110 | { | 2110 | int numNormals = this.normals.Count; |
2111 | int numNormals = this.normals.Count; | 2111 | for (i = 0; i < numNormals; i++) |
2112 | for (i = 0; i < numNormals; i++) | 2112 | this.normals[i] *= q; |
2113 | this.normals[i] *= q; | 2113 | } |
2114 | } | 2114 | |
2115 | 2115 | if (this.viewerFaces != null) | |
2116 | if (this.viewerFaces != null) | 2116 | { |
2117 | { | 2117 | int numViewerFaces = this.viewerFaces.Count; |
2118 | int numViewerFaces = this.viewerFaces.Count; | 2118 | |
2119 | 2119 | for (i = 0; i < numViewerFaces; i++) | |
2120 | for (i = 0; i < numViewerFaces; i++) | 2120 | { |
2121 | { | 2121 | ViewerFace v = this.viewerFaces[i]; |
2122 | ViewerFace v = this.viewerFaces[i]; | 2122 | v.v1 *= q; |
2123 | v.v1 *= q; | 2123 | v.v2 *= q; |
2124 | v.v2 *= q; | 2124 | v.v3 *= q; |
2125 | v.v3 *= q; | 2125 | |
2126 | 2126 | v.n1 *= q; | |
2127 | v.n1 *= q; | 2127 | v.n2 *= q; |
2128 | v.n2 *= q; | 2128 | v.n3 *= q; |
2129 | v.n3 *= q; | 2129 | this.viewerFaces[i] = v; |
2130 | this.viewerFaces[i] = v; | 2130 | } |
2131 | } | 2131 | } |
2132 | } | 2132 | } |
2133 | } | 2133 | |
2134 | 2134 | #if VERTEX_INDEXER | |
2135 | #if VERTEX_INDEXER | 2135 | public VertexIndexer GetVertexIndexer() |
2136 | public VertexIndexer GetVertexIndexer() | 2136 | { |
2137 | { | 2137 | if (this.viewerMode && this.viewerFaces.Count > 0) |
2138 | if (this.viewerMode && this.viewerFaces.Count > 0) | 2138 | return new VertexIndexer(this); |
2139 | return new VertexIndexer(this); | 2139 | return null; |
2140 | return null; | 2140 | } |
2141 | } | 2141 | #endif |
2142 | #endif | 2142 | |
2143 | 2143 | /// <summary> | |
2144 | /// <summary> | 2144 | /// Scales the mesh |
2145 | /// Scales the mesh | 2145 | /// </summary> |
2146 | /// </summary> | 2146 | /// <param name="x"></param> |
2147 | /// <param name="x"></param> | 2147 | /// <param name="y"></param> |
2148 | /// <param name="y"></param> | 2148 | /// <param name="z"></param> |
2149 | /// <param name="z"></param> | 2149 | public void Scale(float x, float y, float z) |
2150 | public void Scale(float x, float y, float z) | 2150 | { |
2151 | { | 2151 | int i; |
2152 | int i; | 2152 | int numVerts = this.coords.Count; |
2153 | int numVerts = this.coords.Count; | 2153 | //Coord vert; |
2154 | //Coord vert; | 2154 | |
2155 | 2155 | Coord m = new Coord(x, y, z); | |
2156 | Coord m = new Coord(x, y, z); | 2156 | for (i = 0; i < numVerts; i++) |
2157 | for (i = 0; i < numVerts; i++) | 2157 | this.coords[i] *= m; |
2158 | this.coords[i] *= m; | 2158 | |
2159 | 2159 | if (this.viewerFaces != null) | |
2160 | if (this.viewerFaces != null) | 2160 | { |
2161 | { | 2161 | int numViewerFaces = this.viewerFaces.Count; |
2162 | int numViewerFaces = this.viewerFaces.Count; | 2162 | for (i = 0; i < numViewerFaces; i++) |
2163 | for (i = 0; i < numViewerFaces; i++) | 2163 | { |
2164 | { | 2164 | ViewerFace v = this.viewerFaces[i]; |
2165 | ViewerFace v = this.viewerFaces[i]; | 2165 | v.v1 *= m; |
2166 | v.v1 *= m; | 2166 | v.v2 *= m; |
2167 | v.v2 *= m; | 2167 | v.v3 *= m; |
2168 | v.v3 *= m; | 2168 | this.viewerFaces[i] = v; |
2169 | this.viewerFaces[i] = v; | 2169 | } |
2170 | } | 2170 | |
2171 | 2171 | } | |
2172 | } | 2172 | |
2173 | 2173 | } | |
2174 | } | 2174 | |
2175 | 2175 | /// <summary> | |
2176 | /// <summary> | 2176 | /// Dumps the mesh to a Blender compatible "Raw" format file |
2177 | /// Dumps the mesh to a Blender compatible "Raw" format file | 2177 | /// </summary> |
2178 | /// </summary> | 2178 | /// <param name="path"></param> |
2179 | /// <param name="path"></param> | 2179 | /// <param name="name"></param> |
2180 | /// <param name="name"></param> | 2180 | /// <param name="title"></param> |
2181 | /// <param name="title"></param> | 2181 | public void DumpRaw(String path, String name, String title) |
2182 | public void DumpRaw(String path, String name, String title) | 2182 | { |
2183 | { | 2183 | if (path == null) |
2184 | if (path == null) | 2184 | return; |
2185 | return; | 2185 | String fileName = name + "_" + title + ".raw"; |
2186 | String fileName = name + "_" + title + ".raw"; | 2186 | String completePath = System.IO.Path.Combine(path, fileName); |
2187 | String completePath = System.IO.Path.Combine(path, fileName); | 2187 | StreamWriter sw = new StreamWriter(completePath); |
2188 | StreamWriter sw = new StreamWriter(completePath); | 2188 | |
2189 | 2189 | for (int i = 0; i < this.faces.Count; i++) | |
2190 | for (int i = 0; i < this.faces.Count; i++) | 2190 | { |
2191 | { | 2191 | string s = this.coords[this.faces[i].v1].ToString(); |
2192 | string s = this.coords[this.faces[i].v1].ToString(); | 2192 | s += " " + this.coords[this.faces[i].v2].ToString(); |
2193 | s += " " + this.coords[this.faces[i].v2].ToString(); | 2193 | s += " " + this.coords[this.faces[i].v3].ToString(); |
2194 | s += " " + this.coords[this.faces[i].v3].ToString(); | 2194 | |
2195 | 2195 | sw.WriteLine(s); | |
2196 | sw.WriteLine(s); | 2196 | } |
2197 | } | 2197 | |
2198 | 2198 | sw.Close(); | |
2199 | sw.Close(); | 2199 | } |
2200 | } | 2200 | } |
2201 | } | 2201 | } |
2202 | } | ||
diff --git a/OpenSim/Region/Physics/Meshing/SculptMesh.cs b/OpenSim/Region/Physics/Meshing/SculptMesh.cs index 4dc6e2e..11b6cd4 100644 --- a/OpenSim/Region/Physics/Meshing/SculptMesh.cs +++ b/OpenSim/Region/Physics/Meshing/SculptMesh.cs | |||
@@ -1,627 +1,645 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors | 2 | * Copyright (c) Contributors |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSimulator Project nor the | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | // to build without references to System.Drawing, comment this out | 28 | // to build without references to System.Drawing, comment this out |
29 | #define SYSTEM_DRAWING | 29 | #define SYSTEM_DRAWING |
30 | 30 | ||
31 | using System; | 31 | using System; |
32 | using System.Collections.Generic; | 32 | using System.Collections.Generic; |
33 | using System.Text; | 33 | using System.Text; |
34 | using System.IO; | 34 | using System.IO; |
35 | 35 | ||
36 | #if SYSTEM_DRAWING | 36 | #if SYSTEM_DRAWING |
37 | using System.Drawing; | 37 | using System.Drawing; |
38 | using System.Drawing.Imaging; | 38 | using System.Drawing.Imaging; |
39 | #endif | 39 | #endif |
40 | 40 | ||
41 | namespace PrimMesher | 41 | namespace PrimMesher |
42 | { | 42 | { |
43 | 43 | ||
44 | public class SculptMesh | 44 | public class SculptMesh |
45 | { | 45 | { |
46 | public List<Coord> coords; | 46 | public List<Coord> coords; |
47 | public List<Face> faces; | 47 | public List<Face> faces; |
48 | 48 | ||
49 | public List<ViewerFace> viewerFaces; | 49 | public List<ViewerFace> viewerFaces; |
50 | public List<Coord> normals; | 50 | public List<Coord> normals; |
51 | public List<UVCoord> uvs; | 51 | public List<UVCoord> uvs; |
52 | 52 | ||
53 | public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 }; | 53 | public enum SculptType { sphere = 1, torus = 2, plane = 3, cylinder = 4 }; |
54 | 54 | ||
55 | #if SYSTEM_DRAWING | 55 | #if SYSTEM_DRAWING |
56 | // private Bitmap ScaleImage(Bitmap srcImage, float scale) | 56 | private Bitmap ScaleImage(Bitmap srcImage, float scale, bool removeAlpha) |
57 | // { | 57 | { |
58 | // int sourceWidth = srcImage.Width; | 58 | int sourceWidth = srcImage.Width; |
59 | // int sourceHeight = srcImage.Height; | 59 | int sourceHeight = srcImage.Height; |
60 | // int sourceX = 0; | 60 | int sourceX = 0; |
61 | // int sourceY = 0; | 61 | int sourceY = 0; |
62 | 62 | ||
63 | // int destX = 0; | 63 | int destX = 0; |
64 | // int destY = 0; | 64 | int destY = 0; |
65 | // int destWidth = (int)(srcImage.Width * scale); | 65 | int destWidth = (int)(srcImage.Width * scale); |
66 | // int destHeight = (int)(srcImage.Height * scale); | 66 | int destHeight = (int)(srcImage.Height * scale); |
67 | 67 | ||
68 | // if (srcImage.PixelFormat == PixelFormat.Format32bppArgb) | 68 | Bitmap scaledImage; |
69 | // for (int y = 0; y < srcImage.Height; y++) | 69 | |
70 | // for (int x = 0; x < srcImage.Width; x++) | 70 | if (removeAlpha) |
71 | // { | 71 | { |
72 | // Color c = srcImage.GetPixel(x, y); | 72 | if (srcImage.PixelFormat == PixelFormat.Format32bppArgb) |
73 | // srcImage.SetPixel(x, y, Color.FromArgb(255, c.R, c.G, c.B)); | 73 | for (int y = 0; y < srcImage.Height; y++) |
74 | // } | 74 | for (int x = 0; x < srcImage.Width; x++) |
75 | 75 | { | |
76 | // Bitmap scaledImage = new Bitmap(destWidth, destHeight, | 76 | Color c = srcImage.GetPixel(x, y); |
77 | // PixelFormat.Format24bppRgb); | 77 | srcImage.SetPixel(x, y, Color.FromArgb(255, c.R, c.G, c.B)); |
78 | 78 | } | |
79 | // scaledImage.SetResolution(96.0f, 96.0f); | 79 | |
80 | 80 | scaledImage = new Bitmap(destWidth, destHeight, | |
81 | // Graphics grPhoto = Graphics.FromImage(scaledImage); | 81 | PixelFormat.Format24bppRgb); |
82 | // grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low; | 82 | } |
83 | 83 | else | |
84 | // grPhoto.DrawImage(srcImage, | 84 | scaledImage = new Bitmap(srcImage, destWidth, destHeight); |
85 | // new Rectangle(destX, destY, destWidth, destHeight), | 85 | |
86 | // new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), | 86 | scaledImage.SetResolution(96.0f, 96.0f); |
87 | // GraphicsUnit.Pixel); | 87 | |
88 | 88 | Graphics grPhoto = Graphics.FromImage(scaledImage); | |
89 | // grPhoto.Dispose(); | 89 | grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low; |
90 | // return scaledImage; | 90 | |
91 | // } | 91 | grPhoto.DrawImage(srcImage, |
92 | 92 | new Rectangle(destX, destY, destWidth, destHeight), | |
93 | 93 | new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), | |
94 | public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) | 94 | GraphicsUnit.Pixel); |
95 | { | 95 | |
96 | Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); | 96 | grPhoto.Dispose(); |
97 | SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); | 97 | return scaledImage; |
98 | bitmap.Dispose(); | 98 | } |
99 | return sculptMesh; | 99 | |
100 | } | 100 | |
101 | 101 | public SculptMesh SculptMeshFromFile(string fileName, SculptType sculptType, int lod, bool viewerMode) | |
102 | public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) | 102 | { |
103 | { | 103 | Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); |
104 | Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); | 104 | SculptMesh sculptMesh = new SculptMesh(bitmap, sculptType, lod, viewerMode); |
105 | _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); | 105 | bitmap.Dispose(); |
106 | bitmap.Dispose(); | 106 | return sculptMesh; |
107 | } | 107 | } |
108 | #endif | 108 | |
109 | 109 | public SculptMesh(string fileName, int sculptType, int lod, int viewerMode, int mirror, int invert) | |
110 | /// <summary> | 110 | { |
111 | /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications | 111 | Bitmap bitmap = (Bitmap)Bitmap.FromFile(fileName); |
112 | /// Construct a sculpt mesh from a 2D array of floats | 112 | _SculptMesh(bitmap, (SculptType)sculptType, lod, viewerMode != 0, mirror != 0, invert != 0); |
113 | /// </summary> | 113 | bitmap.Dispose(); |
114 | /// <param name="zMap"></param> | 114 | } |
115 | /// <param name="xBegin"></param> | 115 | #endif |
116 | /// <param name="xEnd"></param> | 116 | |
117 | /// <param name="yBegin"></param> | 117 | /// <summary> |
118 | /// <param name="yEnd"></param> | 118 | /// ** Experimental ** May disappear from future versions ** not recommeneded for use in applications |
119 | /// <param name="viewerMode"></param> | 119 | /// Construct a sculpt mesh from a 2D array of floats |
120 | public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode) | 120 | /// </summary> |
121 | { | 121 | /// <param name="zMap"></param> |
122 | float xStep, yStep; | 122 | /// <param name="xBegin"></param> |
123 | float uStep, vStep; | 123 | /// <param name="xEnd"></param> |
124 | 124 | /// <param name="yBegin"></param> | |
125 | int numYElements = zMap.GetLength(0); | 125 | /// <param name="yEnd"></param> |
126 | int numXElements = zMap.GetLength(1); | 126 | /// <param name="viewerMode"></param> |
127 | 127 | public SculptMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd, bool viewerMode) | |
128 | try | 128 | { |
129 | { | 129 | float xStep, yStep; |
130 | xStep = (xEnd - xBegin) / (float)(numXElements - 1); | 130 | float uStep, vStep; |
131 | yStep = (yEnd - yBegin) / (float)(numYElements - 1); | 131 | |
132 | 132 | int numYElements = zMap.GetLength(0); | |
133 | uStep = 1.0f / (numXElements - 1); | 133 | int numXElements = zMap.GetLength(1); |
134 | vStep = 1.0f / (numYElements - 1); | 134 | |
135 | } | 135 | try |
136 | catch (DivideByZeroException) | 136 | { |
137 | { | 137 | xStep = (xEnd - xBegin) / (float)(numXElements - 1); |
138 | return; | 138 | yStep = (yEnd - yBegin) / (float)(numYElements - 1); |
139 | } | 139 | |
140 | 140 | uStep = 1.0f / (numXElements - 1); | |
141 | coords = new List<Coord>(); | 141 | vStep = 1.0f / (numYElements - 1); |
142 | faces = new List<Face>(); | 142 | } |
143 | normals = new List<Coord>(); | 143 | catch (DivideByZeroException) |
144 | uvs = new List<UVCoord>(); | 144 | { |
145 | 145 | return; | |
146 | viewerFaces = new List<ViewerFace>(); | 146 | } |
147 | 147 | ||
148 | int p1, p2, p3, p4; | 148 | coords = new List<Coord>(); |
149 | 149 | faces = new List<Face>(); | |
150 | int x, y; | 150 | normals = new List<Coord>(); |
151 | int xStart = 0, yStart = 0; | 151 | uvs = new List<UVCoord>(); |
152 | 152 | ||
153 | for (y = yStart; y < numYElements; y++) | 153 | viewerFaces = new List<ViewerFace>(); |
154 | { | 154 | |
155 | int rowOffset = y * numXElements; | 155 | int p1, p2, p3, p4; |
156 | 156 | ||
157 | for (x = xStart; x < numXElements; x++) | 157 | int x, y; |
158 | { | 158 | int xStart = 0, yStart = 0; |
159 | /* | 159 | |
160 | * p1-----p2 | 160 | for (y = yStart; y < numYElements; y++) |
161 | * | \ f2 | | 161 | { |
162 | * | \ | | 162 | int rowOffset = y * numXElements; |
163 | * | f1 \| | 163 | |
164 | * p3-----p4 | 164 | for (x = xStart; x < numXElements; x++) |
165 | */ | 165 | { |
166 | 166 | /* | |
167 | p4 = rowOffset + x; | 167 | * p1-----p2 |
168 | p3 = p4 - 1; | 168 | * | \ f2 | |
169 | 169 | * | \ | | |
170 | p2 = p4 - numXElements; | 170 | * | f1 \| |
171 | p1 = p3 - numXElements; | 171 | * p3-----p4 |
172 | 172 | */ | |
173 | Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]); | 173 | |
174 | this.coords.Add(c); | 174 | p4 = rowOffset + x; |
175 | if (viewerMode) | 175 | p3 = p4 - 1; |
176 | { | 176 | |
177 | this.normals.Add(new Coord()); | 177 | p2 = p4 - numXElements; |
178 | this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y)); | 178 | p1 = p3 - numXElements; |
179 | } | 179 | |
180 | 180 | Coord c = new Coord(xBegin + x * xStep, yBegin + y * yStep, zMap[y, x]); | |
181 | if (y > 0 && x > 0) | 181 | this.coords.Add(c); |
182 | { | 182 | if (viewerMode) |
183 | Face f1, f2; | 183 | { |
184 | 184 | this.normals.Add(new Coord()); | |
185 | if (viewerMode) | 185 | this.uvs.Add(new UVCoord(uStep * x, 1.0f - vStep * y)); |
186 | { | 186 | } |
187 | f1 = new Face(p1, p4, p3, p1, p4, p3); | 187 | |
188 | f1.uv1 = p1; | 188 | if (y > 0 && x > 0) |
189 | f1.uv2 = p4; | 189 | { |
190 | f1.uv3 = p3; | 190 | Face f1, f2; |
191 | 191 | ||
192 | f2 = new Face(p1, p2, p4, p1, p2, p4); | 192 | if (viewerMode) |
193 | f2.uv1 = p1; | 193 | { |
194 | f2.uv2 = p2; | 194 | f1 = new Face(p1, p4, p3, p1, p4, p3); |
195 | f2.uv3 = p4; | 195 | f1.uv1 = p1; |
196 | } | 196 | f1.uv2 = p4; |
197 | else | 197 | f1.uv3 = p3; |
198 | { | 198 | |
199 | f1 = new Face(p1, p4, p3); | 199 | f2 = new Face(p1, p2, p4, p1, p2, p4); |
200 | f2 = new Face(p1, p2, p4); | 200 | f2.uv1 = p1; |
201 | } | 201 | f2.uv2 = p2; |
202 | 202 | f2.uv3 = p4; | |
203 | this.faces.Add(f1); | 203 | } |
204 | this.faces.Add(f2); | 204 | else |
205 | } | 205 | { |
206 | } | 206 | f1 = new Face(p1, p4, p3); |
207 | } | 207 | f2 = new Face(p1, p2, p4); |
208 | 208 | } | |
209 | if (viewerMode) | 209 | |
210 | calcVertexNormals(SculptType.plane, numXElements, numYElements); | 210 | this.faces.Add(f1); |
211 | } | 211 | this.faces.Add(f2); |
212 | 212 | } | |
213 | #if SYSTEM_DRAWING | 213 | } |
214 | public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) | 214 | } |
215 | { | 215 | |
216 | _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); | 216 | if (viewerMode) |
217 | } | 217 | calcVertexNormals(SculptType.plane, numXElements, numYElements); |
218 | 218 | } | |
219 | public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) | 219 | |
220 | { | 220 | #if SYSTEM_DRAWING |
221 | _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); | 221 | public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode) |
222 | } | 222 | { |
223 | #endif | 223 | _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, false, false); |
224 | 224 | } | |
225 | public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) | 225 | |
226 | { | 226 | public SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) |
227 | _SculptMesh(rows, sculptType, viewerMode, mirror, invert); | 227 | { |
228 | } | 228 | _SculptMesh(sculptBitmap, sculptType, lod, viewerMode, mirror, invert); |
229 | 229 | } | |
230 | #if SYSTEM_DRAWING | 230 | #endif |
231 | /// <summary> | 231 | |
232 | /// converts a bitmap to a list of lists of coords, while scaling the image. | 232 | public SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) |
233 | /// the scaling is done in floating point so as to allow for reduced vertex position | 233 | { |
234 | /// quantization as the position will be averaged between pixel values. this routine will | 234 | _SculptMesh(rows, sculptType, viewerMode, mirror, invert); |
235 | /// likely fail if the bitmap width and height are not powers of 2. | 235 | } |
236 | /// </summary> | 236 | |
237 | /// <param name="bitmap"></param> | 237 | #if SYSTEM_DRAWING |
238 | /// <param name="scale"></param> | 238 | /// <summary> |
239 | /// <param name="mirror"></param> | 239 | /// converts a bitmap to a list of lists of coords, while scaling the image. |
240 | /// <returns></returns> | 240 | /// the scaling is done in floating point so as to allow for reduced vertex position |
241 | private List<List<Coord>> bitmap2Coords(Bitmap bitmap, int scale, bool mirror) | 241 | /// quantization as the position will be averaged between pixel values. this routine will |
242 | { | 242 | /// likely fail if the bitmap width and height are not powers of 2. |
243 | int numRows = bitmap.Height / scale; | 243 | /// </summary> |
244 | int numCols = bitmap.Width / scale; | 244 | /// <param name="bitmap"></param> |
245 | List<List<Coord>> rows = new List<List<Coord>>(numRows); | 245 | /// <param name="scale"></param> |
246 | 246 | /// <param name="mirror"></param> | |
247 | float pixScale = 1.0f / (scale * scale); | 247 | /// <returns></returns> |
248 | pixScale /= 255; | 248 | private List<List<Coord>> bitmap2Coords(Bitmap bitmap, int scale, bool mirror) |
249 | 249 | { | |
250 | int imageX, imageY = 0; | 250 | int numRows = bitmap.Height / scale; |
251 | 251 | int numCols = bitmap.Width / scale; | |
252 | int rowNdx, colNdx; | 252 | List<List<Coord>> rows = new List<List<Coord>>(numRows); |
253 | 253 | ||
254 | for (rowNdx = 0; rowNdx < numRows; rowNdx++) | 254 | float pixScale = 1.0f / (scale * scale); |
255 | { | 255 | pixScale /= 255; |
256 | List<Coord> row = new List<Coord>(numCols); | 256 | |
257 | for (colNdx = 0; colNdx < numCols; colNdx++) | 257 | int imageX, imageY = 0; |
258 | { | 258 | |
259 | imageX = colNdx * scale; | 259 | int rowNdx, colNdx; |
260 | int imageYStart = rowNdx * scale; | 260 | |
261 | int imageYEnd = imageYStart + scale; | 261 | for (rowNdx = 0; rowNdx < numRows; rowNdx++) |
262 | int imageXEnd = imageX + scale; | 262 | { |
263 | float rSum = 0.0f; | 263 | List<Coord> row = new List<Coord>(numCols); |
264 | float gSum = 0.0f; | 264 | for (colNdx = 0; colNdx < numCols; colNdx++) |
265 | float bSum = 0.0f; | 265 | { |
266 | for (; imageX < imageXEnd; imageX++) | 266 | imageX = colNdx * scale; |
267 | { | 267 | int imageYStart = rowNdx * scale; |
268 | for (imageY = imageYStart; imageY < imageYEnd; imageY++) | 268 | int imageYEnd = imageYStart + scale; |
269 | { | 269 | int imageXEnd = imageX + scale; |
270 | Color c = bitmap.GetPixel(imageX, imageY); | 270 | float rSum = 0.0f; |
271 | rSum += c.R; | 271 | float gSum = 0.0f; |
272 | gSum += c.G; | 272 | float bSum = 0.0f; |
273 | bSum += c.B; | 273 | for (; imageX < imageXEnd; imageX++) |
274 | } | 274 | { |
275 | } | 275 | for (imageY = imageYStart; imageY < imageYEnd; imageY++) |
276 | if (mirror) | 276 | { |
277 | row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); | 277 | Color c = bitmap.GetPixel(imageX, imageY); |
278 | else | 278 | if (c.A != 255) |
279 | row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); | 279 | { |
280 | 280 | bitmap.SetPixel(imageX, imageY, Color.FromArgb(255, c.R, c.G, c.B)); | |
281 | } | 281 | c = bitmap.GetPixel(imageX, imageY); |
282 | rows.Add(row); | 282 | } |
283 | } | 283 | rSum += c.R; |
284 | return rows; | 284 | gSum += c.G; |
285 | } | 285 | bSum += c.B; |
286 | 286 | } | |
287 | 287 | } | |
288 | void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) | 288 | if (mirror) |
289 | { | 289 | row.Add(new Coord(-(rSum * pixScale - 0.5f), gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); |
290 | coords = new List<Coord>(); | 290 | else |
291 | faces = new List<Face>(); | 291 | row.Add(new Coord(rSum * pixScale - 0.5f, gSum * pixScale - 0.5f, bSum * pixScale - 0.5f)); |
292 | normals = new List<Coord>(); | 292 | |
293 | uvs = new List<UVCoord>(); | 293 | } |
294 | 294 | rows.Add(row); | |
295 | sculptType = (SculptType)(((int)sculptType) & 0x07); | 295 | } |
296 | 296 | return rows; | |
297 | if (mirror) | 297 | } |
298 | if (sculptType == SculptType.plane) | 298 | |
299 | invert = !invert; | 299 | |
300 | 300 | void _SculptMesh(Bitmap sculptBitmap, SculptType sculptType, int lod, bool viewerMode, bool mirror, bool invert) | |
301 | float sourceScaleFactor = (float)(lod) / (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); | 301 | { |
302 | 302 | coords = new List<Coord>(); | |
303 | int scale = (int)(1.0f / sourceScaleFactor); | 303 | faces = new List<Face>(); |
304 | if (scale < 1) scale = 1; | 304 | normals = new List<Coord>(); |
305 | 305 | uvs = new List<UVCoord>(); | |
306 | _SculptMesh(bitmap2Coords(sculptBitmap, scale, mirror), sculptType, viewerMode, mirror, invert); | 306 | |
307 | } | 307 | sculptType = (SculptType)(((int)sculptType) & 0x07); |
308 | #endif | 308 | |
309 | 309 | if (mirror) | |
310 | 310 | if (sculptType == SculptType.plane) | |
311 | void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) | 311 | invert = !invert; |
312 | { | 312 | |
313 | coords = new List<Coord>(); | 313 | float sculptBitmapLod = (float)Math.Sqrt(sculptBitmap.Width * sculptBitmap.Height); |
314 | faces = new List<Face>(); | 314 | |
315 | normals = new List<Coord>(); | 315 | float sourceScaleFactor = (float)(lod) / sculptBitmapLod; |
316 | uvs = new List<UVCoord>(); | 316 | |
317 | 317 | float fScale = 1.0f / sourceScaleFactor; | |
318 | sculptType = (SculptType)(((int)sculptType) & 0x07); | 318 | |
319 | 319 | int iScale = (int)fScale; | |
320 | if (mirror) | 320 | if (iScale < 1) iScale = 1; |
321 | if (sculptType == SculptType.plane) | 321 | if (iScale > 2 && iScale % 2 == 0) |
322 | invert = !invert; | 322 | _SculptMesh(bitmap2Coords(ScaleImage(sculptBitmap, 64.0f / sculptBitmapLod, true), 64 / lod, mirror), sculptType, viewerMode, mirror, invert); |
323 | 323 | else | |
324 | viewerFaces = new List<ViewerFace>(); | 324 | _SculptMesh(bitmap2Coords(sculptBitmap, iScale, mirror), sculptType, viewerMode, mirror, invert); |
325 | 325 | } | |
326 | int width = rows[0].Count; | 326 | #endif |
327 | 327 | ||
328 | int p1, p2, p3, p4; | 328 | |
329 | 329 | void _SculptMesh(List<List<Coord>> rows, SculptType sculptType, bool viewerMode, bool mirror, bool invert) | |
330 | int imageX, imageY; | 330 | { |
331 | 331 | coords = new List<Coord>(); | |
332 | if (sculptType != SculptType.plane) | 332 | faces = new List<Face>(); |
333 | { | 333 | normals = new List<Coord>(); |
334 | for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) | 334 | uvs = new List<UVCoord>(); |
335 | rows[rowNdx].Add(rows[rowNdx][0]); | 335 | |
336 | } | 336 | sculptType = (SculptType)(((int)sculptType) & 0x07); |
337 | 337 | ||
338 | Coord topPole = rows[0][width / 2]; | 338 | if (mirror) |
339 | Coord bottomPole = rows[rows.Count - 1][width / 2]; | 339 | if (sculptType == SculptType.plane) |
340 | 340 | invert = !invert; | |
341 | if (sculptType == SculptType.sphere) | 341 | |
342 | { | 342 | viewerFaces = new List<ViewerFace>(); |
343 | int count = rows[0].Count; | 343 | |
344 | List<Coord> topPoleRow = new List<Coord>(count); | 344 | int width = rows[0].Count; |
345 | List<Coord> bottomPoleRow = new List<Coord>(count); | 345 | |
346 | 346 | int p1, p2, p3, p4; | |
347 | for (int i = 0; i < count; i++) | 347 | |
348 | { | 348 | int imageX, imageY; |
349 | topPoleRow.Add(topPole); | 349 | |
350 | bottomPoleRow.Add(bottomPole); | 350 | if (sculptType != SculptType.plane) |
351 | } | 351 | { |
352 | rows.Insert(0, topPoleRow); | 352 | for (int rowNdx = 0; rowNdx < rows.Count; rowNdx++) |
353 | rows.Add(bottomPoleRow); | 353 | rows[rowNdx].Add(rows[rowNdx][0]); |
354 | } | 354 | } |
355 | else if (sculptType == SculptType.torus) | 355 | |
356 | rows.Add(rows[0]); | 356 | Coord topPole = rows[0][width / 2]; |
357 | 357 | Coord bottomPole = rows[rows.Count - 1][width / 2]; | |
358 | int coordsDown = rows.Count; | 358 | |
359 | int coordsAcross = rows[0].Count; | 359 | if (sculptType == SculptType.sphere) |
360 | 360 | { | |
361 | float widthUnit = 1.0f / (coordsAcross - 1); | 361 | int count = rows[0].Count; |
362 | float heightUnit = 1.0f / (coordsDown - 1); | 362 | List<Coord> topPoleRow = new List<Coord>(count); |
363 | 363 | List<Coord> bottomPoleRow = new List<Coord>(count); | |
364 | for (imageY = 0; imageY < coordsDown; imageY++) | 364 | |
365 | { | 365 | for (int i = 0; i < count; i++) |
366 | int rowOffset = imageY * coordsAcross; | 366 | { |
367 | 367 | topPoleRow.Add(topPole); | |
368 | for (imageX = 0; imageX < coordsAcross; imageX++) | 368 | bottomPoleRow.Add(bottomPole); |
369 | { | 369 | } |
370 | /* | 370 | rows.Insert(0, topPoleRow); |
371 | * p1-----p2 | 371 | rows.Add(bottomPoleRow); |
372 | * | \ f2 | | 372 | } |
373 | * | \ | | 373 | else if (sculptType == SculptType.torus) |
374 | * | f1 \| | 374 | rows.Add(rows[0]); |
375 | * p3-----p4 | 375 | |
376 | */ | 376 | int coordsDown = rows.Count; |
377 | 377 | int coordsAcross = rows[0].Count; | |
378 | p4 = rowOffset + imageX; | 378 | |
379 | p3 = p4 - 1; | 379 | float widthUnit = 1.0f / (coordsAcross - 1); |
380 | 380 | float heightUnit = 1.0f / (coordsDown - 1); | |
381 | p2 = p4 - coordsAcross; | 381 | |
382 | p1 = p3 - coordsAcross; | 382 | for (imageY = 0; imageY < coordsDown; imageY++) |
383 | 383 | { | |
384 | this.coords.Add(rows[imageY][imageX]); | 384 | int rowOffset = imageY * coordsAcross; |
385 | if (viewerMode) | 385 | |
386 | { | 386 | for (imageX = 0; imageX < coordsAcross; imageX++) |
387 | this.normals.Add(new Coord()); | 387 | { |
388 | this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); | 388 | /* |
389 | } | 389 | * p1-----p2 |
390 | 390 | * | \ f2 | | |
391 | if (imageY > 0 && imageX > 0) | 391 | * | \ | |
392 | { | 392 | * | f1 \| |
393 | Face f1, f2; | 393 | * p3-----p4 |
394 | 394 | */ | |
395 | if (viewerMode) | 395 | |
396 | { | 396 | p4 = rowOffset + imageX; |
397 | if (invert) | 397 | p3 = p4 - 1; |
398 | { | 398 | |
399 | f1 = new Face(p1, p4, p3, p1, p4, p3); | 399 | p2 = p4 - coordsAcross; |
400 | f1.uv1 = p1; | 400 | p1 = p3 - coordsAcross; |
401 | f1.uv2 = p4; | 401 | |
402 | f1.uv3 = p3; | 402 | this.coords.Add(rows[imageY][imageX]); |
403 | 403 | if (viewerMode) | |
404 | f2 = new Face(p1, p2, p4, p1, p2, p4); | 404 | { |
405 | f2.uv1 = p1; | 405 | this.normals.Add(new Coord()); |
406 | f2.uv2 = p2; | 406 | this.uvs.Add(new UVCoord(widthUnit * imageX, heightUnit * imageY)); |
407 | f2.uv3 = p4; | 407 | } |
408 | } | 408 | |
409 | else | 409 | if (imageY > 0 && imageX > 0) |
410 | { | 410 | { |
411 | f1 = new Face(p1, p3, p4, p1, p3, p4); | 411 | Face f1, f2; |
412 | f1.uv1 = p1; | 412 | |
413 | f1.uv2 = p3; | 413 | if (viewerMode) |
414 | f1.uv3 = p4; | 414 | { |
415 | 415 | if (invert) | |
416 | f2 = new Face(p1, p4, p2, p1, p4, p2); | 416 | { |
417 | f2.uv1 = p1; | 417 | f1 = new Face(p1, p4, p3, p1, p4, p3); |
418 | f2.uv2 = p4; | 418 | f1.uv1 = p1; |
419 | f2.uv3 = p2; | 419 | f1.uv2 = p4; |
420 | } | 420 | f1.uv3 = p3; |
421 | } | 421 | |
422 | else | 422 | f2 = new Face(p1, p2, p4, p1, p2, p4); |
423 | { | 423 | f2.uv1 = p1; |
424 | if (invert) | 424 | f2.uv2 = p2; |
425 | { | 425 | f2.uv3 = p4; |
426 | f1 = new Face(p1, p4, p3); | 426 | } |
427 | f2 = new Face(p1, p2, p4); | 427 | else |
428 | } | 428 | { |
429 | else | 429 | f1 = new Face(p1, p3, p4, p1, p3, p4); |
430 | { | 430 | f1.uv1 = p1; |
431 | f1 = new Face(p1, p3, p4); | 431 | f1.uv2 = p3; |
432 | f2 = new Face(p1, p4, p2); | 432 | f1.uv3 = p4; |
433 | } | 433 | |
434 | } | 434 | f2 = new Face(p1, p4, p2, p1, p4, p2); |
435 | 435 | f2.uv1 = p1; | |
436 | this.faces.Add(f1); | 436 | f2.uv2 = p4; |
437 | this.faces.Add(f2); | 437 | f2.uv3 = p2; |
438 | } | 438 | } |
439 | } | 439 | } |
440 | } | 440 | else |
441 | 441 | { | |
442 | if (viewerMode) | 442 | if (invert) |
443 | calcVertexNormals(sculptType, coordsAcross, coordsDown); | 443 | { |
444 | } | 444 | f1 = new Face(p1, p4, p3); |
445 | 445 | f2 = new Face(p1, p2, p4); | |
446 | /// <summary> | 446 | } |
447 | /// Duplicates a SculptMesh object. All object properties are copied by value, including lists. | 447 | else |
448 | /// </summary> | 448 | { |
449 | /// <returns></returns> | 449 | f1 = new Face(p1, p3, p4); |
450 | public SculptMesh Copy() | 450 | f2 = new Face(p1, p4, p2); |
451 | { | 451 | } |
452 | return new SculptMesh(this); | 452 | } |
453 | } | 453 | |
454 | 454 | this.faces.Add(f1); | |
455 | public SculptMesh(SculptMesh sm) | 455 | this.faces.Add(f2); |
456 | { | 456 | } |
457 | coords = new List<Coord>(sm.coords); | 457 | } |
458 | faces = new List<Face>(sm.faces); | 458 | } |
459 | viewerFaces = new List<ViewerFace>(sm.viewerFaces); | 459 | |
460 | normals = new List<Coord>(sm.normals); | 460 | if (viewerMode) |
461 | uvs = new List<UVCoord>(sm.uvs); | 461 | calcVertexNormals(sculptType, coordsAcross, coordsDown); |
462 | } | 462 | } |
463 | 463 | ||
464 | private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) | 464 | /// <summary> |
465 | { // compute vertex normals by summing all the surface normals of all the triangles sharing | 465 | /// Duplicates a SculptMesh object. All object properties are copied by value, including lists. |
466 | // each vertex and then normalizing | 466 | /// </summary> |
467 | int numFaces = this.faces.Count; | 467 | /// <returns></returns> |
468 | for (int i = 0; i < numFaces; i++) | 468 | public SculptMesh Copy() |
469 | { | 469 | { |
470 | Face face = this.faces[i]; | 470 | return new SculptMesh(this); |
471 | Coord surfaceNormal = face.SurfaceNormal(this.coords); | 471 | } |
472 | this.normals[face.n1] += surfaceNormal; | 472 | |
473 | this.normals[face.n2] += surfaceNormal; | 473 | public SculptMesh(SculptMesh sm) |
474 | this.normals[face.n3] += surfaceNormal; | 474 | { |
475 | } | 475 | coords = new List<Coord>(sm.coords); |
476 | 476 | faces = new List<Face>(sm.faces); | |
477 | int numNormals = this.normals.Count; | 477 | viewerFaces = new List<ViewerFace>(sm.viewerFaces); |
478 | for (int i = 0; i < numNormals; i++) | 478 | normals = new List<Coord>(sm.normals); |
479 | this.normals[i] = this.normals[i].Normalize(); | 479 | uvs = new List<UVCoord>(sm.uvs); |
480 | 480 | } | |
481 | if (sculptType != SculptType.plane) | 481 | |
482 | { // blend the vertex normals at the cylinder seam | 482 | private void calcVertexNormals(SculptType sculptType, int xSize, int ySize) |
483 | for (int y = 0; y < ySize; y++) | 483 | { // compute vertex normals by summing all the surface normals of all the triangles sharing |
484 | { | 484 | // each vertex and then normalizing |
485 | int rowOffset = y * xSize; | 485 | int numFaces = this.faces.Count; |
486 | 486 | for (int i = 0; i < numFaces; i++) | |
487 | this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); | 487 | { |
488 | } | 488 | Face face = this.faces[i]; |
489 | } | 489 | Coord surfaceNormal = face.SurfaceNormal(this.coords); |
490 | 490 | this.normals[face.n1] += surfaceNormal; | |
491 | foreach (Face face in this.faces) | 491 | this.normals[face.n2] += surfaceNormal; |
492 | { | 492 | this.normals[face.n3] += surfaceNormal; |
493 | ViewerFace vf = new ViewerFace(0); | 493 | } |
494 | vf.v1 = this.coords[face.v1]; | 494 | |
495 | vf.v2 = this.coords[face.v2]; | 495 | int numNormals = this.normals.Count; |
496 | vf.v3 = this.coords[face.v3]; | 496 | for (int i = 0; i < numNormals; i++) |
497 | 497 | this.normals[i] = this.normals[i].Normalize(); | |
498 | vf.coordIndex1 = face.v1; | 498 | |
499 | vf.coordIndex2 = face.v2; | 499 | if (sculptType != SculptType.plane) |
500 | vf.coordIndex3 = face.v3; | 500 | { // blend the vertex normals at the cylinder seam |
501 | 501 | for (int y = 0; y < ySize; y++) | |
502 | vf.n1 = this.normals[face.n1]; | 502 | { |
503 | vf.n2 = this.normals[face.n2]; | 503 | int rowOffset = y * xSize; |
504 | vf.n3 = this.normals[face.n3]; | 504 | |
505 | 505 | this.normals[rowOffset] = this.normals[rowOffset + xSize - 1] = (this.normals[rowOffset] + this.normals[rowOffset + xSize - 1]).Normalize(); | |
506 | vf.uv1 = this.uvs[face.uv1]; | 506 | } |
507 | vf.uv2 = this.uvs[face.uv2]; | 507 | } |
508 | vf.uv3 = this.uvs[face.uv3]; | 508 | |
509 | 509 | foreach (Face face in this.faces) | |
510 | this.viewerFaces.Add(vf); | 510 | { |
511 | } | 511 | ViewerFace vf = new ViewerFace(0); |
512 | } | 512 | vf.v1 = this.coords[face.v1]; |
513 | 513 | vf.v2 = this.coords[face.v2]; | |
514 | /// <summary> | 514 | vf.v3 = this.coords[face.v3]; |
515 | /// Adds a value to each XYZ vertex coordinate in the mesh | 515 | |
516 | /// </summary> | 516 | vf.coordIndex1 = face.v1; |
517 | /// <param name="x"></param> | 517 | vf.coordIndex2 = face.v2; |
518 | /// <param name="y"></param> | 518 | vf.coordIndex3 = face.v3; |
519 | /// <param name="z"></param> | 519 | |
520 | public void AddPos(float x, float y, float z) | 520 | vf.n1 = this.normals[face.n1]; |
521 | { | 521 | vf.n2 = this.normals[face.n2]; |
522 | int i; | 522 | vf.n3 = this.normals[face.n3]; |
523 | int numVerts = this.coords.Count; | 523 | |
524 | Coord vert; | 524 | vf.uv1 = this.uvs[face.uv1]; |
525 | 525 | vf.uv2 = this.uvs[face.uv2]; | |
526 | for (i = 0; i < numVerts; i++) | 526 | vf.uv3 = this.uvs[face.uv3]; |
527 | { | 527 | |
528 | vert = this.coords[i]; | 528 | this.viewerFaces.Add(vf); |
529 | vert.X += x; | 529 | } |
530 | vert.Y += y; | 530 | } |
531 | vert.Z += z; | 531 | |
532 | this.coords[i] = vert; | 532 | /// <summary> |
533 | } | 533 | /// Adds a value to each XYZ vertex coordinate in the mesh |
534 | 534 | /// </summary> | |
535 | if (this.viewerFaces != null) | 535 | /// <param name="x"></param> |
536 | { | 536 | /// <param name="y"></param> |
537 | int numViewerFaces = this.viewerFaces.Count; | 537 | /// <param name="z"></param> |
538 | 538 | public void AddPos(float x, float y, float z) | |
539 | for (i = 0; i < numViewerFaces; i++) | 539 | { |
540 | { | 540 | int i; |
541 | ViewerFace v = this.viewerFaces[i]; | 541 | int numVerts = this.coords.Count; |
542 | v.AddPos(x, y, z); | 542 | Coord vert; |
543 | this.viewerFaces[i] = v; | 543 | |
544 | } | 544 | for (i = 0; i < numVerts; i++) |
545 | } | 545 | { |
546 | } | 546 | vert = this.coords[i]; |
547 | 547 | vert.X += x; | |
548 | /// <summary> | 548 | vert.Y += y; |
549 | /// Rotates the mesh | 549 | vert.Z += z; |
550 | /// </summary> | 550 | this.coords[i] = vert; |
551 | /// <param name="q"></param> | 551 | } |
552 | public void AddRot(Quat q) | 552 | |
553 | { | 553 | if (this.viewerFaces != null) |
554 | int i; | 554 | { |
555 | int numVerts = this.coords.Count; | 555 | int numViewerFaces = this.viewerFaces.Count; |
556 | 556 | ||
557 | for (i = 0; i < numVerts; i++) | 557 | for (i = 0; i < numViewerFaces; i++) |
558 | this.coords[i] *= q; | 558 | { |
559 | 559 | ViewerFace v = this.viewerFaces[i]; | |
560 | int numNormals = this.normals.Count; | 560 | v.AddPos(x, y, z); |
561 | for (i = 0; i < numNormals; i++) | 561 | this.viewerFaces[i] = v; |
562 | this.normals[i] *= q; | 562 | } |
563 | 563 | } | |
564 | if (this.viewerFaces != null) | 564 | } |
565 | { | 565 | |
566 | int numViewerFaces = this.viewerFaces.Count; | 566 | /// <summary> |
567 | 567 | /// Rotates the mesh | |
568 | for (i = 0; i < numViewerFaces; i++) | 568 | /// </summary> |
569 | { | 569 | /// <param name="q"></param> |
570 | ViewerFace v = this.viewerFaces[i]; | 570 | public void AddRot(Quat q) |
571 | v.v1 *= q; | 571 | { |
572 | v.v2 *= q; | 572 | int i; |
573 | v.v3 *= q; | 573 | int numVerts = this.coords.Count; |
574 | 574 | ||
575 | v.n1 *= q; | 575 | for (i = 0; i < numVerts; i++) |
576 | v.n2 *= q; | 576 | this.coords[i] *= q; |
577 | v.n3 *= q; | 577 | |
578 | 578 | int numNormals = this.normals.Count; | |
579 | this.viewerFaces[i] = v; | 579 | for (i = 0; i < numNormals; i++) |
580 | } | 580 | this.normals[i] *= q; |
581 | } | 581 | |
582 | } | 582 | if (this.viewerFaces != null) |
583 | 583 | { | |
584 | public void Scale(float x, float y, float z) | 584 | int numViewerFaces = this.viewerFaces.Count; |
585 | { | 585 | |
586 | int i; | 586 | for (i = 0; i < numViewerFaces; i++) |
587 | int numVerts = this.coords.Count; | 587 | { |
588 | 588 | ViewerFace v = this.viewerFaces[i]; | |
589 | Coord m = new Coord(x, y, z); | 589 | v.v1 *= q; |
590 | for (i = 0; i < numVerts; i++) | 590 | v.v2 *= q; |
591 | this.coords[i] *= m; | 591 | v.v3 *= q; |
592 | 592 | ||
593 | if (this.viewerFaces != null) | 593 | v.n1 *= q; |
594 | { | 594 | v.n2 *= q; |
595 | int numViewerFaces = this.viewerFaces.Count; | 595 | v.n3 *= q; |
596 | for (i = 0; i < numViewerFaces; i++) | 596 | |
597 | { | 597 | this.viewerFaces[i] = v; |
598 | ViewerFace v = this.viewerFaces[i]; | 598 | } |
599 | v.v1 *= m; | 599 | } |
600 | v.v2 *= m; | 600 | } |
601 | v.v3 *= m; | 601 | |
602 | this.viewerFaces[i] = v; | 602 | public void Scale(float x, float y, float z) |
603 | } | 603 | { |
604 | } | 604 | int i; |
605 | } | 605 | int numVerts = this.coords.Count; |
606 | 606 | ||
607 | public void DumpRaw(String path, String name, String title) | 607 | Coord m = new Coord(x, y, z); |
608 | { | 608 | for (i = 0; i < numVerts; i++) |
609 | if (path == null) | 609 | this.coords[i] *= m; |
610 | return; | 610 | |
611 | String fileName = name + "_" + title + ".raw"; | 611 | if (this.viewerFaces != null) |
612 | String completePath = System.IO.Path.Combine(path, fileName); | 612 | { |
613 | StreamWriter sw = new StreamWriter(completePath); | 613 | int numViewerFaces = this.viewerFaces.Count; |
614 | 614 | for (i = 0; i < numViewerFaces; i++) | |
615 | for (int i = 0; i < this.faces.Count; i++) | 615 | { |
616 | { | 616 | ViewerFace v = this.viewerFaces[i]; |
617 | string s = this.coords[this.faces[i].v1].ToString(); | 617 | v.v1 *= m; |
618 | s += " " + this.coords[this.faces[i].v2].ToString(); | 618 | v.v2 *= m; |
619 | s += " " + this.coords[this.faces[i].v3].ToString(); | 619 | v.v3 *= m; |
620 | 620 | this.viewerFaces[i] = v; | |
621 | sw.WriteLine(s); | 621 | } |
622 | } | 622 | } |
623 | 623 | } | |
624 | sw.Close(); | 624 | |
625 | } | 625 | public void DumpRaw(String path, String name, String title) |
626 | } | 626 | { |
627 | } | 627 | if (path == null) |
628 | return; | ||
629 | String fileName = name + "_" + title + ".raw"; | ||
630 | String completePath = System.IO.Path.Combine(path, fileName); | ||
631 | StreamWriter sw = new StreamWriter(completePath); | ||
632 | |||
633 | for (int i = 0; i < this.faces.Count; i++) | ||
634 | { | ||
635 | string s = this.coords[this.faces[i].v1].ToString(); | ||
636 | s += " " + this.coords[this.faces[i].v2].ToString(); | ||
637 | s += " " + this.coords[this.faces[i].v3].ToString(); | ||
638 | |||
639 | sw.WriteLine(s); | ||
640 | } | ||
641 | |||
642 | sw.Close(); | ||
643 | } | ||
644 | } | ||
645 | } | ||
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 2ab00a3..be7c348 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -1575,11 +1575,11 @@ Console.WriteLine(" JointCreateFixed"); | |||
1575 | { | 1575 | { |
1576 | //Console.WriteLine("Move " + m_primName); | 1576 | //Console.WriteLine("Move " + m_primName); |
1577 | if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009 | 1577 | if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // KF add 161009 |
1578 | /* | ||
1579 | // NON-'VEHICLES' are dealt with here | 1578 | // NON-'VEHICLES' are dealt with here |
1580 | if (d.BodyIsEnabled(Body) && !m_angularlock.ApproxEquals(Vector3.Zero, 0.003f)) | 1579 | if (d.BodyIsEnabled(Body) && !m_angularlock.ApproxEquals(Vector3.Zero, 0.003f)) |
1581 | { | 1580 | { |
1582 | d.Vector3 avel2 = d.BodyGetAngularVel(Body); | 1581 | d.Vector3 avel2 = d.BodyGetAngularVel(Body); |
1582 | /* | ||
1583 | if (m_angularlock.X == 1) | 1583 | if (m_angularlock.X == 1) |
1584 | avel2.X = 0; | 1584 | avel2.X = 0; |
1585 | if (m_angularlock.Y == 1) | 1585 | if (m_angularlock.Y == 1) |
@@ -1587,8 +1587,8 @@ Console.WriteLine(" JointCreateFixed"); | |||
1587 | if (m_angularlock.Z == 1) | 1587 | if (m_angularlock.Z == 1) |
1588 | avel2.Z = 0; | 1588 | avel2.Z = 0; |
1589 | d.BodySetAngularVel(Body, avel2.X, avel2.Y, avel2.Z); | 1589 | d.BodySetAngularVel(Body, avel2.X, avel2.Y, avel2.Z); |
1590 | */ | ||
1590 | } | 1591 | } |
1591 | */ | ||
1592 | //float PID_P = 900.0f; | 1592 | //float PID_P = 900.0f; |
1593 | 1593 | ||
1594 | float m_mass = CalculateMass(); | 1594 | float m_mass = CalculateMass(); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 62eae76..8f82304 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -4221,7 +4221,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
4221 | return; | 4221 | return; |
4222 | } | 4222 | } |
4223 | 4223 | ||
4224 | if( message == string.Empty) | 4224 | if (message == string.Empty) |
4225 | { | 4225 | { |
4226 | ShoutError("Trying to use llTextBox with empty message."); | 4226 | ShoutError("Trying to use llTextBox with empty message."); |
4227 | } | 4227 | } |
diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs index 9c54410..a399672 100644 --- a/OpenSim/Server/Base/ServerUtils.cs +++ b/OpenSim/Server/Base/ServerUtils.cs | |||
@@ -57,6 +57,12 @@ namespace OpenSim.Server.Base | |||
57 | return ret; | 57 | return ret; |
58 | } | 58 | } |
59 | 59 | ||
60 | /// <summary> | ||
61 | /// Load a plugin from a dll with the given class or interface | ||
62 | /// </summary> | ||
63 | /// <param name="dllName"></param> | ||
64 | /// <param name="args">The arguments which control which constructor is invoked on the plugin</param> | ||
65 | /// <returns></returns> | ||
60 | public static T LoadPlugin<T>(string dllName, Object[] args) where T:class | 66 | public static T LoadPlugin<T>(string dllName, Object[] args) where T:class |
61 | { | 67 | { |
62 | string[] parts = dllName.Split(new char[] {':'}); | 68 | string[] parts = dllName.Split(new char[] {':'}); |
@@ -71,6 +77,13 @@ namespace OpenSim.Server.Base | |||
71 | return LoadPlugin<T>(dllName, className, args); | 77 | return LoadPlugin<T>(dllName, className, args); |
72 | } | 78 | } |
73 | 79 | ||
80 | /// <summary> | ||
81 | /// Load a plugin from a dll with the given class or interface | ||
82 | /// </summary> | ||
83 | /// <param name="dllName"></param> | ||
84 | /// <param name="className"></param> | ||
85 | /// <param name="args">The arguments which control which constructor is invoked on the plugin</param> | ||
86 | /// <returns></returns> | ||
74 | public static T LoadPlugin<T>(string dllName, string className, Object[] args) where T:class | 87 | public static T LoadPlugin<T>(string dllName, string className, Object[] args) where T:class |
75 | { | 88 | { |
76 | string interfaceName = typeof(T).ToString(); | 89 | string interfaceName = typeof(T).ToString(); |
@@ -83,28 +96,15 @@ namespace OpenSim.Server.Base | |||
83 | { | 96 | { |
84 | if (pluginType.IsPublic) | 97 | if (pluginType.IsPublic) |
85 | { | 98 | { |
86 | if (className != String.Empty && | 99 | if (className != String.Empty |
87 | pluginType.ToString() != | 100 | && pluginType.ToString() != pluginType.Namespace + "." + className) |
88 | pluginType.Namespace + "." + className) | ||
89 | continue; | 101 | continue; |
90 | Type typeInterface = | 102 | |
91 | pluginType.GetInterface(interfaceName, true); | 103 | Type typeInterface = pluginType.GetInterface(interfaceName, true); |
104 | |||
92 | if (typeInterface != null) | 105 | if (typeInterface != null) |
93 | { | 106 | { |
94 | T plug = null; | 107 | return (T)Activator.CreateInstance(pluginType, args); |
95 | try | ||
96 | { | ||
97 | plug = (T)Activator.CreateInstance(pluginType, | ||
98 | args); | ||
99 | } | ||
100 | catch (Exception e) | ||
101 | { | ||
102 | if (!(e is System.MissingMethodException)) | ||
103 | m_log.ErrorFormat("Error loading plugin from {0}, exception {1}", dllName, e.InnerException); | ||
104 | return null; | ||
105 | } | ||
106 | |||
107 | return plug; | ||
108 | } | 108 | } |
109 | } | 109 | } |
110 | } | 110 | } |
@@ -113,7 +113,7 @@ namespace OpenSim.Server.Base | |||
113 | } | 113 | } |
114 | catch (Exception e) | 114 | catch (Exception e) |
115 | { | 115 | { |
116 | m_log.ErrorFormat("Error loading plugin from {0}, exception {1}", dllName, e); | 116 | m_log.Error(string.Format("Error loading plugin from {0}", dllName), e); |
117 | return null; | 117 | return null; |
118 | } | 118 | } |
119 | } | 119 | } |
diff --git a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs index 79c6b2a..6b1152b 100644 --- a/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs +++ b/OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs | |||
@@ -1,4 +1,31 @@ | |||
1 | using System; | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
2 | using System.Collections; | 29 | using System.Collections; |
3 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
4 | using System.Net; | 31 | using System.Net; |
diff --git a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs index f9db859..34f7dcc 100644 --- a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs +++ b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs | |||
@@ -289,7 +289,7 @@ namespace OpenSim.Server.Handlers.Asset | |||
289 | foreach (InventoryItemBase i in icoll.Items) | 289 | foreach (InventoryItemBase i in icoll.Items) |
290 | items[i.ID.ToString()] = EncodeItem(i); | 290 | items[i.ID.ToString()] = EncodeItem(i); |
291 | result["ITEMS"] = items; | 291 | result["ITEMS"] = items; |
292 | } | 292 | } |
293 | 293 | ||
294 | string xmlString = ServerUtils.BuildXmlResponse(result); | 294 | string xmlString = ServerUtils.BuildXmlResponse(result); |
295 | m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); | 295 | m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); |
diff --git a/OpenSim/Services/Base/ServiceBase.cs b/OpenSim/Services/Base/ServiceBase.cs index 91d5c56..ef30cba 100644 --- a/OpenSim/Services/Base/ServiceBase.cs +++ b/OpenSim/Services/Base/ServiceBase.cs | |||
@@ -72,7 +72,7 @@ namespace OpenSim.Services.Base | |||
72 | // m_log.DebugFormat("[SERVICE BASE]: Found type {0}", pluginType); | 72 | // m_log.DebugFormat("[SERVICE BASE]: Found type {0}", pluginType); |
73 | 73 | ||
74 | if (pluginType.IsPublic) | 74 | if (pluginType.IsPublic) |
75 | { | 75 | { |
76 | if (className != String.Empty && | 76 | if (className != String.Empty && |
77 | pluginType.ToString() != | 77 | pluginType.ToString() != |
78 | pluginType.Namespace + "." + className) | 78 | pluginType.Namespace + "." + className) |
diff --git a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs index ce88236..0e85067 100644 --- a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs +++ b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs | |||
@@ -28,9 +28,9 @@ | |||
28 | using System; | 28 | using System; |
29 | 29 | ||
30 | namespace OpenSim.Services.Connectors | 30 | namespace OpenSim.Services.Connectors |
31 | { | 31 | { |
32 | public class GridUserServiceConnector | 32 | public class GridUserServiceConnector |
33 | { | 33 | { |
34 | public GridUserServiceConnector() | 34 | public GridUserServiceConnector() |
35 | { | 35 | { |
36 | } | 36 | } |
diff --git a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs index 9f73b38..c426bba 100644 --- a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs | |||
@@ -1,4 +1,31 @@ | |||
1 | using System; | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
2 | using System.Collections; | 29 | using System.Collections; |
3 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
4 | using System.Drawing; | 31 | using System.Drawing; |
diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs index 83d3449..3e91e3a 100644 --- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs | |||
@@ -1,4 +1,31 @@ | |||
1 | using System; | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
2 | using System.Collections; | 29 | using System.Collections; |
3 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
4 | using System.IO; | 31 | using System.IO; |
@@ -334,7 +361,7 @@ namespace OpenSim.Services.Connectors.Hypergrid | |||
334 | } | 361 | } |
335 | catch (Exception e) | 362 | catch (Exception e) |
336 | { | 363 | { |
337 | m_log.Debug("[HGrid]: Exception " + e.Message); | 364 | m_log.Debug("[USER AGENT CONNECTOR]: Unable to contact remote server "); |
338 | reason = "Exception: " + e.Message; | 365 | reason = "Exception: " + e.Message; |
339 | return false; | 366 | return false; |
340 | } | 367 | } |
diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs index 9821dd4..0cc1978 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs | |||
@@ -126,7 +126,7 @@ namespace OpenSim.Services.Connectors | |||
126 | }); | 126 | }); |
127 | 127 | ||
128 | if (ret == null) | 128 | if (ret == null) |
129 | return null; | 129 | return null; |
130 | if (ret.Count == 0) | 130 | if (ret.Count == 0) |
131 | return null; | 131 | return null; |
132 | 132 | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs new file mode 100644 index 0000000..1c22a72 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs | |||
@@ -0,0 +1,410 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using log4net; | ||
34 | using Mono.Addins; | ||
35 | using Nini.Config; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using OpenSim.Services.Interfaces; | ||
40 | using OpenMetaverse; | ||
41 | using OpenMetaverse.StructuredData; | ||
42 | |||
43 | namespace OpenSim.Services.Connectors.SimianGrid | ||
44 | { | ||
45 | /// <summary> | ||
46 | /// Connects to the SimianGrid asset service | ||
47 | /// </summary> | ||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
49 | public class SimianAssetServiceConnector : IAssetService, ISharedRegionModule | ||
50 | { | ||
51 | private static readonly ILog m_log = | ||
52 | LogManager.GetLogger( | ||
53 | MethodBase.GetCurrentMethod().DeclaringType); | ||
54 | private static string ZeroID = UUID.Zero.ToString(); | ||
55 | |||
56 | private string m_serverUrl = String.Empty; | ||
57 | private IImprovedAssetCache m_cache; | ||
58 | |||
59 | #region ISharedRegionModule | ||
60 | |||
61 | public Type ReplaceableInterface { get { return null; } } | ||
62 | public void RegionLoaded(Scene scene) | ||
63 | { | ||
64 | if (m_cache == null) | ||
65 | { | ||
66 | IImprovedAssetCache cache = scene.RequestModuleInterface<IImprovedAssetCache>(); | ||
67 | if (cache is ISharedRegionModule) | ||
68 | m_cache = cache; | ||
69 | } | ||
70 | } | ||
71 | public void PostInitialise() { } | ||
72 | public void Close() { } | ||
73 | |||
74 | public SimianAssetServiceConnector() { } | ||
75 | public string Name { get { return "SimianAssetServiceConnector"; } } | ||
76 | public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface<IAssetService>(this); } } | ||
77 | public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface<IAssetService>(this); } } | ||
78 | |||
79 | #endregion ISharedRegionModule | ||
80 | |||
81 | public SimianAssetServiceConnector(IConfigSource source) | ||
82 | { | ||
83 | Initialise(source); | ||
84 | } | ||
85 | |||
86 | public void Initialise(IConfigSource source) | ||
87 | { | ||
88 | if (Simian.IsSimianEnabled(source, "AssetServices")) | ||
89 | { | ||
90 | IConfig gridConfig = source.Configs["AssetService"]; | ||
91 | if (gridConfig == null) | ||
92 | { | ||
93 | m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini"); | ||
94 | throw new Exception("Asset connector init error"); | ||
95 | } | ||
96 | |||
97 | string serviceUrl = gridConfig.GetString("AssetServerURI"); | ||
98 | if (String.IsNullOrEmpty(serviceUrl)) | ||
99 | { | ||
100 | m_log.Error("[ASSET CONNECTOR]: No AssetServerURI in section AssetService"); | ||
101 | throw new Exception("Asset connector init error"); | ||
102 | } | ||
103 | |||
104 | if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) | ||
105 | serviceUrl = serviceUrl + '/'; | ||
106 | |||
107 | m_serverUrl = serviceUrl; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | #region IAssetService | ||
112 | |||
113 | public AssetBase Get(string id) | ||
114 | { | ||
115 | AssetBase asset = null; | ||
116 | |||
117 | // Cache fetch | ||
118 | if (m_cache != null) | ||
119 | { | ||
120 | asset = m_cache.Get(id); | ||
121 | if (asset != null) | ||
122 | return asset; | ||
123 | } | ||
124 | |||
125 | Uri url; | ||
126 | |||
127 | // Determine if id is an absolute URL or a grid-relative UUID | ||
128 | if (!Uri.TryCreate(id, UriKind.Absolute, out url)) | ||
129 | url = new Uri(m_serverUrl + id); | ||
130 | |||
131 | try | ||
132 | { | ||
133 | HttpWebRequest request = UntrustedHttpWebRequest.Create(url); | ||
134 | |||
135 | using (WebResponse response = request.GetResponse()) | ||
136 | { | ||
137 | using (Stream responseStream = response.GetResponseStream()) | ||
138 | { | ||
139 | string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty; | ||
140 | |||
141 | // Create the asset object | ||
142 | asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID); | ||
143 | |||
144 | UUID assetID; | ||
145 | if (UUID.TryParse(id, out assetID)) | ||
146 | asset.FullID = assetID; | ||
147 | |||
148 | // Grab the asset data from the response stream | ||
149 | using (MemoryStream stream = new MemoryStream()) | ||
150 | { | ||
151 | responseStream.CopyTo(stream, Int32.MaxValue); | ||
152 | asset.Data = stream.ToArray(); | ||
153 | } | ||
154 | } | ||
155 | } | ||
156 | |||
157 | // Cache store | ||
158 | if (m_cache != null && asset != null) | ||
159 | m_cache.Cache(asset); | ||
160 | |||
161 | return asset; | ||
162 | } | ||
163 | catch (Exception ex) | ||
164 | { | ||
165 | m_log.Warn("[ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message); | ||
166 | return null; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | /// <summary> | ||
171 | /// Get an asset's metadata | ||
172 | /// </summary> | ||
173 | /// <param name="id"></param> | ||
174 | /// <returns></returns> | ||
175 | public AssetMetadata GetMetadata(string id) | ||
176 | { | ||
177 | AssetMetadata metadata = null; | ||
178 | |||
179 | // Cache fetch | ||
180 | if (m_cache != null) | ||
181 | { | ||
182 | AssetBase asset = m_cache.Get(id); | ||
183 | if (asset != null) | ||
184 | return asset.Metadata; | ||
185 | } | ||
186 | |||
187 | Uri url; | ||
188 | |||
189 | // Determine if id is an absolute URL or a grid-relative UUID | ||
190 | if (!Uri.TryCreate(id, UriKind.Absolute, out url)) | ||
191 | url = new Uri(m_serverUrl + id); | ||
192 | |||
193 | try | ||
194 | { | ||
195 | HttpWebRequest request = UntrustedHttpWebRequest.Create(url); | ||
196 | request.Method = "HEAD"; | ||
197 | |||
198 | using (WebResponse response = request.GetResponse()) | ||
199 | { | ||
200 | using (Stream responseStream = response.GetResponseStream()) | ||
201 | { | ||
202 | // Create the metadata object | ||
203 | metadata = new AssetMetadata(); | ||
204 | metadata.ContentType = response.ContentType; | ||
205 | metadata.ID = id; | ||
206 | |||
207 | UUID uuid; | ||
208 | if (UUID.TryParse(id, out uuid)) | ||
209 | metadata.FullID = uuid; | ||
210 | |||
211 | string lastModifiedStr = response.Headers.Get("Last-Modified"); | ||
212 | if (!String.IsNullOrEmpty(lastModifiedStr)) | ||
213 | { | ||
214 | DateTime lastModified; | ||
215 | if (DateTime.TryParse(lastModifiedStr, out lastModified)) | ||
216 | metadata.CreationDate = lastModified; | ||
217 | } | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | catch (Exception ex) | ||
222 | { | ||
223 | m_log.Warn("[ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message); | ||
224 | } | ||
225 | |||
226 | return metadata; | ||
227 | } | ||
228 | |||
229 | public byte[] GetData(string id) | ||
230 | { | ||
231 | AssetBase asset = Get(id); | ||
232 | |||
233 | if (asset != null) | ||
234 | return asset.Data; | ||
235 | |||
236 | return null; | ||
237 | } | ||
238 | |||
239 | /// <summary> | ||
240 | /// Get an asset asynchronously | ||
241 | /// </summary> | ||
242 | /// <param name="id">The asset id</param> | ||
243 | /// <param name="sender">Represents the requester. Passed back via the handler</param> | ||
244 | /// <param name="handler">The handler to call back once the asset has been retrieved</param> | ||
245 | /// <returns>True if the id was parseable, false otherwise</returns> | ||
246 | public bool Get(string id, Object sender, AssetRetrieved handler) | ||
247 | { | ||
248 | Util.FireAndForget( | ||
249 | delegate(object o) | ||
250 | { | ||
251 | AssetBase asset = Get(id); | ||
252 | handler(id, sender, asset); | ||
253 | } | ||
254 | ); | ||
255 | |||
256 | return true; | ||
257 | } | ||
258 | |||
259 | /// <summary> | ||
260 | /// Creates a new asset | ||
261 | /// </summary> | ||
262 | /// Returns a random ID if none is passed into it | ||
263 | /// <param name="asset"></param> | ||
264 | /// <returns></returns> | ||
265 | public string Store(AssetBase asset) | ||
266 | { | ||
267 | bool storedInCache = false; | ||
268 | string errorMessage = null; | ||
269 | |||
270 | // AssetID handling | ||
271 | if (String.IsNullOrEmpty(asset.ID) || asset.ID == ZeroID) | ||
272 | { | ||
273 | asset.FullID = UUID.Random(); | ||
274 | asset.ID = asset.FullID.ToString(); | ||
275 | } | ||
276 | |||
277 | // Cache handling | ||
278 | if (m_cache != null) | ||
279 | { | ||
280 | m_cache.Cache(asset); | ||
281 | storedInCache = true; | ||
282 | } | ||
283 | |||
284 | // Local asset handling | ||
285 | if (asset.Local) | ||
286 | { | ||
287 | if (!storedInCache) | ||
288 | { | ||
289 | m_log.Error("Cannot store local " + asset.Metadata.ContentType + " asset without an asset cache"); | ||
290 | asset.ID = null; | ||
291 | asset.FullID = UUID.Zero; | ||
292 | } | ||
293 | |||
294 | return asset.ID; | ||
295 | } | ||
296 | |||
297 | // Distinguish public and private assets | ||
298 | bool isPublic = true; | ||
299 | switch ((AssetType)asset.Type) | ||
300 | { | ||
301 | case AssetType.CallingCard: | ||
302 | case AssetType.Gesture: | ||
303 | case AssetType.LSLBytecode: | ||
304 | case AssetType.LSLText: | ||
305 | isPublic = false; | ||
306 | break; | ||
307 | } | ||
308 | |||
309 | // Make sure ContentType is set | ||
310 | if (String.IsNullOrEmpty(asset.Metadata.ContentType)) | ||
311 | asset.Metadata.ContentType = SLUtil.SLAssetTypeToContentType(asset.Type); | ||
312 | |||
313 | // Build the remote storage request | ||
314 | List<MultipartForm.Element> postParameters = new List<MultipartForm.Element>() | ||
315 | { | ||
316 | new MultipartForm.Parameter("AssetID", asset.FullID.ToString()), | ||
317 | new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID), | ||
318 | new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"), | ||
319 | new MultipartForm.Parameter("Public", isPublic ? "1" : "0"), | ||
320 | new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data) | ||
321 | }; | ||
322 | |||
323 | // Make the remote storage request | ||
324 | try | ||
325 | { | ||
326 | HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl); | ||
327 | |||
328 | HttpWebResponse response = MultipartForm.Post(request, postParameters); | ||
329 | using (Stream responseStream = response.GetResponseStream()) | ||
330 | { | ||
331 | try | ||
332 | { | ||
333 | string responseStr = responseStream.GetStreamString(); | ||
334 | OSD responseOSD = OSDParser.Deserialize(responseStr); | ||
335 | if (responseOSD.Type == OSDType.Map) | ||
336 | { | ||
337 | OSDMap responseMap = (OSDMap)responseOSD; | ||
338 | if (responseMap["Success"].AsBoolean()) | ||
339 | return asset.ID; | ||
340 | else | ||
341 | errorMessage = "Upload failed: " + responseMap["Message"].AsString(); | ||
342 | } | ||
343 | else | ||
344 | { | ||
345 | errorMessage = "Response format was invalid."; | ||
346 | } | ||
347 | } | ||
348 | catch | ||
349 | { | ||
350 | errorMessage = "Failed to parse the response."; | ||
351 | } | ||
352 | } | ||
353 | } | ||
354 | catch (WebException ex) | ||
355 | { | ||
356 | errorMessage = ex.Message; | ||
357 | } | ||
358 | |||
359 | m_log.WarnFormat("[ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}", | ||
360 | asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage); | ||
361 | return null; | ||
362 | } | ||
363 | |||
364 | /// <summary> | ||
365 | /// Update an asset's content | ||
366 | /// </summary> | ||
367 | /// Attachments and bare scripts need this!! | ||
368 | /// <param name="id"> </param> | ||
369 | /// <param name="data"></param> | ||
370 | /// <returns></returns> | ||
371 | public bool UpdateContent(string id, byte[] data) | ||
372 | { | ||
373 | AssetBase asset = Get(id); | ||
374 | |||
375 | if (asset == null) | ||
376 | { | ||
377 | m_log.Warn("[ASSET CONNECTOR]: Failed to fetch asset " + id + " for updating"); | ||
378 | return false; | ||
379 | } | ||
380 | |||
381 | asset.Data = data; | ||
382 | |||
383 | string result = Store(asset); | ||
384 | return !String.IsNullOrEmpty(result); | ||
385 | } | ||
386 | |||
387 | /// <summary> | ||
388 | /// Delete an asset | ||
389 | /// </summary> | ||
390 | /// <param name="id"></param> | ||
391 | /// <returns></returns> | ||
392 | public bool Delete(string id) | ||
393 | { | ||
394 | if (m_cache != null) | ||
395 | m_cache.Expire(id); | ||
396 | |||
397 | string url = m_serverUrl + id; | ||
398 | |||
399 | OSDMap response = WebUtil.ServiceRequest(url, "DELETE"); | ||
400 | if (response["Success"].AsBoolean()) | ||
401 | return true; | ||
402 | else | ||
403 | m_log.Warn("[ASSET CONNECTOR]: Failed to delete asset " + id + " from the asset service"); | ||
404 | |||
405 | return false; | ||
406 | } | ||
407 | |||
408 | #endregion IAssetService | ||
409 | } | ||
410 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs new file mode 100644 index 0000000..6317b87 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs | |||
@@ -0,0 +1,201 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Specialized; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Mono.Addins; | ||
33 | using Nini.Config; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using OpenSim.Services.Interfaces; | ||
40 | |||
41 | namespace OpenSim.Services.Connectors.SimianGrid | ||
42 | { | ||
43 | /// <summary> | ||
44 | /// Connects authentication/authorization to the SimianGrid backend | ||
45 | /// </summary> | ||
46 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
47 | public class SimianAuthenticationServiceConnector : IAuthenticationService, ISharedRegionModule | ||
48 | { | ||
49 | private static readonly ILog m_log = | ||
50 | LogManager.GetLogger( | ||
51 | MethodBase.GetCurrentMethod().DeclaringType); | ||
52 | |||
53 | private string m_serverUrl = String.Empty; | ||
54 | |||
55 | #region ISharedRegionModule | ||
56 | |||
57 | public Type ReplaceableInterface { get { return null; } } | ||
58 | public void RegionLoaded(Scene scene) { } | ||
59 | public void PostInitialise() { } | ||
60 | public void Close() { } | ||
61 | |||
62 | public SimianAuthenticationServiceConnector() { } | ||
63 | public string Name { get { return "SimianAuthenticationServiceConnector"; } } | ||
64 | public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface<IAuthenticationService>(this); } } | ||
65 | public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface<IAuthenticationService>(this); } } | ||
66 | |||
67 | #endregion ISharedRegionModule | ||
68 | |||
69 | public SimianAuthenticationServiceConnector(IConfigSource source) | ||
70 | { | ||
71 | Initialise(source); | ||
72 | } | ||
73 | |||
74 | public void Initialise(IConfigSource source) | ||
75 | { | ||
76 | if (Simian.IsSimianEnabled(source, "AuthenticationServices")) | ||
77 | { | ||
78 | IConfig assetConfig = source.Configs["AuthenticationService"]; | ||
79 | if (assetConfig == null) | ||
80 | { | ||
81 | m_log.Error("[AUTH CONNECTOR]: AuthenticationService missing from OpenSim.ini"); | ||
82 | throw new Exception("Authentication connector init error"); | ||
83 | } | ||
84 | |||
85 | string serviceURI = assetConfig.GetString("AuthenticationServerURI"); | ||
86 | if (String.IsNullOrEmpty(serviceURI)) | ||
87 | { | ||
88 | m_log.Error("[AUTH CONNECTOR]: No Server URI named in section AuthenticationService"); | ||
89 | throw new Exception("Authentication connector init error"); | ||
90 | } | ||
91 | |||
92 | m_serverUrl = serviceURI; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | public string Authenticate(UUID principalID, string password, int lifetime) | ||
97 | { | ||
98 | NameValueCollection requestArgs = new NameValueCollection | ||
99 | { | ||
100 | { "RequestMethod", "GetIdentities" }, | ||
101 | { "UserID", principalID.ToString() } | ||
102 | }; | ||
103 | |||
104 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
105 | if (response["Success"].AsBoolean() && response["Identities"] is OSDArray) | ||
106 | { | ||
107 | OSDArray identities = (OSDArray)response["Identities"]; | ||
108 | for (int i = 0; i < identities.Count; i++) | ||
109 | { | ||
110 | OSDMap identity = identities[i] as OSDMap; | ||
111 | if (identity != null) | ||
112 | { | ||
113 | if (identity["Type"].AsString() == "md5hash") | ||
114 | { | ||
115 | string credential = identity["Credential"].AsString(); | ||
116 | |||
117 | if (password == credential || Utils.MD5String(password) == credential) | ||
118 | return Authorize(principalID); | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | m_log.Warn("[AUTH CONNECTOR]: Authentication failed for " + principalID); | ||
124 | } | ||
125 | else | ||
126 | { | ||
127 | m_log.Warn("[AUTH CONNECTOR]: Failed to retrieve identities for " + principalID + ": " + | ||
128 | response["Message"].AsString()); | ||
129 | } | ||
130 | |||
131 | return String.Empty; | ||
132 | } | ||
133 | |||
134 | public bool Verify(UUID principalID, string token, int lifetime) | ||
135 | { | ||
136 | NameValueCollection requestArgs = new NameValueCollection | ||
137 | { | ||
138 | { "RequestMethod", "GetSession" }, | ||
139 | { "SessionID", token } | ||
140 | }; | ||
141 | |||
142 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
143 | if (response["Success"].AsBoolean()) | ||
144 | { | ||
145 | return true; | ||
146 | } | ||
147 | else | ||
148 | { | ||
149 | m_log.Warn("[AUTH CONNECTOR]: Could not verify session for " + principalID + ": " + | ||
150 | response["Message"].AsString()); | ||
151 | } | ||
152 | |||
153 | return false; | ||
154 | } | ||
155 | |||
156 | public bool Release(UUID principalID, string token) | ||
157 | { | ||
158 | NameValueCollection requestArgs = new NameValueCollection | ||
159 | { | ||
160 | { "RequestMethod", "RemoveSession" }, | ||
161 | { "UserID", principalID.ToString() } | ||
162 | }; | ||
163 | |||
164 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
165 | if (response["Success"].AsBoolean()) | ||
166 | { | ||
167 | return true; | ||
168 | } | ||
169 | else | ||
170 | { | ||
171 | m_log.Warn("[AUTH CONNECTOR]: Failed to remove session for " + principalID + ": " + | ||
172 | response["Message"].AsString()); | ||
173 | } | ||
174 | |||
175 | return false; | ||
176 | } | ||
177 | |||
178 | public bool SetPassword(UUID principalID, string passwd) | ||
179 | { | ||
180 | // TODO: Use GetIdentities to find the md5hash identity for principalID | ||
181 | // and then update it with AddIdentity | ||
182 | m_log.Error("[AUTH CONNECTOR]: Changing passwords is not implemented yet"); | ||
183 | return false; | ||
184 | } | ||
185 | |||
186 | private string Authorize(UUID userID) | ||
187 | { | ||
188 | NameValueCollection requestArgs = new NameValueCollection | ||
189 | { | ||
190 | { "RequestMethod", "AddSession" }, | ||
191 | { "UserID", userID.ToString() } | ||
192 | }; | ||
193 | |||
194 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
195 | if (response["Success"].AsBoolean()) | ||
196 | return response["SessionID"].AsUUID().ToString(); | ||
197 | else | ||
198 | return String.Empty; | ||
199 | } | ||
200 | } | ||
201 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs new file mode 100644 index 0000000..a18cb22 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.IO; | ||
32 | using System.Net; | ||
33 | using System.Reflection; | ||
34 | using log4net; | ||
35 | using Mono.Addins; | ||
36 | using Nini.Config; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Server.Base; | ||
41 | using OpenSim.Services.Interfaces; | ||
42 | using OpenMetaverse; | ||
43 | using OpenMetaverse.StructuredData; | ||
44 | |||
45 | namespace OpenSim.Services.Connectors.SimianGrid | ||
46 | { | ||
47 | /// <summary> | ||
48 | /// Connects avatar appearance data to the SimianGrid backend | ||
49 | /// </summary> | ||
50 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
51 | public class SimianAvatarServiceConnector : IAvatarService, ISharedRegionModule | ||
52 | { | ||
53 | private static readonly ILog m_log = | ||
54 | LogManager.GetLogger( | ||
55 | MethodBase.GetCurrentMethod().DeclaringType); | ||
56 | private static string ZeroID = UUID.Zero.ToString(); | ||
57 | |||
58 | private string m_serverUrl = String.Empty; | ||
59 | |||
60 | #region ISharedRegionModule | ||
61 | |||
62 | public Type ReplaceableInterface { get { return null; } } | ||
63 | public void RegionLoaded(Scene scene) { } | ||
64 | public void PostInitialise() { } | ||
65 | public void Close() { } | ||
66 | |||
67 | public SimianAvatarServiceConnector() { } | ||
68 | public string Name { get { return "SimianAvatarServiceConnector"; } } | ||
69 | public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface<IAvatarService>(this); } } | ||
70 | public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface<IAvatarService>(this); } } | ||
71 | |||
72 | #endregion ISharedRegionModule | ||
73 | |||
74 | public SimianAvatarServiceConnector(IConfigSource source) | ||
75 | { | ||
76 | Initialise(source); | ||
77 | } | ||
78 | |||
79 | public void Initialise(IConfigSource source) | ||
80 | { | ||
81 | if (Simian.IsSimianEnabled(source, "AvatarServices")) | ||
82 | { | ||
83 | IConfig gridConfig = source.Configs["AvatarService"]; | ||
84 | if (gridConfig == null) | ||
85 | { | ||
86 | m_log.Error("[AVATAR CONNECTOR]: AvatarService missing from OpenSim.ini"); | ||
87 | throw new Exception("Avatar connector init error"); | ||
88 | } | ||
89 | |||
90 | string serviceUrl = gridConfig.GetString("AvatarServerURI"); | ||
91 | if (String.IsNullOrEmpty(serviceUrl)) | ||
92 | { | ||
93 | m_log.Error("[AVATAR CONNECTOR]: No AvatarServerURI in section AvatarService"); | ||
94 | throw new Exception("Avatar connector init error"); | ||
95 | } | ||
96 | |||
97 | if (!serviceUrl.EndsWith("/")) | ||
98 | serviceUrl = serviceUrl + '/'; | ||
99 | |||
100 | m_serverUrl = serviceUrl; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | #region IAvatarService | ||
105 | |||
106 | public AvatarData GetAvatar(UUID userID) | ||
107 | { | ||
108 | NameValueCollection requestArgs = new NameValueCollection | ||
109 | { | ||
110 | { "RequestMethod", "GetUser" }, | ||
111 | { "UserID", userID.ToString() } | ||
112 | }; | ||
113 | |||
114 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
115 | if (response["Success"].AsBoolean()) | ||
116 | { | ||
117 | OSDMap map = null; | ||
118 | try { map = OSDParser.DeserializeJson(response["LLAppearance"].AsString()) as OSDMap; } | ||
119 | catch { } | ||
120 | |||
121 | if (map != null) | ||
122 | { | ||
123 | AvatarWearable[] wearables = new AvatarWearable[13]; | ||
124 | wearables[0] = new AvatarWearable(map["ShapeItem"].AsUUID(), map["ShapeAsset"].AsUUID()); | ||
125 | wearables[1] = new AvatarWearable(map["SkinItem"].AsUUID(), map["SkinAsset"].AsUUID()); | ||
126 | wearables[2] = new AvatarWearable(map["HairItem"].AsUUID(), map["HairAsset"].AsUUID()); | ||
127 | wearables[3] = new AvatarWearable(map["EyesItem"].AsUUID(), map["EyesAsset"].AsUUID()); | ||
128 | wearables[4] = new AvatarWearable(map["ShirtItem"].AsUUID(), map["ShirtAsset"].AsUUID()); | ||
129 | wearables[5] = new AvatarWearable(map["PantsItem"].AsUUID(), map["PantsAsset"].AsUUID()); | ||
130 | wearables[6] = new AvatarWearable(map["ShoesItem"].AsUUID(), map["ShoesAsset"].AsUUID()); | ||
131 | wearables[7] = new AvatarWearable(map["SocksItem"].AsUUID(), map["SocksAsset"].AsUUID()); | ||
132 | wearables[8] = new AvatarWearable(map["JacketItem"].AsUUID(), map["JacketAsset"].AsUUID()); | ||
133 | wearables[9] = new AvatarWearable(map["GlovesItem"].AsUUID(), map["GlovesAsset"].AsUUID()); | ||
134 | wearables[10] = new AvatarWearable(map["UndershirtItem"].AsUUID(), map["UndershirtAsset"].AsUUID()); | ||
135 | wearables[11] = new AvatarWearable(map["UnderpantsItem"].AsUUID(), map["UnderpantsAsset"].AsUUID()); | ||
136 | wearables[12] = new AvatarWearable(map["SkirtItem"].AsUUID(), map["SkirtAsset"].AsUUID()); | ||
137 | |||
138 | AvatarAppearance appearance = new AvatarAppearance(userID); | ||
139 | appearance.Wearables = wearables; | ||
140 | appearance.AvatarHeight = (float)map["Height"].AsReal(); | ||
141 | |||
142 | AvatarData avatar = new AvatarData(appearance); | ||
143 | |||
144 | // Get attachments | ||
145 | map = null; | ||
146 | try { map = OSDParser.DeserializeJson(response["LLAttachments"].AsString()) as OSDMap; } | ||
147 | catch { } | ||
148 | |||
149 | if (map != null) | ||
150 | { | ||
151 | foreach (KeyValuePair<string, OSD> kvp in map) | ||
152 | avatar.Data[kvp.Key] = kvp.Value.AsString(); | ||
153 | } | ||
154 | |||
155 | return avatar; | ||
156 | } | ||
157 | else | ||
158 | { | ||
159 | m_log.Warn("[AVATAR CONNECTOR]: Failed to get user appearance for " + userID + | ||
160 | ", LLAppearance is missing or invalid"); | ||
161 | return null; | ||
162 | } | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | m_log.Warn("[AVATAR CONNECTOR]: Failed to get user appearance for " + userID + ": " + | ||
167 | response["Message"].AsString()); | ||
168 | } | ||
169 | |||
170 | return null; | ||
171 | } | ||
172 | |||
173 | public bool SetAvatar(UUID userID, AvatarData avatar) | ||
174 | { | ||
175 | m_log.Debug("[AVATAR CONNECTOR]: SetAvatar called for " + userID); | ||
176 | |||
177 | if (avatar.AvatarType == 1) // LLAvatar | ||
178 | { | ||
179 | AvatarAppearance appearance = avatar.ToAvatarAppearance(userID); | ||
180 | |||
181 | OSDMap map = new OSDMap(); | ||
182 | |||
183 | map["Height"] = OSD.FromReal(appearance.AvatarHeight); | ||
184 | |||
185 | map["ShapeItem"] = OSD.FromUUID(appearance.BodyItem); | ||
186 | map["ShapeAsset"] = OSD.FromUUID(appearance.BodyAsset); | ||
187 | map["SkinItem"] = OSD.FromUUID(appearance.SkinItem); | ||
188 | map["SkinAsset"] = OSD.FromUUID(appearance.SkinAsset); | ||
189 | map["HairItem"] = OSD.FromUUID(appearance.HairItem); | ||
190 | map["HairAsset"] = OSD.FromUUID(appearance.HairAsset); | ||
191 | map["EyesItem"] = OSD.FromUUID(appearance.EyesItem); | ||
192 | map["EyesAsset"] = OSD.FromUUID(appearance.EyesAsset); | ||
193 | map["ShirtItem"] = OSD.FromUUID(appearance.ShirtItem); | ||
194 | map["ShirtAsset"] = OSD.FromUUID(appearance.ShirtAsset); | ||
195 | map["PantsItem"] = OSD.FromUUID(appearance.PantsItem); | ||
196 | map["PantsAsset"] = OSD.FromUUID(appearance.PantsAsset); | ||
197 | map["ShoesItem"] = OSD.FromUUID(appearance.ShoesItem); | ||
198 | map["ShoesAsset"] = OSD.FromUUID(appearance.ShoesAsset); | ||
199 | map["SocksItem"] = OSD.FromUUID(appearance.SocksItem); | ||
200 | map["SocksAsset"] = OSD.FromUUID(appearance.SocksAsset); | ||
201 | map["JacketItem"] = OSD.FromUUID(appearance.JacketItem); | ||
202 | map["JacketAsset"] = OSD.FromUUID(appearance.JacketAsset); | ||
203 | map["GlovesItem"] = OSD.FromUUID(appearance.GlovesItem); | ||
204 | map["GlovesAsset"] = OSD.FromUUID(appearance.GlovesAsset); | ||
205 | map["UndershirtItem"] = OSD.FromUUID(appearance.UnderShirtItem); | ||
206 | map["UndershirtAsset"] = OSD.FromUUID(appearance.UnderShirtAsset); | ||
207 | map["UnderpantsItem"] = OSD.FromUUID(appearance.UnderPantsItem); | ||
208 | map["UnderpantsAsset"] = OSD.FromUUID(appearance.UnderPantsAsset); | ||
209 | map["SkirtItem"] = OSD.FromUUID(appearance.SkirtItem); | ||
210 | map["SkirtAsset"] = OSD.FromUUID(appearance.SkirtAsset); | ||
211 | |||
212 | OSDMap items = new OSDMap(); | ||
213 | foreach (KeyValuePair<string, string> kvp in avatar.Data) | ||
214 | { | ||
215 | if (kvp.Key.StartsWith("_ap_")) | ||
216 | items.Add(kvp.Key, OSD.FromString(kvp.Value)); | ||
217 | } | ||
218 | |||
219 | NameValueCollection requestArgs = new NameValueCollection | ||
220 | { | ||
221 | { "RequestMethod", "AddUserData" }, | ||
222 | { "UserID", userID.ToString() }, | ||
223 | { "LLAppearance", OSDParser.SerializeJsonString(map) }, | ||
224 | { "LLAttachments", OSDParser.SerializeJsonString(items) } | ||
225 | }; | ||
226 | |||
227 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
228 | bool success = response["Success"].AsBoolean(); | ||
229 | |||
230 | if (!success) | ||
231 | m_log.Warn("[AVATAR CONNECTOR]: Failed saving appearance for " + userID + ": " + response["Message"].AsString()); | ||
232 | |||
233 | return success; | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | m_log.Error("[AVATAR CONNECTOR]: Can't save appearance for " + userID + ". Unhandled avatar type " + avatar.AvatarType); | ||
238 | return false; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | public bool ResetAvatar(UUID userID) | ||
243 | { | ||
244 | m_log.Error("[AVATAR CONNECTOR]: ResetAvatar called for " + userID + ", implement this"); | ||
245 | return false; | ||
246 | } | ||
247 | |||
248 | public bool SetItems(UUID userID, string[] names, string[] values) | ||
249 | { | ||
250 | m_log.Error("[AVATAR CONNECTOR]: SetItems called for " + userID + " with " + names.Length + " names and " + values.Length + " values, implement this"); | ||
251 | return false; | ||
252 | } | ||
253 | |||
254 | public bool RemoveItems(UUID userID, string[] names) | ||
255 | { | ||
256 | m_log.Error("[AVATAR CONNECTOR]: RemoveItems called for " + userID + " with " + names.Length + " names, implement this"); | ||
257 | return false; | ||
258 | } | ||
259 | |||
260 | #endregion IAvatarService | ||
261 | } | ||
262 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs new file mode 100644 index 0000000..b3ecc7e --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | using Mono.Addins; | ||
34 | using Nini.Config; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | |||
42 | using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; | ||
43 | |||
44 | namespace OpenSim.Services.Connectors.SimianGrid | ||
45 | { | ||
46 | /// <summary> | ||
47 | /// Stores and retrieves friend lists from the SimianGrid backend | ||
48 | /// </summary> | ||
49 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
50 | public class SimianFriendsServiceConnector : IFriendsService, ISharedRegionModule | ||
51 | { | ||
52 | private static readonly ILog m_log = | ||
53 | LogManager.GetLogger( | ||
54 | MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private string m_serverUrl = String.Empty; | ||
57 | |||
58 | #region ISharedRegionModule | ||
59 | |||
60 | public Type ReplaceableInterface { get { return null; } } | ||
61 | public void RegionLoaded(Scene scene) { } | ||
62 | public void PostInitialise() { } | ||
63 | public void Close() { } | ||
64 | |||
65 | public SimianFriendsServiceConnector() { } | ||
66 | public string Name { get { return "SimianFriendsServiceConnector"; } } | ||
67 | public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface<IFriendsService>(this); } } | ||
68 | public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface<IFriendsService>(this); } } | ||
69 | |||
70 | #endregion ISharedRegionModule | ||
71 | |||
72 | public SimianFriendsServiceConnector(IConfigSource source) | ||
73 | { | ||
74 | Initialise(source); | ||
75 | } | ||
76 | |||
77 | public void Initialise(IConfigSource source) | ||
78 | { | ||
79 | if (Simian.IsSimianEnabled(source, "FriendsServices")) | ||
80 | { | ||
81 | IConfig assetConfig = source.Configs["FriendsService"]; | ||
82 | if (assetConfig == null) | ||
83 | { | ||
84 | m_log.Error("[FRIENDS CONNECTOR]: FriendsService missing from OpenSim.ini"); | ||
85 | throw new Exception("Friends connector init error"); | ||
86 | } | ||
87 | |||
88 | string serviceURI = assetConfig.GetString("FriendsServerURI"); | ||
89 | if (String.IsNullOrEmpty(serviceURI)) | ||
90 | { | ||
91 | m_log.Error("[FRIENDS CONNECTOR]: No Server URI named in section FriendsService"); | ||
92 | throw new Exception("Friends connector init error"); | ||
93 | } | ||
94 | |||
95 | m_serverUrl = serviceURI; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | #region IFriendsService | ||
100 | |||
101 | public FriendInfo[] GetFriends(UUID principalID) | ||
102 | { | ||
103 | Dictionary<UUID, FriendInfo> friends = new Dictionary<UUID, FriendInfo>(); | ||
104 | |||
105 | OSDArray friendsArray = GetFriended(principalID); | ||
106 | OSDArray friendedMeArray = GetFriendedBy(principalID); | ||
107 | |||
108 | // Load the list of friends and their granted permissions | ||
109 | for (int i = 0; i < friendsArray.Count; i++) | ||
110 | { | ||
111 | OSDMap friendEntry = friendsArray[i] as OSDMap; | ||
112 | if (friendEntry != null) | ||
113 | { | ||
114 | UUID friendID = friendEntry["Key"].AsUUID(); | ||
115 | |||
116 | FriendInfo friend = new FriendInfo(); | ||
117 | friend.PrincipalID = principalID; | ||
118 | friend.Friend = friendID.ToString(); | ||
119 | friend.MyFlags = friendEntry["Value"].AsInteger(); | ||
120 | friend.TheirFlags = -1; | ||
121 | |||
122 | friends[friendID] = friend; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | // Load the permissions those friends have granted to this user | ||
127 | for (int i = 0; i < friendedMeArray.Count; i++) | ||
128 | { | ||
129 | OSDMap friendedMeEntry = friendedMeArray[i] as OSDMap; | ||
130 | if (friendedMeEntry != null) | ||
131 | { | ||
132 | UUID friendID = friendedMeEntry["OwnerID"].AsUUID(); | ||
133 | |||
134 | FriendInfo friend; | ||
135 | if (friends.TryGetValue(friendID, out friend)) | ||
136 | friend.TheirFlags = friendedMeEntry["Value"].AsInteger(); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | // Convert the dictionary of friends to an array and return it | ||
141 | FriendInfo[] array = new FriendInfo[friends.Count]; | ||
142 | int j = 0; | ||
143 | foreach (FriendInfo friend in friends.Values) | ||
144 | array[j++] = friend; | ||
145 | |||
146 | return array; | ||
147 | } | ||
148 | |||
149 | public bool StoreFriend(UUID principalID, string friend, int flags) | ||
150 | { | ||
151 | NameValueCollection requestArgs = new NameValueCollection | ||
152 | { | ||
153 | { "RequestMethod", "AddGeneric" }, | ||
154 | { "OwnerID", principalID.ToString() }, | ||
155 | { "Type", "Friend" }, | ||
156 | { "Key", friend }, | ||
157 | { "Value", flags.ToString() } | ||
158 | }; | ||
159 | |||
160 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
161 | bool success = response["Success"].AsBoolean(); | ||
162 | |||
163 | if (!success) | ||
164 | m_log.Error("[FRIENDS CONNECTOR]: Failed to store friend " + friend + " for user " + principalID + ": " + response["Message"].AsString()); | ||
165 | |||
166 | return success; | ||
167 | } | ||
168 | |||
169 | public bool Delete(UUID principalID, string friend) | ||
170 | { | ||
171 | NameValueCollection requestArgs = new NameValueCollection | ||
172 | { | ||
173 | { "RequestMethod", "RemoveGeneric" }, | ||
174 | { "OwnerID", principalID.ToString() }, | ||
175 | { "Type", "Friend" }, | ||
176 | { "Key", friend } | ||
177 | }; | ||
178 | |||
179 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
180 | bool success = response["Success"].AsBoolean(); | ||
181 | |||
182 | if (!success) | ||
183 | m_log.Error("[FRIENDS CONNECTOR]: Failed to remove friend " + friend + " for user " + principalID + ": " + response["Message"].AsString()); | ||
184 | |||
185 | return success; | ||
186 | } | ||
187 | |||
188 | #endregion IFriendsService | ||
189 | |||
190 | private OSDArray GetFriended(UUID ownerID) | ||
191 | { | ||
192 | NameValueCollection requestArgs = new NameValueCollection | ||
193 | { | ||
194 | { "RequestMethod", "GetGenerics" }, | ||
195 | { "OwnerID", ownerID.ToString() }, | ||
196 | { "Type", "Friend" } | ||
197 | }; | ||
198 | |||
199 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
200 | if (response["Success"].AsBoolean() && response["Entries"] is OSDArray) | ||
201 | { | ||
202 | return (OSDArray)response["Entries"]; | ||
203 | } | ||
204 | else | ||
205 | { | ||
206 | m_log.Warn("[FRIENDS CONNECTOR]: Failed to retrieve friends for user " + ownerID + ": " + response["Message"].AsString()); | ||
207 | return new OSDArray(0); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | private OSDArray GetFriendedBy(UUID ownerID) | ||
212 | { | ||
213 | NameValueCollection requestArgs = new NameValueCollection | ||
214 | { | ||
215 | { "RequestMethod", "GetGenerics" }, | ||
216 | { "Key", ownerID.ToString() }, | ||
217 | { "Type", "Friend" } | ||
218 | }; | ||
219 | |||
220 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
221 | if (response["Success"].AsBoolean() && response["Entries"] is OSDArray) | ||
222 | { | ||
223 | return (OSDArray)response["Entries"]; | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | m_log.Warn("[FRIENDS CONNECTOR]: Failed to retrieve reverse friends for user " + ownerID + ": " + response["Message"].AsString()); | ||
228 | return new OSDArray(0); | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs new file mode 100644 index 0000000..c3de98e --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using Mono.Addins; | ||
30 | using Nini.Config; | ||
31 | |||
32 | [assembly: Addin("SimianGrid", "1.0")] | ||
33 | [assembly: AddinDependency("OpenSim", "0.5")] | ||
34 | |||
35 | public static class Simian | ||
36 | { | ||
37 | public static bool IsSimianEnabled(IConfigSource config, string moduleName) | ||
38 | { | ||
39 | if (config.Configs["Modules"] != null) | ||
40 | { | ||
41 | string module = config.Configs["Modules"].GetString("AuthenticationServices"); | ||
42 | return !String.IsNullOrEmpty(module) && module.Contains("Simian"); | ||
43 | } | ||
44 | |||
45 | return false; | ||
46 | } | ||
47 | } \ No newline at end of file | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs new file mode 100644 index 0000000..eebdf14 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs | |||
@@ -0,0 +1,421 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using log4net; | ||
34 | using Mono.Addins; | ||
35 | using Nini.Config; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Servers.HttpServer; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using OpenSim.Server.Base; | ||
42 | using OpenMetaverse; | ||
43 | using OpenMetaverse.StructuredData; | ||
44 | |||
45 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
46 | |||
47 | namespace OpenSim.Services.Connectors.SimianGrid | ||
48 | { | ||
49 | /// <summary> | ||
50 | /// Connects region registration and neighbor lookups to the SimianGrid | ||
51 | /// backend | ||
52 | /// </summary> | ||
53 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
54 | public class SimianGridServiceConnector : IGridService, ISharedRegionModule | ||
55 | { | ||
56 | private static readonly ILog m_log = | ||
57 | LogManager.GetLogger( | ||
58 | MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | |||
60 | private string m_serverUrl = String.Empty; | ||
61 | |||
62 | #region ISharedRegionModule | ||
63 | |||
64 | public Type ReplaceableInterface { get { return null; } } | ||
65 | public void RegionLoaded(Scene scene) { } | ||
66 | public void PostInitialise() { } | ||
67 | public void Close() { } | ||
68 | |||
69 | public SimianGridServiceConnector() { } | ||
70 | public string Name { get { return "SimianGridServiceConnector"; } } | ||
71 | public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface<IGridService>(this); } } | ||
72 | public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface<IGridService>(this); } } | ||
73 | |||
74 | #endregion ISharedRegionModule | ||
75 | |||
76 | public SimianGridServiceConnector(IConfigSource source) | ||
77 | { | ||
78 | Initialise(source); | ||
79 | } | ||
80 | |||
81 | public void Initialise(IConfigSource source) | ||
82 | { | ||
83 | if (Simian.IsSimianEnabled(source, "GridServices")) | ||
84 | { | ||
85 | IConfig gridConfig = source.Configs["GridService"]; | ||
86 | if (gridConfig == null) | ||
87 | { | ||
88 | m_log.Error("[GRID CONNECTOR]: GridService missing from OpenSim.ini"); | ||
89 | throw new Exception("Grid connector init error"); | ||
90 | } | ||
91 | |||
92 | string serviceUrl = gridConfig.GetString("GridServerURI"); | ||
93 | if (String.IsNullOrEmpty(serviceUrl)) | ||
94 | { | ||
95 | m_log.Error("[GRID CONNECTOR]: No Server URI named in section GridService"); | ||
96 | throw new Exception("Grid connector init error"); | ||
97 | } | ||
98 | |||
99 | m_serverUrl = serviceUrl; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | #region IGridService | ||
104 | |||
105 | public string RegisterRegion(UUID scopeID, GridRegion regionInfo) | ||
106 | { | ||
107 | Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0); | ||
108 | Vector3d maxPosition = minPosition + new Vector3d(Constants.RegionSize, Constants.RegionSize, 4096.0); | ||
109 | |||
110 | string httpAddress = "http://" + regionInfo.ExternalHostName + ":" + regionInfo.HttpPort + "/"; | ||
111 | |||
112 | OSDMap extraData = new OSDMap | ||
113 | { | ||
114 | { "ServerURI", OSD.FromString(regionInfo.ServerURI) }, | ||
115 | { "InternalAddress", OSD.FromString(regionInfo.InternalEndPoint.Address.ToString()) }, | ||
116 | { "InternalPort", OSD.FromInteger(regionInfo.InternalEndPoint.Port) }, | ||
117 | { "ExternalAddress", OSD.FromString(regionInfo.ExternalEndPoint.Address.ToString()) }, | ||
118 | { "ExternalPort", OSD.FromInteger(regionInfo.ExternalEndPoint.Port) }, | ||
119 | { "MapTexture", OSD.FromUUID(regionInfo.TerrainImage) }, | ||
120 | { "Access", OSD.FromInteger(regionInfo.Access) }, | ||
121 | { "RegionSecret", OSD.FromString(regionInfo.RegionSecret) }, | ||
122 | { "EstateOwner", OSD.FromUUID(regionInfo.EstateOwner) }, | ||
123 | { "Token", OSD.FromString(regionInfo.Token) } | ||
124 | }; | ||
125 | |||
126 | NameValueCollection requestArgs = new NameValueCollection | ||
127 | { | ||
128 | { "RequestMethod", "AddScene" }, | ||
129 | { "SceneID", regionInfo.RegionID.ToString() }, | ||
130 | { "Name", regionInfo.RegionName }, | ||
131 | { "MinPosition", minPosition.ToString() }, | ||
132 | { "MaxPosition", maxPosition.ToString() }, | ||
133 | { "Address", httpAddress }, | ||
134 | { "Enabled", "1" }, | ||
135 | { "ExtraData", OSDParser.SerializeJsonString(extraData) } | ||
136 | }; | ||
137 | |||
138 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
139 | if (response["Success"].AsBoolean()) | ||
140 | return String.Empty; | ||
141 | else | ||
142 | return "Region registration for " + regionInfo.RegionName + " failed: " + response["Message"].AsString(); | ||
143 | } | ||
144 | |||
145 | public bool DeregisterRegion(UUID regionID) | ||
146 | { | ||
147 | NameValueCollection requestArgs = new NameValueCollection | ||
148 | { | ||
149 | { "RequestMethod", "AddScene" }, | ||
150 | { "SceneID", regionID.ToString() }, | ||
151 | { "Enabled", "0" } | ||
152 | }; | ||
153 | |||
154 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
155 | bool success = response["Success"].AsBoolean(); | ||
156 | |||
157 | if (!success) | ||
158 | m_log.Warn("[GRID CONNECTOR]: Region deregistration for " + regionID + " failed: " + response["Message"].AsString()); | ||
159 | |||
160 | return success; | ||
161 | } | ||
162 | |||
163 | public List<GridRegion> GetNeighbours(UUID scopeID, UUID regionID) | ||
164 | { | ||
165 | const int NEIGHBOR_RADIUS = 128; | ||
166 | |||
167 | GridRegion region = GetRegionByUUID(scopeID, regionID); | ||
168 | |||
169 | if (region != null) | ||
170 | { | ||
171 | List<GridRegion> regions = GetRegionRange(scopeID, | ||
172 | region.RegionLocX - NEIGHBOR_RADIUS, region.RegionLocX + (int)Constants.RegionSize + NEIGHBOR_RADIUS, | ||
173 | region.RegionLocY - NEIGHBOR_RADIUS, region.RegionLocY + (int)Constants.RegionSize + NEIGHBOR_RADIUS); | ||
174 | |||
175 | for (int i = 0; i < regions.Count; i++) | ||
176 | { | ||
177 | if (regions[i].RegionID == regionID) | ||
178 | { | ||
179 | regions.RemoveAt(i); | ||
180 | break; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | m_log.Debug("[GRID CONNECTOR]: Found " + regions.Count + " neighbors for region " + regionID); | ||
185 | return regions; | ||
186 | } | ||
187 | |||
188 | return new List<GridRegion>(0); | ||
189 | } | ||
190 | |||
191 | public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID) | ||
192 | { | ||
193 | NameValueCollection requestArgs = new NameValueCollection | ||
194 | { | ||
195 | { "RequestMethod", "GetScene" }, | ||
196 | { "SceneID", regionID.ToString() } | ||
197 | }; | ||
198 | |||
199 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
200 | if (response["Success"].AsBoolean()) | ||
201 | { | ||
202 | return ResponseToGridRegion(response); | ||
203 | } | ||
204 | else | ||
205 | { | ||
206 | m_log.Warn("[GRID CONNECTOR]: Grid service did not find a match for region " + regionID); | ||
207 | return null; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) | ||
212 | { | ||
213 | // Go one meter in from the requested x/y coords to avoid requesting a position | ||
214 | // that falls on the border of two sims | ||
215 | Vector3d position = new Vector3d(x + 1, y + 1, 0.0); | ||
216 | |||
217 | NameValueCollection requestArgs = new NameValueCollection | ||
218 | { | ||
219 | { "RequestMethod", "GetScene" }, | ||
220 | { "Position", position.ToString() }, | ||
221 | { "Enabled", "1" } | ||
222 | }; | ||
223 | |||
224 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
225 | if (response["Success"].AsBoolean()) | ||
226 | { | ||
227 | return ResponseToGridRegion(response); | ||
228 | } | ||
229 | else | ||
230 | { | ||
231 | //m_log.InfoFormat("[GRID CONNECTOR]: Grid service did not find a match for region at {0},{1}", | ||
232 | // x / Constants.RegionSize, y / Constants.RegionSize); | ||
233 | return null; | ||
234 | } | ||
235 | } | ||
236 | |||
237 | public GridRegion GetRegionByName(UUID scopeID, string regionName) | ||
238 | { | ||
239 | List<GridRegion> regions = GetRegionsByName(scopeID, regionName, 1); | ||
240 | |||
241 | m_log.Debug("[GRID CONNECTOR]: Got " + regions.Count + " matches for region name " + regionName); | ||
242 | |||
243 | if (regions.Count > 0) | ||
244 | return regions[0]; | ||
245 | |||
246 | return null; | ||
247 | } | ||
248 | |||
249 | public List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber) | ||
250 | { | ||
251 | List<GridRegion> foundRegions = new List<GridRegion>(); | ||
252 | |||
253 | NameValueCollection requestArgs = new NameValueCollection | ||
254 | { | ||
255 | { "RequestMethod", "GetScenes" }, | ||
256 | { "NameQuery", name }, | ||
257 | { "Enabled", "1" } | ||
258 | }; | ||
259 | if (maxNumber > 0) | ||
260 | requestArgs["MaxNumber"] = maxNumber.ToString(); | ||
261 | |||
262 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
263 | if (response["Success"].AsBoolean()) | ||
264 | { | ||
265 | OSDArray array = response["Scenes"] as OSDArray; | ||
266 | if (array != null) | ||
267 | { | ||
268 | for (int i = 0; i < array.Count; i++) | ||
269 | { | ||
270 | GridRegion region = ResponseToGridRegion(array[i] as OSDMap); | ||
271 | if (region != null) | ||
272 | foundRegions.Add(region); | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | |||
277 | return foundRegions; | ||
278 | } | ||
279 | |||
280 | public List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax) | ||
281 | { | ||
282 | List<GridRegion> foundRegions = new List<GridRegion>(); | ||
283 | |||
284 | Vector3d minPosition = new Vector3d(xmin, ymin, 0.0); | ||
285 | Vector3d maxPosition = new Vector3d(xmax, ymax, 4096.0); | ||
286 | |||
287 | NameValueCollection requestArgs = new NameValueCollection | ||
288 | { | ||
289 | { "RequestMethod", "GetScenes" }, | ||
290 | { "MinPosition", minPosition.ToString() }, | ||
291 | { "MaxPosition", maxPosition.ToString() }, | ||
292 | { "Enabled", "1" } | ||
293 | }; | ||
294 | |||
295 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
296 | if (response["Success"].AsBoolean()) | ||
297 | { | ||
298 | OSDArray array = response["Scenes"] as OSDArray; | ||
299 | if (array != null) | ||
300 | { | ||
301 | for (int i = 0; i < array.Count; i++) | ||
302 | { | ||
303 | GridRegion region = ResponseToGridRegion(array[i] as OSDMap); | ||
304 | if (region != null) | ||
305 | foundRegions.Add(region); | ||
306 | } | ||
307 | } | ||
308 | } | ||
309 | |||
310 | return foundRegions; | ||
311 | } | ||
312 | |||
313 | public List<GridRegion> GetDefaultRegions(UUID scopeID) | ||
314 | { | ||
315 | // TODO: Allow specifying the default grid location | ||
316 | const int DEFAULT_X = 1000 * 256; | ||
317 | const int DEFAULT_Y = 1000 * 256; | ||
318 | |||
319 | GridRegion defRegion = GetNearestRegion(new Vector3d(DEFAULT_X, DEFAULT_Y, 0.0), true); | ||
320 | if (defRegion != null) | ||
321 | return new List<GridRegion>(1) { defRegion }; | ||
322 | else | ||
323 | return new List<GridRegion>(0); | ||
324 | } | ||
325 | |||
326 | public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) | ||
327 | { | ||
328 | GridRegion defRegion = GetNearestRegion(new Vector3d(x, y, 0.0), true); | ||
329 | if (defRegion != null) | ||
330 | return new List<GridRegion>(1) { defRegion }; | ||
331 | else | ||
332 | return new List<GridRegion>(0); | ||
333 | } | ||
334 | |||
335 | public int GetRegionFlags(UUID scopeID, UUID regionID) | ||
336 | { | ||
337 | const int REGION_ONLINE = 4; | ||
338 | |||
339 | NameValueCollection requestArgs = new NameValueCollection | ||
340 | { | ||
341 | { "RequestMethod", "GetScene" }, | ||
342 | { "SceneID", regionID.ToString() } | ||
343 | }; | ||
344 | |||
345 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
346 | if (response["Success"].AsBoolean()) | ||
347 | { | ||
348 | return response["Enabled"].AsBoolean() ? REGION_ONLINE : 0; | ||
349 | } | ||
350 | else | ||
351 | { | ||
352 | m_log.Warn("[GRID CONNECTOR]: Grid service did not find a match for region " + regionID + " during region flags check"); | ||
353 | return -1; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | #endregion IGridService | ||
358 | |||
359 | private GridRegion GetNearestRegion(Vector3d position, bool onlyEnabled) | ||
360 | { | ||
361 | NameValueCollection requestArgs = new NameValueCollection | ||
362 | { | ||
363 | { "RequestMethod", "GetScene" }, | ||
364 | { "Position", position.ToString() }, | ||
365 | { "FindClosest", "1" } | ||
366 | }; | ||
367 | if (onlyEnabled) | ||
368 | requestArgs["Enabled"] = "1"; | ||
369 | |||
370 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
371 | if (response["Success"].AsBoolean()) | ||
372 | { | ||
373 | return ResponseToGridRegion(response); | ||
374 | } | ||
375 | else | ||
376 | { | ||
377 | m_log.Warn("[GRID CONNECTOR]: Grid service did not find a match for region at " + position); | ||
378 | return null; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | private GridRegion ResponseToGridRegion(OSDMap response) | ||
383 | { | ||
384 | if (response == null) | ||
385 | return null; | ||
386 | |||
387 | OSDMap extraData = response["ExtraData"] as OSDMap; | ||
388 | if (extraData == null) | ||
389 | return null; | ||
390 | |||
391 | GridRegion region = new GridRegion(); | ||
392 | |||
393 | region.RegionID = response["SceneID"].AsUUID(); | ||
394 | region.RegionName = response["Name"].AsString(); | ||
395 | |||
396 | Vector3d minPosition = response["MinPosition"].AsVector3d(); | ||
397 | region.RegionLocX = (int)minPosition.X; | ||
398 | region.RegionLocY = (int)minPosition.Y; | ||
399 | |||
400 | Uri httpAddress = response["Address"].AsUri(); | ||
401 | region.ExternalHostName = httpAddress.Host; | ||
402 | region.HttpPort = (uint)httpAddress.Port; | ||
403 | |||
404 | region.ServerURI = extraData["ServerURI"].AsString(); | ||
405 | |||
406 | IPAddress internalAddress; | ||
407 | IPAddress.TryParse(extraData["InternalAddress"].AsString(), out internalAddress); | ||
408 | if (internalAddress == null) | ||
409 | internalAddress = IPAddress.Any; | ||
410 | |||
411 | region.InternalEndPoint = new IPEndPoint(internalAddress, extraData["InternalPort"].AsInteger()); | ||
412 | region.TerrainImage = extraData["MapTexture"].AsUUID(); | ||
413 | region.Access = (byte)extraData["Access"].AsInteger(); | ||
414 | region.RegionSecret = extraData["RegionSecret"].AsString(); | ||
415 | region.EstateOwner = extraData["EstateOwner"].AsUUID(); | ||
416 | region.Token = extraData["Token"].AsString(); | ||
417 | |||
418 | return region; | ||
419 | } | ||
420 | } | ||
421 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs new file mode 100644 index 0000000..891782f --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs | |||
@@ -0,0 +1,895 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | using Mono.Addins; | ||
34 | using Nini.Config; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Server.Base; | ||
41 | using OpenSim.Services.Interfaces; | ||
42 | |||
43 | namespace OpenSim.Services.Connectors.SimianGrid | ||
44 | { | ||
45 | /// <summary> | ||
46 | /// Permissions bitflags | ||
47 | /// </summary> | ||
48 | [Flags] | ||
49 | public enum PermissionMask : uint | ||
50 | { | ||
51 | None = 0, | ||
52 | Transfer = 1 << 13, | ||
53 | Modify = 1 << 14, | ||
54 | Copy = 1 << 15, | ||
55 | Move = 1 << 19, | ||
56 | Damage = 1 << 20, | ||
57 | All = 0x7FFFFFFF | ||
58 | } | ||
59 | |||
60 | /// <summary> | ||
61 | /// Connects avatar inventories to the SimianGrid backend | ||
62 | /// </summary> | ||
63 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
64 | public class SimianInventoryServiceConnector : IInventoryService, ISharedRegionModule | ||
65 | { | ||
66 | private static readonly ILog m_log = | ||
67 | LogManager.GetLogger( | ||
68 | MethodBase.GetCurrentMethod().DeclaringType); | ||
69 | |||
70 | private string m_serverUrl = String.Empty; | ||
71 | private string m_userServerUrl = String.Empty; | ||
72 | private object m_gestureSyncRoot = new object(); | ||
73 | |||
74 | #region ISharedRegionModule | ||
75 | |||
76 | public Type ReplaceableInterface { get { return null; } } | ||
77 | public void RegionLoaded(Scene scene) { } | ||
78 | public void PostInitialise() { } | ||
79 | public void Close() { } | ||
80 | |||
81 | public SimianInventoryServiceConnector() { } | ||
82 | public string Name { get { return "SimianInventoryServiceConnector"; } } | ||
83 | public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface<IInventoryService>(this); } } | ||
84 | public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface<IInventoryService>(this); } } | ||
85 | |||
86 | #endregion ISharedRegionModule | ||
87 | |||
88 | public SimianInventoryServiceConnector(IConfigSource source) | ||
89 | { | ||
90 | Initialise(source); | ||
91 | } | ||
92 | |||
93 | public void Initialise(IConfigSource source) | ||
94 | { | ||
95 | if (Simian.IsSimianEnabled(source, "InventoryServices")) | ||
96 | { | ||
97 | IConfig gridConfig = source.Configs["InventoryService"]; | ||
98 | if (gridConfig == null) | ||
99 | { | ||
100 | m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); | ||
101 | throw new Exception("Inventory connector init error"); | ||
102 | } | ||
103 | |||
104 | string serviceUrl = gridConfig.GetString("InventoryServerURI"); | ||
105 | if (String.IsNullOrEmpty(serviceUrl)) | ||
106 | { | ||
107 | m_log.Error("[INVENTORY CONNECTOR]: No Server URI named in section InventoryService"); | ||
108 | throw new Exception("Inventory connector init error"); | ||
109 | } | ||
110 | |||
111 | m_serverUrl = serviceUrl; | ||
112 | |||
113 | gridConfig = source.Configs["UserAccountService"]; | ||
114 | if (gridConfig != null) | ||
115 | { | ||
116 | serviceUrl = gridConfig.GetString("UserAccountServerURI"); | ||
117 | if (!String.IsNullOrEmpty(serviceUrl)) | ||
118 | m_userServerUrl = serviceUrl; | ||
119 | else | ||
120 | m_log.Info("[INVENTORY CONNECTOR]: No Server URI named in section UserAccountService"); | ||
121 | } | ||
122 | else | ||
123 | { | ||
124 | m_log.Warn("[INVENTORY CONNECTOR]: UserAccountService missing from OpenSim.ini"); | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
129 | /// <summary> | ||
130 | /// Create the entire inventory for a given user | ||
131 | /// </summary> | ||
132 | /// <param name="user"></param> | ||
133 | /// <returns></returns> | ||
134 | public bool CreateUserInventory(UUID userID) | ||
135 | { | ||
136 | NameValueCollection requestArgs = new NameValueCollection | ||
137 | { | ||
138 | { "RequestMethod", "AddInventory" }, | ||
139 | { "OwnerID", userID.ToString() } | ||
140 | }; | ||
141 | |||
142 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
143 | bool success = response["Success"].AsBoolean(); | ||
144 | |||
145 | if (!success) | ||
146 | m_log.Warn("[INVENTORY CONNECTOR]: Inventory creation for " + userID + " failed: " + response["Message"].AsString()); | ||
147 | |||
148 | return success; | ||
149 | } | ||
150 | |||
151 | /// <summary> | ||
152 | /// Gets the skeleton of the inventory -- folders only | ||
153 | /// </summary> | ||
154 | /// <param name="userID"></param> | ||
155 | /// <returns></returns> | ||
156 | public List<InventoryFolderBase> GetInventorySkeleton(UUID userID) | ||
157 | { | ||
158 | NameValueCollection requestArgs = new NameValueCollection | ||
159 | { | ||
160 | { "RequestMethod", "GetInventoryNode" }, | ||
161 | { "ItemID", userID.ToString() }, | ||
162 | { "OwnerID", userID.ToString() }, | ||
163 | { "IncludeFolders", "1" }, | ||
164 | { "IncludeItems", "0" }, | ||
165 | { "ChildrenOnly", "0" } | ||
166 | }; | ||
167 | |||
168 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
169 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
170 | { | ||
171 | OSDArray items = (OSDArray)response["Items"]; | ||
172 | return GetFoldersFromResponse(items, userID, true); | ||
173 | } | ||
174 | else | ||
175 | { | ||
176 | m_log.Warn("[INVENTORY CONNECTOR]: Failed to retrieve inventory skeleton for " + userID + ": " + | ||
177 | response["Message"].AsString()); | ||
178 | return new List<InventoryFolderBase>(0); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | /// <summary> | ||
183 | /// Synchronous inventory fetch. | ||
184 | /// </summary> | ||
185 | /// <param name="userID"></param> | ||
186 | /// <returns></returns> | ||
187 | [Obsolete] | ||
188 | public InventoryCollection GetUserInventory(UUID userID) | ||
189 | { | ||
190 | m_log.Error("[INVENTORY CONNECTOR]: Obsolete GetUserInventory called for " + userID); | ||
191 | |||
192 | InventoryCollection inventory = new InventoryCollection(); | ||
193 | inventory.UserID = userID; | ||
194 | inventory.Folders = new List<InventoryFolderBase>(); | ||
195 | inventory.Items = new List<InventoryItemBase>(); | ||
196 | |||
197 | return inventory; | ||
198 | } | ||
199 | |||
200 | /// <summary> | ||
201 | /// Request the inventory for a user. This is an asynchronous operation that will call the callback when the | ||
202 | /// inventory has been received | ||
203 | /// </summary> | ||
204 | /// <param name="userID"></param> | ||
205 | /// <param name="callback"></param> | ||
206 | [Obsolete] | ||
207 | public void GetUserInventory(UUID userID, InventoryReceiptCallback callback) | ||
208 | { | ||
209 | m_log.Error("[INVENTORY CONNECTOR]: Obsolete GetUserInventory called for " + userID); | ||
210 | callback(new List<InventoryFolderImpl>(0), new List<InventoryItemBase>(0)); | ||
211 | } | ||
212 | |||
213 | /// <summary> | ||
214 | /// Retrieve the root inventory folder for the given user. | ||
215 | /// </summary> | ||
216 | /// <param name="userID"></param> | ||
217 | /// <returns>null if no root folder was found</returns> | ||
218 | public InventoryFolderBase GetRootFolder(UUID userID) | ||
219 | { | ||
220 | NameValueCollection requestArgs = new NameValueCollection | ||
221 | { | ||
222 | { "RequestMethod", "GetInventoryNode" }, | ||
223 | { "ItemID", userID.ToString() }, | ||
224 | { "OwnerID", userID.ToString() }, | ||
225 | { "IncludeFolders", "1" }, | ||
226 | { "IncludeItems", "0" }, | ||
227 | { "ChildrenOnly", "1" } | ||
228 | }; | ||
229 | |||
230 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
231 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
232 | { | ||
233 | OSDArray items = (OSDArray)response["Items"]; | ||
234 | List<InventoryFolderBase> folders = GetFoldersFromResponse(items, userID, true); | ||
235 | |||
236 | if (folders.Count > 0) | ||
237 | return folders[0]; | ||
238 | } | ||
239 | |||
240 | return null; | ||
241 | } | ||
242 | |||
243 | /// <summary> | ||
244 | /// Gets the user folder for the given folder-type | ||
245 | /// </summary> | ||
246 | /// <param name="userID"></param> | ||
247 | /// <param name="type"></param> | ||
248 | /// <returns></returns> | ||
249 | public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) | ||
250 | { | ||
251 | string contentType = SLUtil.SLAssetTypeToContentType((int)type); | ||
252 | |||
253 | NameValueCollection requestArgs = new NameValueCollection | ||
254 | { | ||
255 | { "RequestMethod", "GetFolderForType" }, | ||
256 | { "ContentType", contentType }, | ||
257 | { "OwnerID", userID.ToString() } | ||
258 | }; | ||
259 | |||
260 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
261 | if (response["Success"].AsBoolean() && response["Folder"] is OSDMap) | ||
262 | { | ||
263 | OSDMap folder = (OSDMap)response["Folder"]; | ||
264 | |||
265 | return new InventoryFolderBase( | ||
266 | folder["ID"].AsUUID(), | ||
267 | folder["Name"].AsString(), | ||
268 | folder["OwnerID"].AsUUID(), | ||
269 | (short)SLUtil.ContentTypeToSLAssetType(folder["ContentType"].AsString()), | ||
270 | folder["ParentID"].AsUUID(), | ||
271 | (ushort)folder["Version"].AsInteger() | ||
272 | ); | ||
273 | } | ||
274 | else | ||
275 | { | ||
276 | m_log.Warn("[INVENTORY CONNECTOR]: Default folder not found for content type " + contentType); | ||
277 | return GetRootFolder(userID); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | /// <summary> | ||
282 | /// Get an item, given by its UUID | ||
283 | /// </summary> | ||
284 | /// <param name="item"></param> | ||
285 | /// <returns></returns> | ||
286 | public InventoryItemBase GetItem(InventoryItemBase item) | ||
287 | { | ||
288 | NameValueCollection requestArgs = new NameValueCollection | ||
289 | { | ||
290 | { "RequestMethod", "GetInventoryNode" }, | ||
291 | { "ItemID", item.ID.ToString() }, | ||
292 | { "OwnerID", item.Owner.ToString() }, | ||
293 | { "IncludeFolders", "1" }, | ||
294 | { "IncludeItems", "1" }, | ||
295 | { "ChildrenOnly", "1" } | ||
296 | }; | ||
297 | |||
298 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
299 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
300 | { | ||
301 | List<InventoryItemBase> items = GetItemsFromResponse((OSDArray)response["Items"]); | ||
302 | if (items.Count > 0) | ||
303 | { | ||
304 | // The requested item should be the first in this list, but loop through | ||
305 | // and sanity check just in case | ||
306 | for (int i = 0; i < items.Count; i++) | ||
307 | { | ||
308 | if (items[i].ID == item.ID) | ||
309 | return items[i]; | ||
310 | } | ||
311 | } | ||
312 | } | ||
313 | |||
314 | m_log.Warn("[INVENTORY CONNECTOR]: Item " + item.ID + " owned by " + item.Owner + " not found"); | ||
315 | return null; | ||
316 | } | ||
317 | |||
318 | /// <summary> | ||
319 | /// Get a folder, given by its UUID | ||
320 | /// </summary> | ||
321 | /// <param name="folder"></param> | ||
322 | /// <returns></returns> | ||
323 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) | ||
324 | { | ||
325 | NameValueCollection requestArgs = new NameValueCollection | ||
326 | { | ||
327 | { "RequestMethod", "GetInventoryNode" }, | ||
328 | { "ItemID", folder.ID.ToString() }, | ||
329 | { "OwnerID", folder.Owner.ToString() }, | ||
330 | { "IncludeFolders", "1" }, | ||
331 | { "IncludeItems", "0" }, | ||
332 | { "ChildrenOnly", "1" } | ||
333 | }; | ||
334 | |||
335 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
336 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
337 | { | ||
338 | OSDArray items = (OSDArray)response["Items"]; | ||
339 | List<InventoryFolderBase> folders = GetFoldersFromResponse(items, folder.ID, true); | ||
340 | |||
341 | if (folders.Count > 0) | ||
342 | return folders[0]; | ||
343 | } | ||
344 | |||
345 | return null; | ||
346 | } | ||
347 | |||
348 | /// <summary> | ||
349 | /// Gets everything (folders and items) inside a folder | ||
350 | /// </summary> | ||
351 | /// <param name="userID"></param> | ||
352 | /// <param name="folderID"></param> | ||
353 | /// <returns></returns> | ||
354 | public InventoryCollection GetFolderContent(UUID userID, UUID folderID) | ||
355 | { | ||
356 | InventoryCollection inventory = new InventoryCollection(); | ||
357 | inventory.UserID = userID; | ||
358 | |||
359 | NameValueCollection requestArgs = new NameValueCollection | ||
360 | { | ||
361 | { "RequestMethod", "GetInventoryNode" }, | ||
362 | { "ItemID", folderID.ToString() }, | ||
363 | { "OwnerID", userID.ToString() }, | ||
364 | { "IncludeFolders", "1" }, | ||
365 | { "IncludeItems", "1" }, | ||
366 | { "ChildrenOnly", "1" } | ||
367 | }; | ||
368 | |||
369 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
370 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
371 | { | ||
372 | OSDArray items = (OSDArray)response["Items"]; | ||
373 | |||
374 | inventory.Folders = GetFoldersFromResponse(items, folderID, false); | ||
375 | inventory.Items = GetItemsFromResponse(items); | ||
376 | } | ||
377 | else | ||
378 | { | ||
379 | m_log.Warn("[INVENTORY CONNECTOR]: Error fetching folder " + folderID + " content for " + userID + ": " + | ||
380 | response["Message"].AsString()); | ||
381 | inventory.Folders = new List<InventoryFolderBase>(0); | ||
382 | inventory.Items = new List<InventoryItemBase>(0); | ||
383 | } | ||
384 | |||
385 | return inventory; | ||
386 | } | ||
387 | |||
388 | /// <summary> | ||
389 | /// Gets the items inside a folder | ||
390 | /// </summary> | ||
391 | /// <param name="userID"></param> | ||
392 | /// <param name="folderID"></param> | ||
393 | /// <returns></returns> | ||
394 | public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) | ||
395 | { | ||
396 | InventoryCollection inventory = new InventoryCollection(); | ||
397 | inventory.UserID = userID; | ||
398 | |||
399 | NameValueCollection requestArgs = new NameValueCollection | ||
400 | { | ||
401 | { "RequestMethod", "GetInventoryNode" }, | ||
402 | { "ItemID", folderID.ToString() }, | ||
403 | { "OwnerID", userID.ToString() }, | ||
404 | { "IncludeFolders", "0" }, | ||
405 | { "IncludeItems", "1" }, | ||
406 | { "ChildrenOnly", "1" } | ||
407 | }; | ||
408 | |||
409 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
410 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
411 | { | ||
412 | OSDArray items = (OSDArray)response["Items"]; | ||
413 | return GetItemsFromResponse(items); | ||
414 | } | ||
415 | else | ||
416 | { | ||
417 | m_log.Warn("[INVENTORY CONNECTOR]: Error fetching folder " + folderID + " for " + userID + ": " + | ||
418 | response["Message"].AsString()); | ||
419 | return new List<InventoryItemBase>(0); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | /// <summary> | ||
424 | /// Add a new folder to the user's inventory | ||
425 | /// </summary> | ||
426 | /// <param name="folder"></param> | ||
427 | /// <returns>true if the folder was successfully added</returns> | ||
428 | public bool AddFolder(InventoryFolderBase folder) | ||
429 | { | ||
430 | NameValueCollection requestArgs = new NameValueCollection | ||
431 | { | ||
432 | { "RequestMethod", "AddInventoryFolder" }, | ||
433 | { "FolderID", folder.ID.ToString() }, | ||
434 | { "ParentID", folder.ParentID.ToString() }, | ||
435 | { "OwnerID", folder.Owner.ToString() }, | ||
436 | { "Name", folder.Name }, | ||
437 | { "ContentType", SLUtil.SLAssetTypeToContentType(folder.Type) } | ||
438 | }; | ||
439 | |||
440 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
441 | bool success = response["Success"].AsBoolean(); | ||
442 | |||
443 | if (!success) | ||
444 | { | ||
445 | m_log.Warn("[INVENTORY CONNECTOR]: Error creating folder " + folder.Name + " for " + folder.Owner + ": " + | ||
446 | response["Message"].AsString()); | ||
447 | } | ||
448 | |||
449 | return success; | ||
450 | } | ||
451 | |||
452 | /// <summary> | ||
453 | /// Update a folder in the user's inventory | ||
454 | /// </summary> | ||
455 | /// <param name="folder"></param> | ||
456 | /// <returns>true if the folder was successfully updated</returns> | ||
457 | public bool UpdateFolder(InventoryFolderBase folder) | ||
458 | { | ||
459 | return AddFolder(folder); | ||
460 | } | ||
461 | |||
462 | /// <summary> | ||
463 | /// Move an inventory folder to a new location | ||
464 | /// </summary> | ||
465 | /// <param name="folder">A folder containing the details of the new location</param> | ||
466 | /// <returns>true if the folder was successfully moved</returns> | ||
467 | public bool MoveFolder(InventoryFolderBase folder) | ||
468 | { | ||
469 | return AddFolder(folder); | ||
470 | } | ||
471 | |||
472 | /// <summary> | ||
473 | /// Delete an item from the user's inventory | ||
474 | /// </summary> | ||
475 | /// <param name="item"></param> | ||
476 | /// <returns>true if the item was successfully deleted</returns> | ||
477 | //bool DeleteItem(InventoryItemBase item); | ||
478 | public bool DeleteFolders(UUID userID, List<UUID> folderIDs) | ||
479 | { | ||
480 | return DeleteItems(userID, folderIDs); | ||
481 | } | ||
482 | |||
483 | /// <summary> | ||
484 | /// Delete an item from the user's inventory | ||
485 | /// </summary> | ||
486 | /// <param name="item"></param> | ||
487 | /// <returns>true if the item was successfully deleted</returns> | ||
488 | public bool DeleteItems(UUID userID, List<UUID> itemIDs) | ||
489 | { | ||
490 | // TODO: RemoveInventoryNode should be replaced with RemoveInventoryNodes | ||
491 | bool allSuccess = true; | ||
492 | |||
493 | for (int i = 0; i < itemIDs.Count; i++) | ||
494 | { | ||
495 | UUID itemID = itemIDs[i]; | ||
496 | |||
497 | NameValueCollection requestArgs = new NameValueCollection | ||
498 | { | ||
499 | { "RequestMethod", "RemoveInventoryNode" }, | ||
500 | { "OwnerID", userID.ToString() }, | ||
501 | { "ItemID", itemID.ToString() } | ||
502 | }; | ||
503 | |||
504 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
505 | bool success = response["Success"].AsBoolean(); | ||
506 | |||
507 | if (!success) | ||
508 | { | ||
509 | m_log.Warn("[INVENTORY CONNECTOR]: Error removing item " + itemID + " for " + userID + ": " + | ||
510 | response["Message"].AsString()); | ||
511 | allSuccess = false; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | return allSuccess; | ||
516 | } | ||
517 | |||
518 | /// <summary> | ||
519 | /// Purge an inventory folder of all its items and subfolders. | ||
520 | /// </summary> | ||
521 | /// <param name="folder"></param> | ||
522 | /// <returns>true if the folder was successfully purged</returns> | ||
523 | public bool PurgeFolder(InventoryFolderBase folder) | ||
524 | { | ||
525 | NameValueCollection requestArgs = new NameValueCollection | ||
526 | { | ||
527 | { "RequestMethod", "PurgeInventoryFolder" }, | ||
528 | { "OwnerID", folder.Owner.ToString() }, | ||
529 | { "FolderID", folder.ID.ToString() } | ||
530 | }; | ||
531 | |||
532 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
533 | bool success = response["Success"].AsBoolean(); | ||
534 | |||
535 | if (!success) | ||
536 | { | ||
537 | m_log.Warn("[INVENTORY CONNECTOR]: Error purging folder " + folder.ID + " for " + folder.Owner + ": " + | ||
538 | response["Message"].AsString()); | ||
539 | } | ||
540 | |||
541 | return success; | ||
542 | } | ||
543 | |||
544 | /// <summary> | ||
545 | /// Add a new item to the user's inventory | ||
546 | /// </summary> | ||
547 | /// <param name="item"></param> | ||
548 | /// <returns>true if the item was successfully added</returns> | ||
549 | public bool AddItem(InventoryItemBase item) | ||
550 | { | ||
551 | // A folder of UUID.Zero means we need to find the most appropriate home for this item | ||
552 | if (item.Folder == UUID.Zero) | ||
553 | { | ||
554 | InventoryFolderBase folder = GetFolderForType(item.Owner, (AssetType)item.AssetType); | ||
555 | if (folder != null && folder.ID != UUID.Zero) | ||
556 | item.Folder = folder.ID; | ||
557 | else | ||
558 | item.Folder = item.Owner; // Root folder | ||
559 | } | ||
560 | |||
561 | if ((AssetType)item.AssetType == AssetType.Gesture) | ||
562 | UpdateGesture(item.Owner, item.ID, item.Flags == 1); | ||
563 | |||
564 | if (item.BasePermissions == 0) | ||
565 | m_log.WarnFormat("[INVENTORY CONNECTOR]: Adding inventory item {0} ({1}) with no base permissions", item.Name, item.ID); | ||
566 | |||
567 | OSDMap permissions = new OSDMap | ||
568 | { | ||
569 | { "BaseMask", OSD.FromInteger(item.BasePermissions) }, | ||
570 | { "EveryoneMask", OSD.FromInteger(item.EveryOnePermissions) }, | ||
571 | { "GroupMask", OSD.FromInteger(item.GroupPermissions) }, | ||
572 | { "NextOwnerMask", OSD.FromInteger(item.NextPermissions) }, | ||
573 | { "OwnerMask", OSD.FromInteger(item.CurrentPermissions) } | ||
574 | }; | ||
575 | |||
576 | OSDMap extraData = new OSDMap() | ||
577 | { | ||
578 | { "Flags", OSD.FromInteger(item.Flags) }, | ||
579 | { "GroupID", OSD.FromUUID(item.GroupID) }, | ||
580 | { "GroupOwned", OSD.FromBoolean(item.GroupOwned) }, | ||
581 | { "SalePrice", OSD.FromInteger(item.SalePrice) }, | ||
582 | { "SaleType", OSD.FromInteger(item.SaleType) }, | ||
583 | { "Permissions", permissions } | ||
584 | }; | ||
585 | |||
586 | NameValueCollection requestArgs = new NameValueCollection | ||
587 | { | ||
588 | { "RequestMethod", "AddInventoryItem" }, | ||
589 | { "ItemID", item.ID.ToString() }, | ||
590 | { "AssetID", item.AssetID.ToString() }, | ||
591 | { "ParentID", item.Folder.ToString() }, | ||
592 | { "OwnerID", item.Owner.ToString() }, | ||
593 | { "Name", item.Name }, | ||
594 | { "Description", item.Description }, | ||
595 | { "CreatorID", item.CreatorId }, | ||
596 | { "ExtraData", OSDParser.SerializeJsonString(extraData) } | ||
597 | }; | ||
598 | |||
599 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
600 | bool success = response["Success"].AsBoolean(); | ||
601 | |||
602 | if (!success) | ||
603 | { | ||
604 | m_log.Warn("[INVENTORY CONNECTOR]: Error creating item " + item.Name + " for " + item.Owner + ": " + | ||
605 | response["Message"].AsString()); | ||
606 | } | ||
607 | |||
608 | return success; | ||
609 | } | ||
610 | |||
611 | /// <summary> | ||
612 | /// Update an item in the user's inventory | ||
613 | /// </summary> | ||
614 | /// <param name="item"></param> | ||
615 | /// <returns>true if the item was successfully updated</returns> | ||
616 | public bool UpdateItem(InventoryItemBase item) | ||
617 | { | ||
618 | if (item.AssetID != UUID.Zero) | ||
619 | { | ||
620 | return AddItem(item); | ||
621 | } | ||
622 | else | ||
623 | { | ||
624 | // This is actually a folder update | ||
625 | InventoryFolderBase folder = new InventoryFolderBase(item.ID, item.Name, item.Owner, (short)item.AssetType, item.Folder, 0); | ||
626 | return UpdateFolder(folder); | ||
627 | } | ||
628 | } | ||
629 | |||
630 | public bool MoveItems(UUID ownerID, List<InventoryItemBase> items) | ||
631 | { | ||
632 | bool success = true; | ||
633 | |||
634 | while (items.Count > 0) | ||
635 | { | ||
636 | List<InventoryItemBase> currentItems = new List<InventoryItemBase>(); | ||
637 | UUID destFolderID = items[0].Folder; | ||
638 | |||
639 | // Find all of the items being moved to the current destination folder | ||
640 | for (int i = 0; i < items.Count; i++) | ||
641 | { | ||
642 | InventoryItemBase item = items[i]; | ||
643 | if (item.Folder == destFolderID) | ||
644 | currentItems.Add(item); | ||
645 | } | ||
646 | |||
647 | // Do the inventory move for the current items | ||
648 | success &= MoveItems(ownerID, items, destFolderID); | ||
649 | |||
650 | // Remove the processed items from the list | ||
651 | for (int i = 0; i < currentItems.Count; i++) | ||
652 | items.Remove(currentItems[i]); | ||
653 | } | ||
654 | |||
655 | return success; | ||
656 | } | ||
657 | |||
658 | /// <summary> | ||
659 | /// Does the given user have an inventory structure? | ||
660 | /// </summary> | ||
661 | /// <param name="userID"></param> | ||
662 | /// <returns></returns> | ||
663 | public bool HasInventoryForUser(UUID userID) | ||
664 | { | ||
665 | return GetRootFolder(userID) != null; | ||
666 | } | ||
667 | |||
668 | /// <summary> | ||
669 | /// Get the active gestures of the agent. | ||
670 | /// </summary> | ||
671 | /// <param name="userID"></param> | ||
672 | /// <returns></returns> | ||
673 | public List<InventoryItemBase> GetActiveGestures(UUID userID) | ||
674 | { | ||
675 | OSDArray items = FetchGestures(userID); | ||
676 | |||
677 | string[] itemIDs = new string[items.Count]; | ||
678 | for (int i = 0; i < items.Count; i++) | ||
679 | itemIDs[i] = items[i].AsUUID().ToString(); | ||
680 | |||
681 | NameValueCollection requestArgs = new NameValueCollection | ||
682 | { | ||
683 | { "RequestMethod", "GetInventoryNodes" }, | ||
684 | { "OwnerID", userID.ToString() }, | ||
685 | { "Items", String.Join(",", itemIDs) } | ||
686 | }; | ||
687 | |||
688 | // FIXME: Implement this in SimianGrid | ||
689 | return new List<InventoryItemBase>(0); | ||
690 | } | ||
691 | |||
692 | /// <summary> | ||
693 | /// Get the union of permissions of all inventory items | ||
694 | /// that hold the given assetID. | ||
695 | /// </summary> | ||
696 | /// <param name="userID"></param> | ||
697 | /// <param name="assetID"></param> | ||
698 | /// <returns>The permissions or 0 if no such asset is found in | ||
699 | /// the user's inventory</returns> | ||
700 | public int GetAssetPermissions(UUID userID, UUID assetID) | ||
701 | { | ||
702 | NameValueCollection requestArgs = new NameValueCollection | ||
703 | { | ||
704 | { "RequestMethod", "GetInventoryNodes" }, | ||
705 | { "OwnerID", userID.ToString() }, | ||
706 | { "AssetID", assetID.ToString() } | ||
707 | }; | ||
708 | |||
709 | // FIXME: Implement this in SimianGrid | ||
710 | return (int)PermissionMask.All; | ||
711 | } | ||
712 | |||
713 | private List<InventoryFolderBase> GetFoldersFromResponse(OSDArray items, UUID baseFolder, bool includeBaseFolder) | ||
714 | { | ||
715 | List<InventoryFolderBase> invFolders = new List<InventoryFolderBase>(items.Count); | ||
716 | |||
717 | for (int i = 0; i < items.Count; i++) | ||
718 | { | ||
719 | OSDMap item = items[i] as OSDMap; | ||
720 | |||
721 | if (item != null && item["Type"].AsString() == "Folder") | ||
722 | { | ||
723 | UUID folderID = item["ID"].AsUUID(); | ||
724 | |||
725 | if (folderID == baseFolder && !includeBaseFolder) | ||
726 | continue; | ||
727 | |||
728 | invFolders.Add(new InventoryFolderBase( | ||
729 | folderID, | ||
730 | item["Name"].AsString(), | ||
731 | item["OwnerID"].AsUUID(), | ||
732 | (short)SLUtil.ContentTypeToSLAssetType(item["ContentType"].AsString()), | ||
733 | item["ParentID"].AsUUID(), | ||
734 | (ushort)item["Version"].AsInteger() | ||
735 | )); | ||
736 | } | ||
737 | } | ||
738 | |||
739 | return invFolders; | ||
740 | } | ||
741 | |||
742 | private List<InventoryItemBase> GetItemsFromResponse(OSDArray items) | ||
743 | { | ||
744 | List<InventoryItemBase> invItems = new List<InventoryItemBase>(items.Count); | ||
745 | |||
746 | for (int i = 0; i < items.Count; i++) | ||
747 | { | ||
748 | OSDMap item = items[i] as OSDMap; | ||
749 | |||
750 | if (item != null && item["Type"].AsString() == "Item") | ||
751 | { | ||
752 | InventoryItemBase invItem = new InventoryItemBase(); | ||
753 | |||
754 | invItem.AssetID = item["AssetID"].AsUUID(); | ||
755 | invItem.AssetType = SLUtil.ContentTypeToSLAssetType(item["ContentType"].AsString()); | ||
756 | invItem.CreationDate = item["CreationDate"].AsInteger(); | ||
757 | invItem.CreatorId = item["CreatorID"].AsString(); | ||
758 | invItem.CreatorIdAsUuid = item["CreatorID"].AsUUID(); | ||
759 | invItem.Description = item["Description"].AsString(); | ||
760 | invItem.Folder = item["ParentID"].AsUUID(); | ||
761 | invItem.ID = item["ID"].AsUUID(); | ||
762 | invItem.InvType = SLUtil.ContentTypeToSLInvType(item["ContentType"].AsString()); | ||
763 | invItem.Name = item["Name"].AsString(); | ||
764 | invItem.Owner = item["OwnerID"].AsUUID(); | ||
765 | |||
766 | OSDMap extraData = item["ExtraData"] as OSDMap; | ||
767 | if (extraData != null && extraData.Count > 0) | ||
768 | { | ||
769 | invItem.Flags = extraData["Flags"].AsUInteger(); | ||
770 | invItem.GroupID = extraData["GroupID"].AsUUID(); | ||
771 | invItem.GroupOwned = extraData["GroupOwned"].AsBoolean(); | ||
772 | invItem.SalePrice = extraData["SalePrice"].AsInteger(); | ||
773 | invItem.SaleType = (byte)extraData["SaleType"].AsInteger(); | ||
774 | |||
775 | OSDMap perms = extraData["Permissions"] as OSDMap; | ||
776 | if (perms != null) | ||
777 | { | ||
778 | invItem.BasePermissions = perms["BaseMask"].AsUInteger(); | ||
779 | invItem.CurrentPermissions = perms["OwnerMask"].AsUInteger(); | ||
780 | invItem.EveryOnePermissions = perms["EveryoneMask"].AsUInteger(); | ||
781 | invItem.GroupPermissions = perms["GroupMask"].AsUInteger(); | ||
782 | invItem.NextPermissions = perms["NextOwnerMask"].AsUInteger(); | ||
783 | } | ||
784 | } | ||
785 | |||
786 | if (invItem.BasePermissions == 0) | ||
787 | { | ||
788 | m_log.InfoFormat("[INVENTORY CONNECTOR]: Forcing item permissions to full for item {0} ({1})", | ||
789 | invItem.Name, invItem.ID); | ||
790 | invItem.BasePermissions = (uint)PermissionMask.All; | ||
791 | invItem.CurrentPermissions = (uint)PermissionMask.All; | ||
792 | invItem.EveryOnePermissions = (uint)PermissionMask.All; | ||
793 | invItem.GroupPermissions = (uint)PermissionMask.All; | ||
794 | invItem.NextPermissions = (uint)PermissionMask.All; | ||
795 | } | ||
796 | |||
797 | invItems.Add(invItem); | ||
798 | } | ||
799 | } | ||
800 | |||
801 | return invItems; | ||
802 | } | ||
803 | |||
804 | private bool MoveItems(UUID ownerID, List<InventoryItemBase> items, UUID destFolderID) | ||
805 | { | ||
806 | string[] itemIDs = new string[items.Count]; | ||
807 | for (int i = 0; i < items.Count; i++) | ||
808 | itemIDs[i] = items[i].ID.ToString(); | ||
809 | |||
810 | NameValueCollection requestArgs = new NameValueCollection | ||
811 | { | ||
812 | { "RequestMethod", "MoveInventoryNodes" }, | ||
813 | { "OwnerID", ownerID.ToString() }, | ||
814 | { "FolderID", destFolderID.ToString() }, | ||
815 | { "Items", String.Join(",", itemIDs) } | ||
816 | }; | ||
817 | |||
818 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
819 | bool success = response["Success"].AsBoolean(); | ||
820 | |||
821 | if (!success) | ||
822 | { | ||
823 | m_log.Warn("[INVENTORY CONNECTOR]: Failed to move " + items.Count + " items to " + | ||
824 | destFolderID + ": " + response["Message"].AsString()); | ||
825 | } | ||
826 | |||
827 | return success; | ||
828 | } | ||
829 | |||
830 | private void UpdateGesture(UUID userID, UUID itemID, bool enabled) | ||
831 | { | ||
832 | OSDArray gestures = FetchGestures(userID); | ||
833 | OSDArray newGestures = new OSDArray(); | ||
834 | |||
835 | for (int i = 0; i < gestures.Count; i++) | ||
836 | { | ||
837 | UUID gesture = gestures[i].AsUUID(); | ||
838 | if (gesture != itemID) | ||
839 | newGestures.Add(OSD.FromUUID(gesture)); | ||
840 | } | ||
841 | |||
842 | if (enabled) | ||
843 | newGestures.Add(OSD.FromUUID(itemID)); | ||
844 | |||
845 | SaveGestures(userID, newGestures); | ||
846 | } | ||
847 | |||
848 | private OSDArray FetchGestures(UUID userID) | ||
849 | { | ||
850 | NameValueCollection requestArgs = new NameValueCollection | ||
851 | { | ||
852 | { "RequestMethod", "GetUser" }, | ||
853 | { "UserID", userID.ToString() } | ||
854 | }; | ||
855 | |||
856 | OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs); | ||
857 | if (response["Success"].AsBoolean()) | ||
858 | { | ||
859 | OSDMap user = response["User"] as OSDMap; | ||
860 | if (user != null && response.ContainsKey("Gestures")) | ||
861 | { | ||
862 | OSD gestures = OSDParser.DeserializeJson(response["Gestures"].AsString()); | ||
863 | if (gestures != null && gestures is OSDArray) | ||
864 | return (OSDArray)gestures; | ||
865 | else | ||
866 | m_log.Error("[INVENTORY CONNECTOR]: Unrecognized active gestures data for " + userID); | ||
867 | } | ||
868 | } | ||
869 | else | ||
870 | { | ||
871 | m_log.Warn("[INVENTORY CONNECTOR]: Failed to fetch active gestures for " + userID + ": " + | ||
872 | response["Message"].AsString()); | ||
873 | } | ||
874 | |||
875 | return new OSDArray(); | ||
876 | } | ||
877 | |||
878 | private void SaveGestures(UUID userID, OSDArray gestures) | ||
879 | { | ||
880 | NameValueCollection requestArgs = new NameValueCollection | ||
881 | { | ||
882 | { "RequestMethod", "AddUserData" }, | ||
883 | { "UserID", userID.ToString() }, | ||
884 | { "Gestures", OSDParser.SerializeJsonString(gestures) } | ||
885 | }; | ||
886 | |||
887 | OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs); | ||
888 | if (!response["Success"].AsBoolean()) | ||
889 | { | ||
890 | m_log.Warn("[INVENTORY CONNECTOR]: Failed to save active gestures for " + userID + ": " + | ||
891 | response["Message"].AsString()); | ||
892 | } | ||
893 | } | ||
894 | } | ||
895 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs new file mode 100644 index 0000000..1b5edf4 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs | |||
@@ -0,0 +1,511 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using log4net; | ||
34 | using Mono.Addins; | ||
35 | using Nini.Config; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Servers.HttpServer; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using OpenSim.Server.Base; | ||
42 | using OpenMetaverse; | ||
43 | using OpenMetaverse.StructuredData; | ||
44 | |||
45 | using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; | ||
46 | |||
47 | namespace OpenSim.Services.Connectors.SimianGrid | ||
48 | { | ||
49 | /// <summary> | ||
50 | /// Connects avatar presence information (for tracking current location and | ||
51 | /// message routing) to the SimianGrid backend | ||
52 | /// </summary> | ||
53 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
54 | public class SimianPresenceServiceConnector : IPresenceService, ISharedRegionModule | ||
55 | { | ||
56 | private static readonly ILog m_log = | ||
57 | LogManager.GetLogger( | ||
58 | MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | |||
60 | private string m_serverUrl = String.Empty; | ||
61 | |||
62 | #region ISharedRegionModule | ||
63 | |||
64 | public Type ReplaceableInterface { get { return null; } } | ||
65 | public void RegionLoaded(Scene scene) { } | ||
66 | public void PostInitialise() { } | ||
67 | public void Close() { } | ||
68 | |||
69 | public SimianPresenceServiceConnector() { } | ||
70 | public string Name { get { return "SimianPresenceServiceConnector"; } } | ||
71 | public void AddRegion(Scene scene) | ||
72 | { | ||
73 | if (!String.IsNullOrEmpty(m_serverUrl)) | ||
74 | { | ||
75 | scene.RegisterModuleInterface<IPresenceService>(this); | ||
76 | |||
77 | scene.EventManager.OnMakeRootAgent += MakeRootAgentHandler; | ||
78 | scene.EventManager.OnNewClient += NewClientHandler; | ||
79 | scene.EventManager.OnSignificantClientMovement += SignificantClientMovementHandler; | ||
80 | |||
81 | LogoutRegionAgents(scene.RegionInfo.RegionID); | ||
82 | } | ||
83 | } | ||
84 | public void RemoveRegion(Scene scene) | ||
85 | { | ||
86 | if (!String.IsNullOrEmpty(m_serverUrl)) | ||
87 | { | ||
88 | scene.UnregisterModuleInterface<IPresenceService>(this); | ||
89 | |||
90 | scene.EventManager.OnMakeRootAgent -= MakeRootAgentHandler; | ||
91 | scene.EventManager.OnNewClient -= NewClientHandler; | ||
92 | scene.EventManager.OnSignificantClientMovement -= SignificantClientMovementHandler; | ||
93 | |||
94 | LogoutRegionAgents(scene.RegionInfo.RegionID); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | #endregion ISharedRegionModule | ||
99 | |||
100 | public SimianPresenceServiceConnector(IConfigSource source) | ||
101 | { | ||
102 | Initialise(source); | ||
103 | } | ||
104 | |||
105 | public void Initialise(IConfigSource source) | ||
106 | { | ||
107 | if (Simian.IsSimianEnabled(source, "PresenceServices")) | ||
108 | { | ||
109 | IConfig gridConfig = source.Configs["PresenceService"]; | ||
110 | if (gridConfig == null) | ||
111 | { | ||
112 | m_log.Error("[PRESENCE CONNECTOR]: PresenceService missing from OpenSim.ini"); | ||
113 | throw new Exception("Presence connector init error"); | ||
114 | } | ||
115 | |||
116 | string serviceUrl = gridConfig.GetString("PresenceServerURI"); | ||
117 | if (String.IsNullOrEmpty(serviceUrl)) | ||
118 | { | ||
119 | m_log.Error("[PRESENCE CONNECTOR]: No PresenceServerURI in section PresenceService"); | ||
120 | throw new Exception("Presence connector init error"); | ||
121 | } | ||
122 | |||
123 | m_serverUrl = serviceUrl; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | #region IPresenceService | ||
128 | |||
129 | public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID) | ||
130 | { | ||
131 | m_log.ErrorFormat("[PRESENCE CONNECTOR]: Login requested, UserID={0}, SessionID={1}, SecureSessionID={2}", | ||
132 | userID, sessionID, secureSessionID); | ||
133 | |||
134 | NameValueCollection requestArgs = new NameValueCollection | ||
135 | { | ||
136 | { "RequestMethod", "AddSession" }, | ||
137 | { "UserID", userID.ToString() } | ||
138 | }; | ||
139 | if (sessionID != UUID.Zero) | ||
140 | { | ||
141 | requestArgs["SessionID"] = sessionID.ToString(); | ||
142 | requestArgs["SecureSessionID"] = secureSessionID.ToString(); | ||
143 | } | ||
144 | |||
145 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
146 | bool success = response["Success"].AsBoolean(); | ||
147 | |||
148 | if (!success) | ||
149 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to login agent " + userID + ": " + response["Message"].AsString()); | ||
150 | |||
151 | return success; | ||
152 | } | ||
153 | |||
154 | public bool LogoutAgent(UUID sessionID, Vector3 position, Vector3 lookAt) | ||
155 | { | ||
156 | m_log.InfoFormat("[PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID); | ||
157 | |||
158 | NameValueCollection requestArgs = new NameValueCollection | ||
159 | { | ||
160 | { "RequestMethod", "RemoveSession" }, | ||
161 | { "SessionID", sessionID.ToString() } | ||
162 | }; | ||
163 | |||
164 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
165 | bool success = response["Success"].AsBoolean(); | ||
166 | |||
167 | if (!success) | ||
168 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to logout agent with sessionID " + sessionID + ": " + response["Message"].AsString()); | ||
169 | |||
170 | return success; | ||
171 | } | ||
172 | |||
173 | public bool LogoutRegionAgents(UUID regionID) | ||
174 | { | ||
175 | m_log.InfoFormat("[PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID); | ||
176 | |||
177 | NameValueCollection requestArgs = new NameValueCollection | ||
178 | { | ||
179 | { "RequestMethod", "RemoveSessions" }, | ||
180 | { "SceneID", regionID.ToString() } | ||
181 | }; | ||
182 | |||
183 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
184 | bool success = response["Success"].AsBoolean(); | ||
185 | |||
186 | if (!success) | ||
187 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to logout agents from region " + regionID + ": " + response["Message"].AsString()); | ||
188 | |||
189 | return success; | ||
190 | } | ||
191 | |||
192 | public bool ReportAgent(UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt) | ||
193 | { | ||
194 | //m_log.DebugFormat("[PRESENCE CONNECTOR]: Updating session data for agent with sessionID " + sessionID); | ||
195 | |||
196 | NameValueCollection requestArgs = new NameValueCollection | ||
197 | { | ||
198 | { "RequestMethod", "UpdateSession" }, | ||
199 | { "SessionID", sessionID.ToString() }, | ||
200 | { "SceneID", regionID.ToString() }, | ||
201 | { "ScenePosition", position.ToString() }, | ||
202 | { "SceneLookAt", lookAt.ToString() } | ||
203 | }; | ||
204 | |||
205 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
206 | bool success = response["Success"].AsBoolean(); | ||
207 | |||
208 | if (!success) | ||
209 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to update agent session " + sessionID + ": " + response["Message"].AsString()); | ||
210 | |||
211 | return success; | ||
212 | } | ||
213 | |||
214 | public PresenceInfo GetAgent(UUID sessionID) | ||
215 | { | ||
216 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting session data for agent with sessionID " + sessionID); | ||
217 | |||
218 | NameValueCollection requestArgs = new NameValueCollection | ||
219 | { | ||
220 | { "RequestMethod", "GetSession" }, | ||
221 | { "SessionID", sessionID.ToString() } | ||
222 | }; | ||
223 | |||
224 | OSDMap sessionResponse = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
225 | if (sessionResponse["Success"].AsBoolean()) | ||
226 | { | ||
227 | UUID userID = sessionResponse["UserID"].AsUUID(); | ||
228 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting user data for " + userID); | ||
229 | |||
230 | requestArgs = new NameValueCollection | ||
231 | { | ||
232 | { "RequestMethod", "GetUser" }, | ||
233 | { "UserID", userID.ToString() } | ||
234 | }; | ||
235 | |||
236 | OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
237 | if (userResponse["Success"].AsBoolean()) | ||
238 | return ResponseToPresenceInfo(sessionResponse, userResponse); | ||
239 | else | ||
240 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString()); | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve session " + sessionID + ": " + sessionResponse["Message"].AsString()); | ||
245 | } | ||
246 | |||
247 | return null; | ||
248 | } | ||
249 | |||
250 | public PresenceInfo[] GetAgents(string[] userIDs) | ||
251 | { | ||
252 | List<PresenceInfo> presences = new List<PresenceInfo>(userIDs.Length); | ||
253 | |||
254 | for (int i = 0; i < userIDs.Length; i++) | ||
255 | { | ||
256 | UUID userID; | ||
257 | if (UUID.TryParse(userIDs[i], out userID) && userID != UUID.Zero) | ||
258 | presences.AddRange(GetSessions(userID)); | ||
259 | } | ||
260 | |||
261 | return presences.ToArray(); | ||
262 | } | ||
263 | |||
264 | public bool SetHomeLocation(string userID, UUID regionID, Vector3 position, Vector3 lookAt) | ||
265 | { | ||
266 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Setting home location for user " + userID); | ||
267 | |||
268 | NameValueCollection requestArgs = new NameValueCollection | ||
269 | { | ||
270 | { "RequestMethod", "AddUserData" }, | ||
271 | { "UserID", userID.ToString() }, | ||
272 | { "HomeLocation", SerializeLocation(regionID, position, lookAt) } | ||
273 | }; | ||
274 | |||
275 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
276 | bool success = response["Success"].AsBoolean(); | ||
277 | |||
278 | if (!success) | ||
279 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to set home location for " + userID + ": " + response["Message"].AsString()); | ||
280 | |||
281 | return success; | ||
282 | } | ||
283 | |||
284 | #endregion IPresenceService | ||
285 | |||
286 | #region Presence Detection | ||
287 | |||
288 | private void MakeRootAgentHandler(ScenePresence sp) | ||
289 | { | ||
290 | m_log.DebugFormat("[PRESENCE DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName); | ||
291 | |||
292 | ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); | ||
293 | SetLastLocation(sp.UUID, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); | ||
294 | } | ||
295 | |||
296 | private void NewClientHandler(IClientAPI client) | ||
297 | { | ||
298 | client.OnConnectionClosed += LogoutHandler; | ||
299 | } | ||
300 | |||
301 | private void SignificantClientMovementHandler(IClientAPI client) | ||
302 | { | ||
303 | ScenePresence sp; | ||
304 | if (client.Scene is Scene && ((Scene)client.Scene).TryGetAvatar(client.AgentId, out sp)) | ||
305 | ReportAgent(sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); | ||
306 | } | ||
307 | |||
308 | private void LogoutHandler(IClientAPI client) | ||
309 | { | ||
310 | if (client.IsLoggingOut) | ||
311 | { | ||
312 | client.OnConnectionClosed -= LogoutHandler; | ||
313 | |||
314 | object obj; | ||
315 | if (client.Scene.TryGetAvatar(client.AgentId, out obj) && obj is ScenePresence) | ||
316 | { | ||
317 | // The avatar is still in the scene, we can get the exact logout position | ||
318 | ScenePresence sp = (ScenePresence)obj; | ||
319 | SetLastLocation(client.AgentId, client.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); | ||
320 | } | ||
321 | else | ||
322 | { | ||
323 | // The avatar was already removed from the scene, store LastLocation using the most recent session data | ||
324 | m_log.Warn("[PRESENCE]: " + client.Name + " has already been removed from the scene, storing approximate LastLocation"); | ||
325 | SetLastLocation(client.SessionId); | ||
326 | } | ||
327 | |||
328 | LogoutAgent(client.SessionId, Vector3.Zero, Vector3.UnitX); | ||
329 | } | ||
330 | } | ||
331 | |||
332 | #endregion Presence Detection | ||
333 | |||
334 | #region Helpers | ||
335 | |||
336 | private OSDMap GetUserData(UUID userID) | ||
337 | { | ||
338 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting user data for " + userID); | ||
339 | |||
340 | NameValueCollection requestArgs = new NameValueCollection | ||
341 | { | ||
342 | { "RequestMethod", "GetUser" }, | ||
343 | { "UserID", userID.ToString() } | ||
344 | }; | ||
345 | |||
346 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
347 | if (response["Success"].AsBoolean() && response["User"] is OSDMap) | ||
348 | return response; | ||
349 | else | ||
350 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + response["Message"].AsString()); | ||
351 | |||
352 | return null; | ||
353 | } | ||
354 | |||
355 | private OSDMap GetSessionData(UUID sessionID) | ||
356 | { | ||
357 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting session data for session " + sessionID); | ||
358 | |||
359 | NameValueCollection requestArgs = new NameValueCollection | ||
360 | { | ||
361 | { "RequestMethod", "GetSession" }, | ||
362 | { "SessionID", sessionID.ToString() } | ||
363 | }; | ||
364 | |||
365 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
366 | if (response["Success"].AsBoolean()) | ||
367 | return response; | ||
368 | else | ||
369 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve session data for session " + sessionID); | ||
370 | |||
371 | return null; | ||
372 | } | ||
373 | |||
374 | private List<PresenceInfo> GetSessions(UUID userID) | ||
375 | { | ||
376 | List<PresenceInfo> presences = new List<PresenceInfo>(1); | ||
377 | |||
378 | OSDMap userResponse = GetUserData(userID); | ||
379 | if (userResponse != null) | ||
380 | { | ||
381 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Requesting sessions for " + userID); | ||
382 | |||
383 | NameValueCollection requestArgs = new NameValueCollection | ||
384 | { | ||
385 | { "RequestMethod", "GetSession" }, | ||
386 | { "UserID", userID.ToString() } | ||
387 | }; | ||
388 | |||
389 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
390 | if (response["Success"].AsBoolean()) | ||
391 | { | ||
392 | PresenceInfo presence = ResponseToPresenceInfo(response, userResponse); | ||
393 | if (presence != null) | ||
394 | presences.Add(presence); | ||
395 | } | ||
396 | else | ||
397 | { | ||
398 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve sessions for " + userID + ": " + response["Message"].AsString()); | ||
399 | } | ||
400 | } | ||
401 | |||
402 | return presences; | ||
403 | } | ||
404 | |||
405 | /// <summary> | ||
406 | /// Fetch the last known avatar location with GetSession and persist it | ||
407 | /// as user data with AddUserData | ||
408 | /// </summary> | ||
409 | private bool SetLastLocation(UUID sessionID) | ||
410 | { | ||
411 | NameValueCollection requestArgs = new NameValueCollection | ||
412 | { | ||
413 | { "RequestMethod", "GetSession" }, | ||
414 | { "SessionID", sessionID.ToString() } | ||
415 | }; | ||
416 | |||
417 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
418 | bool success = response["Success"].AsBoolean(); | ||
419 | |||
420 | if (success) | ||
421 | { | ||
422 | UUID userID = response["UserID"].AsUUID(); | ||
423 | UUID sceneID = response["SceneID"].AsUUID(); | ||
424 | Vector3 position = response["ScenePosition"].AsVector3(); | ||
425 | Vector3 lookAt = response["SceneLookAt"].AsVector3(); | ||
426 | |||
427 | return SetLastLocation(userID, sceneID, position, lookAt); | ||
428 | } | ||
429 | else | ||
430 | { | ||
431 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to retrieve presence information for session " + sessionID + | ||
432 | " while saving last location: " + response["Message"].AsString()); | ||
433 | } | ||
434 | |||
435 | return success; | ||
436 | } | ||
437 | |||
438 | private bool SetLastLocation(UUID userID, UUID sceneID, Vector3 position, Vector3 lookAt) | ||
439 | { | ||
440 | NameValueCollection requestArgs = new NameValueCollection | ||
441 | { | ||
442 | { "RequestMethod", "AddUserData" }, | ||
443 | { "UserID", userID.ToString() }, | ||
444 | { "LastLocation", SerializeLocation(sceneID, position, lookAt) } | ||
445 | }; | ||
446 | |||
447 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
448 | bool success = response["Success"].AsBoolean(); | ||
449 | |||
450 | if (!success) | ||
451 | m_log.Warn("[PRESENCE CONNECTOR]: Failed to set last location for " + userID + ": " + response["Message"].AsString()); | ||
452 | |||
453 | return success; | ||
454 | } | ||
455 | |||
456 | private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse, OSDMap userResponse) | ||
457 | { | ||
458 | if (sessionResponse == null) | ||
459 | return null; | ||
460 | |||
461 | PresenceInfo info = new PresenceInfo(); | ||
462 | |||
463 | info.Online = true; | ||
464 | info.UserID = sessionResponse["UserID"].AsUUID().ToString(); | ||
465 | info.RegionID = sessionResponse["SceneID"].AsUUID(); | ||
466 | info.Position = sessionResponse["ScenePosition"].AsVector3(); | ||
467 | info.LookAt = sessionResponse["SceneLookAt"].AsVector3(); | ||
468 | |||
469 | if (userResponse != null && userResponse["User"] is OSDMap) | ||
470 | { | ||
471 | OSDMap user = (OSDMap)userResponse["User"]; | ||
472 | |||
473 | info.Login = user["LastLoginDate"].AsDate(); | ||
474 | info.Logout = user["LastLogoutDate"].AsDate(); | ||
475 | DeserializeLocation(user["HomeLocation"].AsString(), out info.HomeRegionID, out info.HomePosition, out info.HomeLookAt); | ||
476 | } | ||
477 | |||
478 | return info; | ||
479 | } | ||
480 | |||
481 | private string SerializeLocation(UUID regionID, Vector3 position, Vector3 lookAt) | ||
482 | { | ||
483 | return "{" + String.Format("\"SceneID\":\"{0}\",\"Position\":\"{1}\",\"LookAt\":\"{2}\"", regionID, position, lookAt) + "}"; | ||
484 | } | ||
485 | |||
486 | private bool DeserializeLocation(string location, out UUID regionID, out Vector3 position, out Vector3 lookAt) | ||
487 | { | ||
488 | OSDMap map = null; | ||
489 | |||
490 | try { map = OSDParser.DeserializeJson(location) as OSDMap; } | ||
491 | catch { } | ||
492 | |||
493 | if (map != null) | ||
494 | { | ||
495 | regionID = map["SceneID"].AsUUID(); | ||
496 | if (Vector3.TryParse(map["Position"].AsString(), out position) && | ||
497 | Vector3.TryParse(map["LookAt"].AsString(), out lookAt)) | ||
498 | { | ||
499 | return true; | ||
500 | } | ||
501 | } | ||
502 | |||
503 | regionID = UUID.Zero; | ||
504 | position = Vector3.Zero; | ||
505 | lookAt = Vector3.Zero; | ||
506 | return false; | ||
507 | } | ||
508 | |||
509 | #endregion Helpers | ||
510 | } | ||
511 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs new file mode 100644 index 0000000..9c226fb --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs | |||
@@ -0,0 +1,435 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | using Mono.Addins; | ||
34 | using Nini.Config; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Framework.Client; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using OpenSim.Services.Interfaces; | ||
42 | |||
43 | namespace OpenSim.Services.Connectors.SimianGrid | ||
44 | { | ||
45 | /// <summary> | ||
46 | /// Avatar profile flags | ||
47 | /// </summary> | ||
48 | [Flags] | ||
49 | public enum ProfileFlags : uint | ||
50 | { | ||
51 | AllowPublish = 1, | ||
52 | MaturePublish = 2, | ||
53 | Identified = 4, | ||
54 | Transacted = 8, | ||
55 | Online = 16 | ||
56 | } | ||
57 | |||
58 | /// <summary> | ||
59 | /// Connects avatar profile and classified queries to the SimianGrid | ||
60 | /// backend | ||
61 | /// </summary> | ||
62 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
63 | public class SimianProfiles : INonSharedRegionModule | ||
64 | { | ||
65 | private static readonly ILog m_log = | ||
66 | LogManager.GetLogger( | ||
67 | MethodBase.GetCurrentMethod().DeclaringType); | ||
68 | |||
69 | private string m_serverUrl = String.Empty; | ||
70 | |||
71 | #region INonSharedRegionModule | ||
72 | |||
73 | public Type ReplaceableInterface { get { return null; } } | ||
74 | public void RegionLoaded(Scene scene) { } | ||
75 | public void Close() { } | ||
76 | |||
77 | public SimianProfiles() { } | ||
78 | public string Name { get { return "SimianProfiles"; } } | ||
79 | public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { CheckEstateManager(scene); scene.EventManager.OnClientConnect += ClientConnectHandler; } } | ||
80 | public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.EventManager.OnClientConnect -= ClientConnectHandler; } } | ||
81 | |||
82 | #endregion INonSharedRegionModule | ||
83 | |||
84 | public SimianProfiles(IConfigSource source) | ||
85 | { | ||
86 | Initialise(source); | ||
87 | } | ||
88 | |||
89 | public void Initialise(IConfigSource source) | ||
90 | { | ||
91 | if (Simian.IsSimianEnabled(source, "UserAccountServices")) | ||
92 | { | ||
93 | IConfig gridConfig = source.Configs["UserAccountService"]; | ||
94 | if (gridConfig == null) | ||
95 | { | ||
96 | m_log.Error("[PROFILES]: UserAccountService missing from OpenSim.ini"); | ||
97 | throw new Exception("Profiles init error"); | ||
98 | } | ||
99 | |||
100 | string serviceUrl = gridConfig.GetString("UserAccountServerURI"); | ||
101 | if (String.IsNullOrEmpty(serviceUrl)) | ||
102 | { | ||
103 | m_log.Error("[PROFILES]: No UserAccountServerURI in section UserAccountService"); | ||
104 | throw new Exception("Profiles init error"); | ||
105 | } | ||
106 | |||
107 | if (!serviceUrl.EndsWith("/")) | ||
108 | serviceUrl = serviceUrl + '/'; | ||
109 | |||
110 | m_serverUrl = serviceUrl; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | private void ClientConnectHandler(IClientCore clientCore) | ||
115 | { | ||
116 | if (clientCore is IClientAPI) | ||
117 | { | ||
118 | IClientAPI client = (IClientAPI)clientCore; | ||
119 | |||
120 | // Classifieds | ||
121 | client.AddGenericPacketHandler("avatarclassifiedsrequest", AvatarClassifiedsRequestHandler); | ||
122 | client.OnClassifiedInfoRequest += ClassifiedInfoRequestHandler; | ||
123 | client.OnClassifiedInfoUpdate += ClassifiedInfoUpdateHandler; | ||
124 | client.OnClassifiedDelete += ClassifiedDeleteHandler; | ||
125 | |||
126 | // Picks | ||
127 | client.AddGenericPacketHandler("avatarpicksrequest", HandleAvatarPicksRequest); | ||
128 | client.AddGenericPacketHandler("pickinforequest", HandlePickInfoRequest); | ||
129 | client.OnPickInfoUpdate += PickInfoUpdateHandler; | ||
130 | client.OnPickDelete += PickDeleteHandler; | ||
131 | |||
132 | // Notes | ||
133 | client.AddGenericPacketHandler("avatarnotesrequest", HandleAvatarNotesRequest); | ||
134 | client.OnAvatarNotesUpdate += AvatarNotesUpdateHandler; | ||
135 | |||
136 | // Profiles | ||
137 | client.OnRequestAvatarProperties += RequestAvatarPropertiesHandler; | ||
138 | client.OnUpdateAvatarProperties += UpdateAvatarPropertiesHandler; | ||
139 | client.OnAvatarInterestUpdate += AvatarInterestUpdateHandler; | ||
140 | client.OnUserInfoRequest += UserInfoRequestHandler; | ||
141 | client.OnUpdateUserInfo += UpdateUserInfoHandler; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | #region Classifieds | ||
146 | |||
147 | private void AvatarClassifiedsRequestHandler(Object sender, string method, List<String> args) | ||
148 | { | ||
149 | if (!(sender is IClientAPI)) | ||
150 | return; | ||
151 | IClientAPI client = (IClientAPI)sender; | ||
152 | |||
153 | UUID targetAvatarID; | ||
154 | if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID)) | ||
155 | { | ||
156 | m_log.Error("[PROFILES]: Unrecognized arguments for " + method); | ||
157 | return; | ||
158 | } | ||
159 | |||
160 | // FIXME: Query the generic key/value store for classifieds | ||
161 | client.SendAvatarClassifiedReply(targetAvatarID, new Dictionary<UUID, string>(0)); | ||
162 | } | ||
163 | |||
164 | private void ClassifiedInfoRequestHandler(UUID classifiedID, IClientAPI client) | ||
165 | { | ||
166 | // FIXME: Fetch this info | ||
167 | client.SendClassifiedInfoReply(classifiedID, UUID.Zero, 0, Utils.DateTimeToUnixTime(DateTime.UtcNow + TimeSpan.FromDays(1)), | ||
168 | 0, String.Empty, String.Empty, UUID.Zero, 0, UUID.Zero, String.Empty, Vector3.Zero, String.Empty, 0, 0); | ||
169 | } | ||
170 | |||
171 | private void ClassifiedInfoUpdateHandler(UUID classifiedID, uint category, string name, string description, | ||
172 | UUID parcelID, uint parentEstate, UUID snapshotID, Vector3 globalPos, byte classifiedFlags, int price, | ||
173 | IClientAPI client) | ||
174 | { | ||
175 | // FIXME: Save this info | ||
176 | } | ||
177 | |||
178 | private void ClassifiedDeleteHandler(UUID classifiedID, IClientAPI client) | ||
179 | { | ||
180 | // FIXME: Delete the specified classified ad | ||
181 | } | ||
182 | |||
183 | #endregion Classifieds | ||
184 | |||
185 | #region Picks | ||
186 | |||
187 | private void HandleAvatarPicksRequest(Object sender, string method, List<String> args) | ||
188 | { | ||
189 | if (!(sender is IClientAPI)) | ||
190 | return; | ||
191 | IClientAPI client = (IClientAPI)sender; | ||
192 | |||
193 | UUID targetAvatarID; | ||
194 | if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID)) | ||
195 | { | ||
196 | m_log.Error("[PROFILES]: Unrecognized arguments for " + method); | ||
197 | return; | ||
198 | } | ||
199 | |||
200 | // FIXME: Fetch these | ||
201 | client.SendAvatarPicksReply(targetAvatarID, new Dictionary<UUID, string>(0)); | ||
202 | } | ||
203 | |||
204 | private void HandlePickInfoRequest(Object sender, string method, List<String> args) | ||
205 | { | ||
206 | if (!(sender is IClientAPI)) | ||
207 | return; | ||
208 | IClientAPI client = (IClientAPI)sender; | ||
209 | |||
210 | UUID avatarID; | ||
211 | UUID pickID; | ||
212 | if (args.Count < 2 || !UUID.TryParse(args[0], out avatarID) || !UUID.TryParse(args[1], out pickID)) | ||
213 | { | ||
214 | m_log.Error("[PROFILES]: Unrecognized arguments for " + method); | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | // FIXME: Fetch this | ||
219 | client.SendPickInfoReply(pickID, avatarID, false, UUID.Zero, String.Empty, String.Empty, UUID.Zero, String.Empty, | ||
220 | String.Empty, String.Empty, Vector3.Zero, 0, false); | ||
221 | } | ||
222 | |||
223 | private void PickInfoUpdateHandler(IClientAPI client, UUID pickID, UUID creatorID, bool topPick, string name, | ||
224 | string desc, UUID snapshotID, int sortOrder, bool enabled) | ||
225 | { | ||
226 | // FIXME: Save this | ||
227 | } | ||
228 | |||
229 | private void PickDeleteHandler(IClientAPI client, UUID pickID) | ||
230 | { | ||
231 | // FIXME: Delete | ||
232 | } | ||
233 | |||
234 | #endregion Picks | ||
235 | |||
236 | #region Notes | ||
237 | |||
238 | private void HandleAvatarNotesRequest(Object sender, string method, List<String> args) | ||
239 | { | ||
240 | if (!(sender is IClientAPI)) | ||
241 | return; | ||
242 | IClientAPI client = (IClientAPI)sender; | ||
243 | |||
244 | UUID targetAvatarID; | ||
245 | if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID)) | ||
246 | { | ||
247 | m_log.Error("[PROFILES]: Unrecognized arguments for " + method); | ||
248 | return; | ||
249 | } | ||
250 | |||
251 | // FIXME: Fetch this | ||
252 | client.SendAvatarNotesReply(targetAvatarID, String.Empty); | ||
253 | } | ||
254 | |||
255 | private void AvatarNotesUpdateHandler(IClientAPI client, UUID targetID, string notes) | ||
256 | { | ||
257 | // FIXME: Save this | ||
258 | } | ||
259 | |||
260 | #endregion Notes | ||
261 | |||
262 | #region Profiles | ||
263 | |||
264 | private void RequestAvatarPropertiesHandler(IClientAPI client, UUID avatarID) | ||
265 | { | ||
266 | OSDMap user = FetchUserData(avatarID); | ||
267 | |||
268 | ProfileFlags flags = ProfileFlags.AllowPublish | ProfileFlags.MaturePublish; | ||
269 | |||
270 | if (user != null) | ||
271 | { | ||
272 | OSDMap about = null; | ||
273 | if (user.ContainsKey("LLAbout")) | ||
274 | { | ||
275 | try { about = OSDParser.DeserializeJson(user["LLAbout"].AsString()) as OSDMap; } | ||
276 | catch { } | ||
277 | } | ||
278 | |||
279 | if (about == null) | ||
280 | about = new OSDMap(0); | ||
281 | |||
282 | // Check if this user is a grid operator | ||
283 | byte[] charterMember; | ||
284 | if (user["AccessLevel"].AsInteger() >= 200) | ||
285 | charterMember = Utils.StringToBytes("Operator"); | ||
286 | else | ||
287 | charterMember = Utils.EmptyBytes; | ||
288 | |||
289 | // Check if the user is online | ||
290 | if (client.Scene is Scene) | ||
291 | { | ||
292 | OpenSim.Services.Interfaces.PresenceInfo[] presences = ((Scene)client.Scene).PresenceService.GetAgents(new string[] { avatarID.ToString() }); | ||
293 | if (presences != null && presences.Length > 0) | ||
294 | flags |= ProfileFlags.Online; | ||
295 | } | ||
296 | |||
297 | // Check if the user is identified | ||
298 | if (user["Identified"].AsBoolean()) | ||
299 | flags |= ProfileFlags.Identified; | ||
300 | |||
301 | client.SendAvatarProperties(avatarID, about["About"].AsString(), user["CreationDate"].AsDate().ToString("M/d/yyyy", | ||
302 | System.Globalization.CultureInfo.InvariantCulture), charterMember, about["FLAbout"].AsString(), (uint)flags, | ||
303 | about["FLImage"].AsUUID(), about["Image"].AsUUID(), about["URL"].AsString(), user["Partner"].AsUUID()); | ||
304 | |||
305 | } | ||
306 | else | ||
307 | { | ||
308 | m_log.Warn("[PROFILES]: Failed to fetch profile information for " + client.Name + ", returning default values"); | ||
309 | client.SendAvatarProperties(avatarID, String.Empty, "1/1/1970", Utils.EmptyBytes, | ||
310 | String.Empty, (uint)flags, UUID.Zero, UUID.Zero, String.Empty, UUID.Zero); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | private void UpdateAvatarPropertiesHandler(IClientAPI client, UserProfileData profileData) | ||
315 | { | ||
316 | OSDMap map = new OSDMap | ||
317 | { | ||
318 | { "About", OSD.FromString(profileData.AboutText) }, | ||
319 | { "Image", OSD.FromUUID(profileData.Image) }, | ||
320 | { "FLAbout", OSD.FromString(profileData.FirstLifeAboutText) }, | ||
321 | { "FLImage", OSD.FromUUID(profileData.FirstLifeImage) }, | ||
322 | { "URL", OSD.FromString(profileData.ProfileUrl) } | ||
323 | }; | ||
324 | |||
325 | AddUserData(client.AgentId, "LLAbout", map); | ||
326 | } | ||
327 | |||
328 | private void AvatarInterestUpdateHandler(IClientAPI client, uint wantmask, string wanttext, uint skillsmask, | ||
329 | string skillstext, string languages) | ||
330 | { | ||
331 | OSDMap map = new OSDMap | ||
332 | { | ||
333 | { "WantMask", OSD.FromInteger(wantmask) }, | ||
334 | { "WantText", OSD.FromString(wanttext) }, | ||
335 | { "SkillsMask", OSD.FromInteger(skillsmask) }, | ||
336 | { "SkillsText", OSD.FromString(skillstext) }, | ||
337 | { "Languages", OSD.FromString(languages) } | ||
338 | }; | ||
339 | |||
340 | AddUserData(client.AgentId, "LLInterests", map); | ||
341 | } | ||
342 | |||
343 | private void UserInfoRequestHandler(IClientAPI client) | ||
344 | { | ||
345 | m_log.Error("[PROFILES]: UserInfoRequestHandler"); | ||
346 | |||
347 | // Fetch this user's e-mail address | ||
348 | NameValueCollection requestArgs = new NameValueCollection | ||
349 | { | ||
350 | { "RequestMethod", "GetUser" }, | ||
351 | { "UserID", client.AgentId.ToString() } | ||
352 | }; | ||
353 | |||
354 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
355 | string email = response["Email"].AsString(); | ||
356 | |||
357 | if (!response["Success"].AsBoolean()) | ||
358 | m_log.Warn("[PROFILES]: GetUser failed during a user info request for " + client.Name); | ||
359 | |||
360 | client.SendUserInfoReply(false, true, email); | ||
361 | } | ||
362 | |||
363 | private void UpdateUserInfoHandler(bool imViaEmail, bool visible, IClientAPI client) | ||
364 | { | ||
365 | m_log.Info("[PROFILES]: Ignoring user info update from " + client.Name); | ||
366 | } | ||
367 | |||
368 | #endregion Profiles | ||
369 | |||
370 | /// <summary> | ||
371 | /// Sanity checks regions for a valid estate owner at startup | ||
372 | /// </summary> | ||
373 | private void CheckEstateManager(Scene scene) | ||
374 | { | ||
375 | EstateSettings estate = scene.RegionInfo.EstateSettings; | ||
376 | |||
377 | if (estate.EstateOwner == UUID.Zero) | ||
378 | { | ||
379 | // Attempt to lookup the grid admin | ||
380 | UserAccount admin = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, UUID.Zero); | ||
381 | if (admin != null) | ||
382 | { | ||
383 | m_log.InfoFormat("[PROFILES]: Setting estate {0} (ID: {1}) owner to {2}", estate.EstateName, | ||
384 | estate.EstateID, admin.Name); | ||
385 | |||
386 | estate.EstateOwner = admin.PrincipalID; | ||
387 | estate.Save(); | ||
388 | } | ||
389 | else | ||
390 | { | ||
391 | m_log.WarnFormat("[PROFILES]: Estate {0} (ID: {1}) does not have an owner", estate.EstateName, estate.EstateID); | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | |||
396 | private bool AddUserData(UUID userID, string key, OSDMap value) | ||
397 | { | ||
398 | NameValueCollection requestArgs = new NameValueCollection | ||
399 | { | ||
400 | { "RequestMethod", "AddUserData" }, | ||
401 | { "UserID", userID.ToString() }, | ||
402 | { key, OSDParser.SerializeJsonString(value) } | ||
403 | }; | ||
404 | |||
405 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
406 | bool success = response["Success"].AsBoolean(); | ||
407 | |||
408 | if (!success) | ||
409 | m_log.WarnFormat("[PROFILES]: Failed to add user data with key {0} for {1}: {2}", key, userID, response["Message"].AsString()); | ||
410 | |||
411 | return success; | ||
412 | } | ||
413 | |||
414 | private OSDMap FetchUserData(UUID userID) | ||
415 | { | ||
416 | NameValueCollection requestArgs = new NameValueCollection | ||
417 | { | ||
418 | { "RequestMethod", "GetUser" }, | ||
419 | { "UserID", userID.ToString() } | ||
420 | }; | ||
421 | |||
422 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
423 | if (response["Success"].AsBoolean() && response["User"] is OSDMap) | ||
424 | { | ||
425 | return (OSDMap)response["User"]; | ||
426 | } | ||
427 | else | ||
428 | { | ||
429 | m_log.Error("[PROFILES]: Failed to fetch user data for " + userID + ": " + response["Message"].AsString()); | ||
430 | } | ||
431 | |||
432 | return null; | ||
433 | } | ||
434 | } | ||
435 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs new file mode 100644 index 0000000..bb0ac57 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs | |||
@@ -0,0 +1,311 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Region.Framework.Interfaces; | ||
35 | using OpenSim.Region.Framework.Scenes; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using log4net; | ||
38 | using Mono.Addins; | ||
39 | using Nini.Config; | ||
40 | using OpenMetaverse; | ||
41 | using OpenMetaverse.StructuredData; | ||
42 | |||
43 | namespace OpenSim.Services.Connectors.SimianGrid | ||
44 | { | ||
45 | /// <summary> | ||
46 | /// Connects user account data (creating new users, looking up existing | ||
47 | /// users) to the SimianGrid backend | ||
48 | /// </summary> | ||
49 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
50 | public class SimianUserAccountServiceConnector : IUserAccountService, ISharedRegionModule | ||
51 | { | ||
52 | private static readonly ILog m_log = | ||
53 | LogManager.GetLogger( | ||
54 | MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private string m_serverUrl = String.Empty; | ||
57 | private ExpiringCache<UUID, UserAccount> m_accountCache; | ||
58 | |||
59 | #region ISharedRegionModule | ||
60 | |||
61 | public Type ReplaceableInterface { get { return null; } } | ||
62 | public void RegionLoaded(Scene scene) { } | ||
63 | public void PostInitialise() { } | ||
64 | public void Close() { } | ||
65 | |||
66 | public SimianUserAccountServiceConnector() { } | ||
67 | public string Name { get { return "SimianUserAccountServiceConnector"; } } | ||
68 | public void AddRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.RegisterModuleInterface<IUserAccountService>(this); } } | ||
69 | public void RemoveRegion(Scene scene) { if (!String.IsNullOrEmpty(m_serverUrl)) { scene.UnregisterModuleInterface<IUserAccountService>(this); } } | ||
70 | |||
71 | #endregion ISharedRegionModule | ||
72 | |||
73 | public SimianUserAccountServiceConnector(IConfigSource source) | ||
74 | { | ||
75 | Initialise(source); | ||
76 | } | ||
77 | |||
78 | public void Initialise(IConfigSource source) | ||
79 | { | ||
80 | if (Simian.IsSimianEnabled(source, "UserAccountServices")) | ||
81 | { | ||
82 | IConfig assetConfig = source.Configs["UserAccountService"]; | ||
83 | if (assetConfig == null) | ||
84 | { | ||
85 | m_log.Error("[ACCOUNT CONNECTOR]: UserAccountService missing from OpenSim.ini"); | ||
86 | throw new Exception("User account connector init error"); | ||
87 | } | ||
88 | |||
89 | string serviceURI = assetConfig.GetString("UserAccountServerURI"); | ||
90 | if (String.IsNullOrEmpty(serviceURI)) | ||
91 | { | ||
92 | m_log.Error("[ACCOUNT CONNECTOR]: No UserAccountServerURI in section UserAccountService, skipping SimianUserAccountServiceConnector"); | ||
93 | throw new Exception("User account connector init error"); | ||
94 | } | ||
95 | |||
96 | m_accountCache = new ExpiringCache<UUID, UserAccount>(); | ||
97 | m_serverUrl = serviceURI; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) | ||
102 | { | ||
103 | NameValueCollection requestArgs = new NameValueCollection | ||
104 | { | ||
105 | { "RequestMethod", "GetUser" }, | ||
106 | { "Name", firstName + ' ' + lastName } | ||
107 | }; | ||
108 | |||
109 | return GetUser(requestArgs); | ||
110 | } | ||
111 | |||
112 | public UserAccount GetUserAccount(UUID scopeID, string email) | ||
113 | { | ||
114 | NameValueCollection requestArgs = new NameValueCollection | ||
115 | { | ||
116 | { "RequestMethod", "GetUser" }, | ||
117 | { "Email", email } | ||
118 | }; | ||
119 | |||
120 | return GetUser(requestArgs); | ||
121 | } | ||
122 | |||
123 | public UserAccount GetUserAccount(UUID scopeID, UUID userID) | ||
124 | { | ||
125 | // Cache check | ||
126 | UserAccount account; | ||
127 | if (m_accountCache.TryGetValue(userID, out account)) | ||
128 | return account; | ||
129 | |||
130 | NameValueCollection requestArgs = new NameValueCollection | ||
131 | { | ||
132 | { "RequestMethod", "GetUser" }, | ||
133 | { "UserID", userID.ToString() } | ||
134 | }; | ||
135 | |||
136 | return GetUser(requestArgs); | ||
137 | } | ||
138 | |||
139 | public List<UserAccount> GetUserAccounts(UUID scopeID, string query) | ||
140 | { | ||
141 | List<UserAccount> accounts = new List<UserAccount>(); | ||
142 | |||
143 | m_log.DebugFormat("[ACCOUNT CONNECTOR]: Searching for user accounts with name query " + query); | ||
144 | |||
145 | NameValueCollection requestArgs = new NameValueCollection | ||
146 | { | ||
147 | { "RequestMethod", "GetUsers" }, | ||
148 | { "NameQuery", query } | ||
149 | }; | ||
150 | |||
151 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
152 | if (response["Success"].AsBoolean()) | ||
153 | { | ||
154 | OSDArray array = response["Users"] as OSDArray; | ||
155 | if (array != null && array.Count > 0) | ||
156 | { | ||
157 | for (int i = 0; i < array.Count; i++) | ||
158 | { | ||
159 | UserAccount account = ResponseToUserAccount(array[i] as OSDMap); | ||
160 | if (account != null) | ||
161 | accounts.Add(account); | ||
162 | } | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | m_log.Warn("[ACCOUNT CONNECTOR]: Account search failed, response data was in an invalid format"); | ||
167 | } | ||
168 | } | ||
169 | else | ||
170 | { | ||
171 | m_log.Warn("[ACCOUNT CONNECTOR]: Failed to search for account data by name " + query); | ||
172 | } | ||
173 | |||
174 | return accounts; | ||
175 | } | ||
176 | |||
177 | public bool StoreUserAccount(UserAccount data) | ||
178 | { | ||
179 | m_log.InfoFormat("[ACCOUNT CONNECTOR]: Storing user account for " + data.Name); | ||
180 | |||
181 | NameValueCollection requestArgs = new NameValueCollection | ||
182 | { | ||
183 | { "RequestMethod", "AddUser" }, | ||
184 | { "UserID", data.PrincipalID.ToString() }, | ||
185 | { "Name", data.Name }, | ||
186 | { "Email", data.Email }, | ||
187 | { "AccessLevel", data.UserLevel.ToString() } | ||
188 | }; | ||
189 | |||
190 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
191 | |||
192 | if (response["Success"].AsBoolean()) | ||
193 | { | ||
194 | m_log.InfoFormat("[ACCOUNT CONNECTOR]: Storing user account data for " + data.Name); | ||
195 | |||
196 | requestArgs = new NameValueCollection | ||
197 | { | ||
198 | { "RequestMethod", "AddUserData" }, | ||
199 | { "UserID", data.PrincipalID.ToString() }, | ||
200 | { "CreationDate", data.Created.ToString() }, | ||
201 | { "UserFlags", data.UserFlags.ToString() }, | ||
202 | { "UserTitle", data.UserTitle } | ||
203 | }; | ||
204 | |||
205 | response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
206 | bool success = response["Success"].AsBoolean(); | ||
207 | |||
208 | if (success) | ||
209 | { | ||
210 | // Cache the user account info | ||
211 | m_accountCache.AddOrUpdate(data.PrincipalID, data, DateTime.Now + TimeSpan.FromMinutes(2.0d)); | ||
212 | } | ||
213 | else | ||
214 | { | ||
215 | m_log.Warn("[ACCOUNT CONNECTOR]: Failed to store user account data for " + data.Name + ": " + response["Message"].AsString()); | ||
216 | } | ||
217 | |||
218 | return success; | ||
219 | } | ||
220 | else | ||
221 | { | ||
222 | m_log.Warn("[ACCOUNT CONNECTOR]: Failed to store user account for " + data.Name + ": " + response["Message"].AsString()); | ||
223 | } | ||
224 | |||
225 | return false; | ||
226 | } | ||
227 | |||
228 | /// <summary> | ||
229 | /// Helper method for the various ways of retrieving a user account | ||
230 | /// </summary> | ||
231 | /// <param name="requestArgs">Service query parameters</param> | ||
232 | /// <returns>A UserAccount object on success, null on failure</returns> | ||
233 | private UserAccount GetUser(NameValueCollection requestArgs) | ||
234 | { | ||
235 | string lookupValue = (requestArgs.Count > 1) ? requestArgs[1] : "(Unknown)"; | ||
236 | m_log.DebugFormat("[ACCOUNT CONNECTOR]: Looking up user account with query: " + lookupValue); | ||
237 | |||
238 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
239 | if (response["Success"].AsBoolean()) | ||
240 | { | ||
241 | OSDMap user = response["User"] as OSDMap; | ||
242 | if (user != null) | ||
243 | return ResponseToUserAccount(user); | ||
244 | else | ||
245 | m_log.Warn("[ACCOUNT CONNECTOR]: Account search failed, response data was in an invalid format"); | ||
246 | } | ||
247 | else | ||
248 | { | ||
249 | m_log.Warn("[ACCOUNT CONNECTOR]: Failed to lookup user account with query: " + lookupValue); | ||
250 | } | ||
251 | |||
252 | return null; | ||
253 | } | ||
254 | |||
255 | /// <summary> | ||
256 | /// Convert a User object in LLSD format to a UserAccount | ||
257 | /// </summary> | ||
258 | /// <param name="response">LLSD containing user account data</param> | ||
259 | /// <returns>A UserAccount object on success, null on failure</returns> | ||
260 | private UserAccount ResponseToUserAccount(OSDMap response) | ||
261 | { | ||
262 | if (response == null) | ||
263 | return null; | ||
264 | |||
265 | UserAccount account = new UserAccount(); | ||
266 | account.PrincipalID = response["UserID"].AsUUID(); | ||
267 | account.Created = response["CreationDate"].AsInteger(); | ||
268 | account.Email = response["Email"].AsString(); | ||
269 | account.ServiceURLs = new Dictionary<string, object>(0); | ||
270 | account.UserFlags = response["UserFlags"].AsInteger(); | ||
271 | account.UserLevel = response["AccessLevel"].AsInteger(); | ||
272 | account.UserTitle = response["UserTitle"].AsString(); | ||
273 | GetFirstLastName(response["Name"].AsString(), out account.FirstName, out account.LastName); | ||
274 | |||
275 | // Cache the user account info | ||
276 | m_accountCache.AddOrUpdate(account.PrincipalID, account, DateTime.Now + TimeSpan.FromMinutes(2.0d)); | ||
277 | |||
278 | return account; | ||
279 | } | ||
280 | |||
281 | /// <summary> | ||
282 | /// Convert a name with a single space in it to a first and last name | ||
283 | /// </summary> | ||
284 | /// <param name="name">A full name such as "John Doe"</param> | ||
285 | /// <param name="firstName">First name</param> | ||
286 | /// <param name="lastName">Last name (surname)</param> | ||
287 | private static void GetFirstLastName(string name, out string firstName, out string lastName) | ||
288 | { | ||
289 | if (String.IsNullOrEmpty(name)) | ||
290 | { | ||
291 | firstName = String.Empty; | ||
292 | lastName = String.Empty; | ||
293 | } | ||
294 | else | ||
295 | { | ||
296 | string[] names = name.Split(' '); | ||
297 | |||
298 | if (names.Length == 2) | ||
299 | { | ||
300 | firstName = names[0]; | ||
301 | lastName = names[1]; | ||
302 | } | ||
303 | else | ||
304 | { | ||
305 | firstName = String.Empty; | ||
306 | lastName = name; | ||
307 | } | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | } | ||
diff --git a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs index 8e7c92b..2f9b520 100644 --- a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs +++ b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs | |||
@@ -113,6 +113,7 @@ namespace OpenSim.Services.Connectors | |||
113 | 113 | ||
114 | public virtual UserAccount GetUserAccount(UUID scopeID, UUID userID) | 114 | public virtual UserAccount GetUserAccount(UUID scopeID, UUID userID) |
115 | { | 115 | { |
116 | m_log.DebugFormat("[ACCOUNTS CONNECTOR]: GetUSerAccount {0}", userID); | ||
116 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | 117 | Dictionary<string, object> sendData = new Dictionary<string, object>(); |
117 | //sendData["SCOPEID"] = scopeID.ToString(); | 118 | //sendData["SCOPEID"] = scopeID.ToString(); |
118 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | 119 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); |
diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index 1368e46..2faf018 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs | |||
@@ -123,8 +123,7 @@ namespace OpenSim.Services.GridService | |||
123 | if ((rflags & OpenSim.Data.RegionFlags.Reservation) != 0) | 123 | if ((rflags & OpenSim.Data.RegionFlags.Reservation) != 0) |
124 | { | 124 | { |
125 | // Regions reserved for the null key cannot be taken. | 125 | // Regions reserved for the null key cannot be taken. |
126 | // | 126 | if ((string)region.Data["PrincipalID"] == UUID.Zero.ToString()) |
127 | if (region.Data["PrincipalID"] == UUID.Zero.ToString()) | ||
128 | return "Region location us reserved"; | 127 | return "Region location us reserved"; |
129 | 128 | ||
130 | // Treat it as an auth request | 129 | // Treat it as an auth request |
@@ -132,7 +131,6 @@ namespace OpenSim.Services.GridService | |||
132 | // NOTE: Fudging the flags value here, so these flags | 131 | // NOTE: Fudging the flags value here, so these flags |
133 | // should not be used elsewhere. Don't optimize | 132 | // should not be used elsewhere. Don't optimize |
134 | // this with the later retrieval of the same flags! | 133 | // this with the later retrieval of the same flags! |
135 | // | ||
136 | rflags |= OpenSim.Data.RegionFlags.Authenticate; | 134 | rflags |= OpenSim.Data.RegionFlags.Authenticate; |
137 | } | 135 | } |
138 | 136 | ||
@@ -489,7 +487,7 @@ namespace OpenSim.Services.GridService | |||
489 | f |= (OpenSim.Data.RegionFlags)val; | 487 | f |= (OpenSim.Data.RegionFlags)val; |
490 | } | 488 | } |
491 | } | 489 | } |
492 | catch (Exception e) | 490 | catch (Exception) |
493 | { | 491 | { |
494 | MainConsole.Instance.Output("Error in flag specification: " + p); | 492 | MainConsole.Instance.Output("Error in flag specification: " + p); |
495 | } | 493 | } |
diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs index de5df9d..58746d0 100644 --- a/OpenSim/Services/GridService/HypergridLinker.cs +++ b/OpenSim/Services/GridService/HypergridLinker.cs | |||
@@ -168,10 +168,11 @@ namespace OpenSim.Services.GridService | |||
168 | } | 168 | } |
169 | 169 | ||
170 | // Sanity check. | 170 | // Sanity check. |
171 | IPAddress ipaddr = null; | 171 | //IPAddress ipaddr = null; |
172 | try | 172 | try |
173 | { | 173 | { |
174 | ipaddr = Util.GetHostFromDNS(host); | 174 | //ipaddr = Util.GetHostFromDNS(host); |
175 | Util.GetHostFromDNS(host); | ||
175 | } | 176 | } |
176 | catch | 177 | catch |
177 | { | 178 | { |
diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs index 15379b5..26f211b 100644 --- a/OpenSim/Services/HypergridService/UserAgentService.cs +++ b/OpenSim/Services/HypergridService/UserAgentService.cs | |||
@@ -1,4 +1,31 @@ | |||
1 | using System; | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
2 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
3 | using System.Net; | 30 | using System.Net; |
4 | using System.Reflection; | 31 | using System.Reflection; |
diff --git a/OpenSim/Services/Interfaces/IUserAccountService.cs b/OpenSim/Services/Interfaces/IUserAccountService.cs index 3dacf53..a45bf8c 100644 --- a/OpenSim/Services/Interfaces/IUserAccountService.cs +++ b/OpenSim/Services/Interfaces/IUserAccountService.cs | |||
@@ -140,14 +140,20 @@ namespace OpenSim.Services.Interfaces | |||
140 | UserAccount GetUserAccount(UUID scopeID, UUID userID); | 140 | UserAccount GetUserAccount(UUID scopeID, UUID userID); |
141 | UserAccount GetUserAccount(UUID scopeID, string FirstName, string LastName); | 141 | UserAccount GetUserAccount(UUID scopeID, string FirstName, string LastName); |
142 | UserAccount GetUserAccount(UUID scopeID, string Email); | 142 | UserAccount GetUserAccount(UUID scopeID, string Email); |
143 | // Returns the list of avatars that matches both the search | 143 | |
144 | // criterion and the scope ID passed | 144 | /// <summary> |
145 | // | 145 | /// Returns the list of avatars that matches both the search criterion and the scope ID passed |
146 | /// </summary> | ||
147 | /// <param name="scopeID"></param> | ||
148 | /// <param name="query"></param> | ||
149 | /// <returns></returns> | ||
146 | List<UserAccount> GetUserAccounts(UUID scopeID, string query); | 150 | List<UserAccount> GetUserAccounts(UUID scopeID, string query); |
147 | 151 | ||
148 | // Store the data given, wich replaces the sotred data, therefore | 152 | /// <summary> |
149 | // must be complete. | 153 | /// Store the data given, wich replaces the sotred data, therefore must be complete. |
150 | // | 154 | /// </summary> |
155 | /// <param name="data"></param> | ||
156 | /// <returns></returns> | ||
151 | bool StoreUserAccount(UserAccount data); | 157 | bool StoreUserAccount(UserAccount data); |
152 | } | 158 | } |
153 | } | 159 | } \ No newline at end of file |
diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs index 05f5b4c..ee30fa3 100644 --- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs +++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs | |||
@@ -47,9 +47,9 @@ namespace OpenSim.Services.LLLoginService | |||
47 | { | 47 | { |
48 | public class LLFailedLoginResponse : OpenSim.Services.Interfaces.FailedLoginResponse | 48 | public class LLFailedLoginResponse : OpenSim.Services.Interfaces.FailedLoginResponse |
49 | { | 49 | { |
50 | string m_key; | 50 | protected string m_key; |
51 | string m_value; | 51 | protected string m_value; |
52 | string m_login; | 52 | protected string m_login; |
53 | 53 | ||
54 | public static LLFailedLoginResponse UserProblem; | 54 | public static LLFailedLoginResponse UserProblem; |
55 | public static LLFailedLoginResponse AuthorizationProblem; | 55 | public static LLFailedLoginResponse AuthorizationProblem; |
@@ -623,7 +623,7 @@ namespace OpenSim.Services.LLLoginService | |||
623 | } | 623 | } |
624 | 624 | ||
625 | private InventoryData GetInventorySkeleton(List<InventoryFolderBase> folders) | 625 | private InventoryData GetInventorySkeleton(List<InventoryFolderBase> folders) |
626 | { | 626 | { |
627 | UUID rootID = UUID.Zero; | 627 | UUID rootID = UUID.Zero; |
628 | ArrayList AgentInventoryArray = new ArrayList(); | 628 | ArrayList AgentInventoryArray = new ArrayList(); |
629 | Hashtable TempHash; | 629 | Hashtable TempHash; |
diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index ae729f8..1eaf4d4 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs | |||
@@ -1,4 +1,31 @@ | |||
1 | using System; | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
2 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
3 | using System.Net; | 30 | using System.Net; |
4 | using System.Reflection; | 31 | using System.Reflection; |
@@ -24,24 +51,24 @@ namespace OpenSim.Services.LLLoginService | |||
24 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
25 | private static bool Initialized = false; | 52 | private static bool Initialized = false; |
26 | 53 | ||
27 | private IUserAccountService m_UserAccountService; | 54 | protected IUserAccountService m_UserAccountService; |
28 | private IAuthenticationService m_AuthenticationService; | 55 | protected IAuthenticationService m_AuthenticationService; |
29 | private IInventoryService m_InventoryService; | 56 | protected IInventoryService m_InventoryService; |
30 | private IGridService m_GridService; | 57 | protected IGridService m_GridService; |
31 | private IPresenceService m_PresenceService; | 58 | protected IPresenceService m_PresenceService; |
32 | private ISimulationService m_LocalSimulationService; | 59 | private ISimulationService m_LocalSimulationService; |
33 | private ISimulationService m_RemoteSimulationService; | 60 | private ISimulationService m_RemoteSimulationService; |
34 | private ILibraryService m_LibraryService; | 61 | protected ILibraryService m_LibraryService; |
35 | private IFriendsService m_FriendsService; | 62 | protected IFriendsService m_FriendsService; |
36 | private IAvatarService m_AvatarService; | 63 | protected IAvatarService m_AvatarService; |
37 | private IUserAgentService m_UserAgentService; | 64 | private IUserAgentService m_UserAgentService; |
38 | 65 | ||
39 | private GatekeeperServiceConnector m_GatekeeperConnector; | 66 | private GatekeeperServiceConnector m_GatekeeperConnector; |
40 | 67 | ||
41 | private string m_DefaultRegionName; | 68 | private string m_DefaultRegionName; |
42 | private string m_WelcomeMessage; | 69 | protected string m_WelcomeMessage; |
43 | private bool m_RequireInventory; | 70 | private bool m_RequireInventory; |
44 | private int m_MinLoginLevel; | 71 | protected int m_MinLoginLevel; |
45 | private string m_GatekeeperURL; | 72 | private string m_GatekeeperURL; |
46 | 73 | ||
47 | IConfig m_LoginServerConfig; | 74 | IConfig m_LoginServerConfig; |
@@ -259,7 +286,7 @@ namespace OpenSim.Services.LLLoginService | |||
259 | } | 286 | } |
260 | } | 287 | } |
261 | 288 | ||
262 | private GridRegion FindDestination(UserAccount account, PresenceInfo pinfo, UUID sessionID, string startLocation, out GridRegion gatekeeper, out string where, out Vector3 position, out Vector3 lookAt) | 289 | protected GridRegion FindDestination(UserAccount account, PresenceInfo pinfo, UUID sessionID, string startLocation, out GridRegion gatekeeper, out string where, out Vector3 position, out Vector3 lookAt) |
263 | { | 290 | { |
264 | m_log.DebugFormat("[LLOGIN SERVICE]: FindDestination for start location {0}", startLocation); | 291 | m_log.DebugFormat("[LLOGIN SERVICE]: FindDestination for start location {0}", startLocation); |
265 | 292 | ||
@@ -470,7 +497,7 @@ namespace OpenSim.Services.LLLoginService | |||
470 | } | 497 | } |
471 | } | 498 | } |
472 | 499 | ||
473 | private AgentCircuitData LaunchAgentAtGrid(GridRegion gatekeeper, GridRegion destination, UserAccount account, AvatarData avatar, | 500 | protected AgentCircuitData LaunchAgentAtGrid(GridRegion gatekeeper, GridRegion destination, UserAccount account, AvatarData avatar, |
474 | UUID session, UUID secureSession, Vector3 position, string currentWhere, out string where, out string reason) | 501 | UUID session, UUID secureSession, Vector3 position, string currentWhere, out string where, out string reason) |
475 | { | 502 | { |
476 | where = currentWhere; | 503 | where = currentWhere; |
diff --git a/OpenSim/Services/PresenceService/PresenceService.cs b/OpenSim/Services/PresenceService/PresenceService.cs index 304538a..ea8d673 100644 --- a/OpenSim/Services/PresenceService/PresenceService.cs +++ b/OpenSim/Services/PresenceService/PresenceService.cs | |||
@@ -72,6 +72,10 @@ namespace OpenSim.Services.PresenceService | |||
72 | data.Data["HomeRegionID"] = d[0].Data["HomeRegionID"]; | 72 | data.Data["HomeRegionID"] = d[0].Data["HomeRegionID"]; |
73 | data.Data["HomePosition"] = d[0].Data["HomePosition"]; | 73 | data.Data["HomePosition"] = d[0].Data["HomePosition"]; |
74 | data.Data["HomeLookAt"] = d[0].Data["HomeLookAt"]; | 74 | data.Data["HomeLookAt"] = d[0].Data["HomeLookAt"]; |
75 | data.Data["Position"] = d[0].Data["Position"]; | ||
76 | data.Data["LookAt"] = d[0].Data["LookAt"]; | ||
77 | |||
78 | data.RegionID = d[0].RegionID; | ||
75 | } | 79 | } |
76 | else | 80 | else |
77 | { | 81 | { |
diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs index 36cce75..c6e33bb 100644 --- a/OpenSim/Services/UserAccountService/GridUserService.cs +++ b/OpenSim/Services/UserAccountService/GridUserService.cs | |||
@@ -58,7 +58,7 @@ namespace OpenSim.Services.UserAccountService | |||
58 | info.HomePosition = Vector3.Parse(d.Data["HomePosition"]); | 58 | info.HomePosition = Vector3.Parse(d.Data["HomePosition"]); |
59 | info.HomeLookAt = Vector3.Parse(d.Data["HomeLookAt"]); | 59 | info.HomeLookAt = Vector3.Parse(d.Data["HomeLookAt"]); |
60 | 60 | ||
61 | return info; | 61 | return info; |
62 | } | 62 | } |
63 | 63 | ||
64 | public bool StoreGridUserInfo(GridUserInfo info) | 64 | public bool StoreGridUserInfo(GridUserInfo info) |
diff --git a/OpenSim/Services/UserAccountService/UserAccountService.cs b/OpenSim/Services/UserAccountService/UserAccountService.cs index 82c34e7..38caf74 100644 --- a/OpenSim/Services/UserAccountService/UserAccountService.cs +++ b/OpenSim/Services/UserAccountService/UserAccountService.cs | |||
@@ -200,7 +200,9 @@ namespace OpenSim.Services.UserAccountService | |||
200 | } | 200 | } |
201 | 201 | ||
202 | if (d.Length < 1) | 202 | if (d.Length < 1) |
203 | { | ||
203 | return null; | 204 | return null; |
205 | } | ||
204 | 206 | ||
205 | return MakeUserAccount(d[0]); | 207 | return MakeUserAccount(d[0]); |
206 | } | 208 | } |
diff --git a/OpenSim/Tests/Common/Mock/MockUserAccountService.cs b/OpenSim/Tests/Common/Mock/MockUserAccountService.cs new file mode 100644 index 0000000..0769c7a --- /dev/null +++ b/OpenSim/Tests/Common/Mock/MockUserAccountService.cs | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System.Collections.Generic; | ||
29 | using Nini.Config; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Services.Interfaces; | ||
32 | |||
33 | namespace OpenSim.Tests.Common.Mock | ||
34 | { | ||
35 | public class MockUserAccountService : IUserAccountService | ||
36 | { | ||
37 | |||
38 | public MockUserAccountService(IConfigSource config) {} | ||
39 | |||
40 | public UserAccount GetUserAccount(UUID scopeID, UUID userID) { return new UserAccount(); } | ||
41 | public UserAccount GetUserAccount(UUID scopeID, string FirstName, string LastName) { return new UserAccount(); } | ||
42 | public UserAccount GetUserAccount(UUID scopeID, string Email) { return new UserAccount(); } | ||
43 | public List<UserAccount> GetUserAccounts(UUID scopeID, string query) { return new List<UserAccount>(); } | ||
44 | public bool StoreUserAccount(UserAccount data) { return true; } | ||
45 | } | ||
46 | } \ No newline at end of file | ||
diff --git a/OpenSim/Tests/Common/Mock/TestScene.cs b/OpenSim/Tests/Common/Mock/TestScene.cs index 076cb7a..01f2c14 100644 --- a/OpenSim/Tests/Common/Mock/TestScene.cs +++ b/OpenSim/Tests/Common/Mock/TestScene.cs | |||
@@ -65,6 +65,6 @@ namespace OpenSim.Tests.Common.Mock | |||
65 | public AsyncSceneObjectGroupDeleter SceneObjectGroupDeleter | 65 | public AsyncSceneObjectGroupDeleter SceneObjectGroupDeleter |
66 | { | 66 | { |
67 | get { return m_asyncSceneObjectDeleter; } | 67 | get { return m_asyncSceneObjectDeleter; } |
68 | } | 68 | } |
69 | } | 69 | } |
70 | } | 70 | } \ No newline at end of file |
diff --git a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs index 9e718f6..864e2aa 100644 --- a/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs +++ b/OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs | |||
@@ -128,7 +128,7 @@ namespace OpenSim.Tests.Common.Setup | |||
128 | /// <param name="realServices">Starts real inventory and asset services, as opposed to mock ones, if true</param> | 128 | /// <param name="realServices">Starts real inventory and asset services, as opposed to mock ones, if true</param> |
129 | /// <returns></returns> | 129 | /// <returns></returns> |
130 | public static TestScene SetupScene( | 130 | public static TestScene SetupScene( |
131 | string name, UUID id, uint x, uint y, String realServices) | 131 | string name, UUID id, uint x, uint y, String realServices) |
132 | { | 132 | { |
133 | bool newScene = false; | 133 | bool newScene = false; |
134 | 134 | ||
@@ -179,15 +179,16 @@ namespace OpenSim.Tests.Common.Setup | |||
179 | StartAssetService(testScene, true); | 179 | StartAssetService(testScene, true); |
180 | else | 180 | else |
181 | StartAssetService(testScene, false); | 181 | StartAssetService(testScene, false); |
182 | |||
182 | if (realServices.Contains("inventory")) | 183 | if (realServices.Contains("inventory")) |
183 | StartInventoryService(testScene, true); | 184 | StartInventoryService(testScene, true); |
184 | else | 185 | else |
185 | StartInventoryService(testScene, false); | 186 | StartInventoryService(testScene, false); |
187 | |||
186 | if (realServices.Contains("grid")) | 188 | if (realServices.Contains("grid")) |
187 | StartGridService(testScene, true); | 189 | StartGridService(testScene, true); |
188 | if (realServices.Contains("useraccounts")) | 190 | |
189 | StartUserAccountService(testScene, true); | 191 | StartUserAccountService(testScene, realServices.Contains("useraccounts")); |
190 | |||
191 | } | 192 | } |
192 | // If not, make sure the shared module gets references to this new scene | 193 | // If not, make sure the shared module gets references to this new scene |
193 | else | 194 | else |
@@ -196,9 +197,13 @@ namespace OpenSim.Tests.Common.Setup | |||
196 | m_assetService.RegionLoaded(testScene); | 197 | m_assetService.RegionLoaded(testScene); |
197 | m_inventoryService.AddRegion(testScene); | 198 | m_inventoryService.AddRegion(testScene); |
198 | m_inventoryService.RegionLoaded(testScene); | 199 | m_inventoryService.RegionLoaded(testScene); |
200 | m_userAccountService.AddRegion(testScene); | ||
201 | m_userAccountService.RegionLoaded(testScene); | ||
199 | } | 202 | } |
203 | |||
200 | m_inventoryService.PostInitialise(); | 204 | m_inventoryService.PostInitialise(); |
201 | m_assetService.PostInitialise(); | 205 | m_assetService.PostInitialise(); |
206 | m_userAccountService.PostInitialise(); | ||
202 | 207 | ||
203 | testScene.SetModuleInterfaces(); | 208 | testScene.SetModuleInterfaces(); |
204 | 209 | ||
@@ -209,6 +214,14 @@ namespace OpenSim.Tests.Common.Setup | |||
209 | physicsPluginManager.LoadPluginsFromAssembly("Physics/OpenSim.Region.Physics.BasicPhysicsPlugin.dll"); | 214 | physicsPluginManager.LoadPluginsFromAssembly("Physics/OpenSim.Region.Physics.BasicPhysicsPlugin.dll"); |
210 | testScene.PhysicsScene | 215 | testScene.PhysicsScene |
211 | = physicsPluginManager.GetPhysicsScene("basicphysics", "ZeroMesher", new IniConfigSource(), "test"); | 216 | = physicsPluginManager.GetPhysicsScene("basicphysics", "ZeroMesher", new IniConfigSource(), "test"); |
217 | |||
218 | // It's really not a good idea to use static variables as they carry over between tests, leading to | ||
219 | // problems that are extremely hard to debug. Really, these static fields need to be eliminated - | ||
220 | // tests using multiple regions that need to share modules need to find another solution. | ||
221 | m_assetService = null; | ||
222 | m_inventoryService = null; | ||
223 | m_gridService = null; | ||
224 | m_userAccountService = null; | ||
212 | 225 | ||
213 | return testScene; | 226 | return testScene; |
214 | } | 227 | } |
@@ -273,6 +286,11 @@ namespace OpenSim.Tests.Common.Setup | |||
273 | //testScene.AddRegionModule(m_gridService.Name, m_gridService); | 286 | //testScene.AddRegionModule(m_gridService.Name, m_gridService); |
274 | } | 287 | } |
275 | 288 | ||
289 | /// <summary> | ||
290 | /// Start a user account service, whether real or mock | ||
291 | /// </summary> | ||
292 | /// <param name="testScene"></param> | ||
293 | /// <param name="real">Starts a real service if true, a mock service if not</param> | ||
276 | private static void StartUserAccountService(Scene testScene, bool real) | 294 | private static void StartUserAccountService(Scene testScene, bool real) |
277 | { | 295 | { |
278 | IConfigSource config = new IniConfigSource(); | 296 | IConfigSource config = new IniConfigSource(); |
@@ -280,8 +298,14 @@ namespace OpenSim.Tests.Common.Setup | |||
280 | config.AddConfig("UserAccountService"); | 298 | config.AddConfig("UserAccountService"); |
281 | config.Configs["Modules"].Set("UserAccountServices", "LocalUserAccountServicesConnector"); | 299 | config.Configs["Modules"].Set("UserAccountServices", "LocalUserAccountServicesConnector"); |
282 | config.Configs["UserAccountService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); | 300 | config.Configs["UserAccountService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); |
301 | |||
283 | if (real) | 302 | if (real) |
284 | config.Configs["UserAccountService"].Set("LocalServiceModule", "OpenSim.Services.UserAccountService.dll:UserAccountService"); | 303 | config.Configs["UserAccountService"].Set( |
304 | "LocalServiceModule", "OpenSim.Services.UserAccountService.dll:UserAccountService"); | ||
305 | else | ||
306 | config.Configs["UserAccountService"].Set( | ||
307 | "LocalServiceModule", "OpenSim.Tests.Common.dll:MockUserAccountService"); | ||
308 | |||
285 | if (m_userAccountService == null) | 309 | if (m_userAccountService == null) |
286 | { | 310 | { |
287 | ISharedRegionModule userAccountService = new LocalUserAccountServicesConnector(); | 311 | ISharedRegionModule userAccountService = new LocalUserAccountServicesConnector(); |
@@ -292,10 +316,9 @@ namespace OpenSim.Tests.Common.Setup | |||
292 | // config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Tests.Common.dll:TestGridService"); | 316 | // config.Configs["GridService"].Set("LocalServiceModule", "OpenSim.Tests.Common.dll:TestGridService"); |
293 | m_userAccountService.AddRegion(testScene); | 317 | m_userAccountService.AddRegion(testScene); |
294 | m_userAccountService.RegionLoaded(testScene); | 318 | m_userAccountService.RegionLoaded(testScene); |
295 | //testScene.AddRegionModule(m_gridService.Name, m_gridService); | 319 | testScene.AddRegionModule(m_userAccountService.Name, m_userAccountService); |
296 | } | 320 | } |
297 | 321 | ||
298 | |||
299 | /// <summary> | 322 | /// <summary> |
300 | /// Setup modules for a scene using their default settings. | 323 | /// Setup modules for a scene using their default settings. |
301 | /// </summary> | 324 | /// </summary> |