aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorMelanie2010-03-15 17:23:35 +0000
committerMelanie2010-03-15 17:23:35 +0000
commitd3f33acc1a6a385ee19814286fe27cb5e48c1551 (patch)
tree07795e74a637ca63d96b5ee06950b8c1a7a99489 /OpenSim
parentMerge branch 'careminster' into careminster-presence-refactor (diff)
parentflip UVs for profile faces (diff)
downloadopensim-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 '')
-rw-r--r--OpenSim/Data/IGridUserData.cs2
-rw-r--r--OpenSim/Data/MSSQL/MSSQLAvatarData.cs2
-rw-r--r--OpenSim/Data/MSSQL/MSSQLGenericTableHandler.cs6
-rw-r--r--OpenSim/Data/MSSQL/MSSQLGridUserData.cs4
-rw-r--r--OpenSim/Data/MSSQL/MSSQLManager.cs4
-rw-r--r--OpenSim/Data/MSSQL/MSSQLUserAccountData.cs2
-rw-r--r--OpenSim/Data/MySQL/MySQLGenericTableHandler.cs2
-rw-r--r--OpenSim/Data/MySQL/MySQLGridUserData.cs2
-rw-r--r--OpenSim/Data/MySQL/MySQLPresenceData.cs2
-rw-r--r--OpenSim/Data/Null/NullPresenceData.cs16
-rw-r--r--OpenSim/Data/SQLite/SQLiteAuthenticationData.cs2
-rw-r--r--OpenSim/Framework/MultipartForm.cs29
-rw-r--r--OpenSim/Framework/SLUtil.cs33
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs6
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs7
-rw-r--r--OpenSim/Framework/UntrustedWebRequest.cs33
-rw-r--r--OpenSim/Framework/WebUtil.cs29
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs115
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs2
-rw-r--r--OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml3
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/Tests/PresenceConnectorsTests.cs4
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/LocalUserAccountServiceConnector.cs33
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/RemoteUserAccountServiceConnector.cs15
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/UserAccounts/UserAccountCache.cs44
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs10
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs2
-rw-r--r--OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs42
-rw-r--r--OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs29
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs8
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs43
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs35
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs88
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs6
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs3
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs15
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs13
-rw-r--r--OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETCharacter.cs33
-rw-r--r--OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETPrim.cs102
-rw-r--r--OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs99
-rw-r--r--OpenSim/Region/Physics/Meshing/PrimMesher.cs4403
-rw-r--r--OpenSim/Region/Physics/Meshing/SculptMesh.cs1272
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs4
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs2
-rw-r--r--OpenSim/Server/Base/ServerUtils.cs40
-rw-r--r--OpenSim/Server/Handlers/Hypergrid/UserAgentServerConnector.cs29
-rw-r--r--OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs2
-rw-r--r--OpenSim/Services/Base/ServiceBase.cs2
-rw-r--r--OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs4
-rw-r--r--OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs29
-rw-r--r--OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs31
-rw-r--r--OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs2
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs410
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs201
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs262
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs232
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs47
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs421
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs895
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs511
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs435
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs311
-rw-r--r--OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs1
-rw-r--r--OpenSim/Services/GridService/GridService.cs6
-rw-r--r--OpenSim/Services/GridService/HypergridLinker.cs5
-rw-r--r--OpenSim/Services/HypergridService/UserAgentService.cs29
-rw-r--r--OpenSim/Services/Interfaces/IUserAccountService.cs20
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginResponse.cs8
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginService.cs53
-rw-r--r--OpenSim/Services/PresenceService/PresenceService.cs4
-rw-r--r--OpenSim/Services/UserAccountService/GridUserService.cs2
-rw-r--r--OpenSim/Services/UserAccountService/UserAccountService.cs2
-rw-r--r--OpenSim/Tests/Common/Mock/MockUserAccountService.cs46
-rw-r--r--OpenSim/Tests/Common/Mock/TestScene.cs4
-rw-r--r--OpenSim/Tests/Common/Setup/SceneSetupHelpers.cs37
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 @@
1using 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
28using System;
2using System.Collections.Generic; 29using System.Collections.Generic;
3using System.Net; 30using System.Net;
4using System.IO; 31using 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 @@
1using 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
28using System;
2using System.Collections.Generic; 29using System.Collections.Generic;
3using System.Reflection; 30using System.Reflection;
4using log4net; 31using 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 @@
1using 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
28using System;
2using System.Collections.Generic; 29using System.Collections.Generic;
3using System.IO; 30using System.IO;
4using System.Net; 31using 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 @@
1using 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
28using System;
2using System.Collections.Generic; 29using System.Collections.Generic;
3using System.Collections.Specialized; 30using System.Collections.Specialized;
4using System.IO; 31using 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;
36using OpenSim.Region.Framework.Scenes; 36using OpenSim.Region.Framework.Scenes;
37 37
38namespace OpenSim.Region.CoreModules.Avatar.Attachments 38namespace 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;
31using OpenSim.Region.Framework.Scenes; 31using OpenSim.Region.Framework.Scenes;
32 32
33namespace OpenSim.Region.Framework.Interfaces 33namespace 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 @@
1using 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
28using System;
2using System.Collections.Generic; 29using System.Collections.Generic;
3 30
4using OpenSim.Framework; 31using 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
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31using System.IO; 31using System.IO;
32 32
33namespace PrimMesher 33namespace 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
31using System; 31using System;
32using System.Collections.Generic; 32using System.Collections.Generic;
33using System.Text; 33using System.Text;
34using System.IO; 34using System.IO;
35 35
36#if SYSTEM_DRAWING 36#if SYSTEM_DRAWING
37using System.Drawing; 37using System.Drawing;
38using System.Drawing.Imaging; 38using System.Drawing.Imaging;
39#endif 39#endif
40 40
41namespace PrimMesher 41namespace 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 @@
1using 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
28using System;
2using System.Collections; 29using System.Collections;
3using System.Collections.Generic; 30using System.Collections.Generic;
4using System.Net; 31using 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 @@
28using System; 28using System;
29 29
30namespace OpenSim.Services.Connectors 30namespace 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 @@
1using 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
28using System;
2using System.Collections; 29using System.Collections;
3using System.Collections.Generic; 30using System.Collections.Generic;
4using System.Drawing; 31using 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 @@
1using 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
28using System;
2using System.Collections; 29using System.Collections;
3using System.Collections.Generic; 30using System.Collections.Generic;
4using System.IO; 31using 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
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Reflection;
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40using OpenMetaverse;
41using OpenMetaverse.StructuredData;
42
43namespace 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
28using System;
29using System.Collections.Specialized;
30using System.Reflection;
31using log4net;
32using Mono.Addins;
33using Nini.Config;
34using OpenMetaverse;
35using OpenMetaverse.StructuredData;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Services.Interfaces;
40
41namespace 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
28using System;
29using System.Collections.Generic;
30using System.Collections.Specialized;
31using System.IO;
32using System.Net;
33using System.Reflection;
34using log4net;
35using Mono.Addins;
36using Nini.Config;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Server.Base;
41using OpenSim.Services.Interfaces;
42using OpenMetaverse;
43using OpenMetaverse.StructuredData;
44
45namespace 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
28using System;
29using System.Collections.Generic;
30using System.Collections.Specialized;
31using System.Reflection;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41
42using FriendInfo = OpenSim.Services.Interfaces.FriendInfo;
43
44namespace 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
28using System;
29using Mono.Addins;
30using Nini.Config;
31
32[assembly: Addin("SimianGrid", "1.0")]
33[assembly: AddinDependency("OpenSim", "0.5")]
34
35public 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
28using System;
29using System.Collections.Generic;
30using System.Collections.Specialized;
31using System.Net;
32using System.Reflection;
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Server.Base;
42using OpenMetaverse;
43using OpenMetaverse.StructuredData;
44
45using GridRegion = OpenSim.Services.Interfaces.GridRegion;
46
47namespace 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
28using System;
29using System.Collections.Generic;
30using System.Collections.Specialized;
31using System.Reflection;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Server.Base;
41using OpenSim.Services.Interfaces;
42
43namespace 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
28using System;
29using System.Collections.Generic;
30using System.Collections.Specialized;
31using System.Net;
32using System.Reflection;
33using log4net;
34using Mono.Addins;
35using Nini.Config;
36using OpenSim.Framework;
37using OpenSim.Framework.Servers.HttpServer;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Framework.Scenes;
40using OpenSim.Services.Interfaces;
41using OpenSim.Server.Base;
42using OpenMetaverse;
43using OpenMetaverse.StructuredData;
44
45using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
46
47namespace 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
28using System;
29using System.Collections.Generic;
30using System.Collections.Specialized;
31using System.Reflection;
32using log4net;
33using Mono.Addins;
34using Nini.Config;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using OpenSim.Framework;
38using OpenSim.Framework.Client;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Services.Interfaces;
42
43namespace 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
28using System;
29using System.Collections.Generic;
30using System.Collections.Specialized;
31using System.IO;
32using System.Reflection;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
35using OpenSim.Region.Framework.Scenes;
36using OpenSim.Services.Interfaces;
37using log4net;
38using Mono.Addins;
39using Nini.Config;
40using OpenMetaverse;
41using OpenMetaverse.StructuredData;
42
43namespace 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 @@
1using 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
28using System;
2using System.Collections.Generic; 29using System.Collections.Generic;
3using System.Net; 30using System.Net;
4using System.Reflection; 31using 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 @@
1using 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
28using System;
2using System.Collections.Generic; 29using System.Collections.Generic;
3using System.Net; 30using System.Net;
4using System.Reflection; 31using 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
28using System.Collections.Generic;
29using Nini.Config;
30using OpenMetaverse;
31using OpenSim.Services.Interfaces;
32
33namespace 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>