diff options
author | Michael Heilmann | 2015-05-19 15:18:45 -0400 |
---|---|---|
committer | Michael Heilmann | 2015-05-19 15:18:45 -0400 |
commit | 140ea04b9d692344d803fc87364fb252561725c3 (patch) | |
tree | d503b7ae17baca374d704b548fc7da512f512388 /OpenSim/Region | |
parent | Merge pull request #7 from gamucf/moses.metricsPhase2 (diff) | |
parent | resolve possible nullref when sending appearance packet. Thanks to zadark for... (diff) | |
download | opensim-SC_OLD-140ea04b9d692344d803fc87364fb252561725c3.zip opensim-SC_OLD-140ea04b9d692344d803fc87364fb252561725c3.tar.gz opensim-SC_OLD-140ea04b9d692344d803fc87364fb252561725c3.tar.bz2 opensim-SC_OLD-140ea04b9d692344d803fc87364fb252561725c3.tar.xz |
Merging Opensim upstream before generating patch
Diffstat (limited to 'OpenSim/Region')
50 files changed, 3036 insertions, 687 deletions
diff --git a/OpenSim/Region/Application/Properties/AssemblyInfo.cs b/OpenSim/Region/Application/Properties/AssemblyInfo.cs index 650425b..8652312 100644 --- a/OpenSim/Region/Application/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Application/Properties/AssemblyInfo.cs | |||
@@ -30,7 +30,7 @@ using Mono.Addins; | |||
30 | // Build Number | 30 | // Build Number |
31 | // Revision | 31 | // Revision |
32 | // | 32 | // |
33 | [assembly: AssemblyVersion("0.8.1.*")] | 33 | [assembly: AssemblyVersion("0.8.2.*")] |
34 | 34 | ||
35 | [assembly: AddinRoot("OpenSim", OpenSim.VersionInfo.VersionNumber)] | 35 | [assembly: AddinRoot("OpenSim", OpenSim.VersionInfo.VersionNumber)] |
36 | [assembly: ImportAddinAssembly("OpenSim.Framework.dll")] | 36 | [assembly: ImportAddinAssembly("OpenSim.Framework.dll")] |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs index 3bc0be8..264eaa3 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 053a6a2..30d1921 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | |||
@@ -201,11 +201,12 @@ namespace OpenSim.Region.ClientStack.Linden | |||
201 | 201 | ||
202 | Scene.EventManager.OnRegisterCaps += RegisterCaps; | 202 | Scene.EventManager.OnRegisterCaps += RegisterCaps; |
203 | 203 | ||
204 | int nworkers = 2; // was 2 | ||
204 | if (ProcessQueuedRequestsAsync && m_workerThreads == null) | 205 | if (ProcessQueuedRequestsAsync && m_workerThreads == null) |
205 | { | 206 | { |
206 | m_workerThreads = new Thread[2]; | 207 | m_workerThreads = new Thread[nworkers]; |
207 | 208 | ||
208 | for (uint i = 0; i < 2; i++) | 209 | for (uint i = 0; i < nworkers; i++) |
209 | { | 210 | { |
210 | m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests, | 211 | m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests, |
211 | String.Format("InventoryWorkerThread{0}", i), | 212 | String.Format("InventoryWorkerThread{0}", i), |
@@ -364,7 +365,11 @@ namespace OpenSim.Region.ClientStack.Linden | |||
364 | requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); | 365 | requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); |
365 | 366 | ||
366 | lock (responses) | 367 | lock (responses) |
368 | { | ||
369 | if (responses.ContainsKey(requestID)) | ||
370 | m_log.WarnFormat("[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054"); | ||
367 | responses[requestID] = response; | 371 | responses[requestID] = response; |
372 | } | ||
368 | 373 | ||
369 | WebFetchInvDescModule.ProcessedRequestsCount++; | 374 | WebFetchInvDescModule.ProcessedRequestsCount++; |
370 | } | 375 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 311dd31..284c5fa 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -3747,6 +3747,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3747 | avp.Sender.IsTrial = false; | 3747 | avp.Sender.IsTrial = false; |
3748 | avp.Sender.ID = agentID; | 3748 | avp.Sender.ID = agentID; |
3749 | avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; | 3749 | avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; |
3750 | avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0]; | ||
3750 | //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); | 3751 | //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString()); |
3751 | OutPacket(avp, ThrottleOutPacketType.Task); | 3752 | OutPacket(avp, ThrottleOutPacketType.Task); |
3752 | } | 3753 | } |
@@ -4465,7 +4466,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4465 | { | 4466 | { |
4466 | uint priority = 0; // time based ordering only | 4467 | uint priority = 0; // time based ordering only |
4467 | lock (m_entityProps.SyncRoot) | 4468 | lock (m_entityProps.SyncRoot) |
4468 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); | 4469 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,true)); |
4469 | } | 4470 | } |
4470 | 4471 | ||
4471 | private void ResendPropertyUpdate(ObjectPropertyUpdate update) | 4472 | private void ResendPropertyUpdate(ObjectPropertyUpdate update) |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs index 8ce1b85..8795c0c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs index 75f0774..f54298c 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs | |||
@@ -35,6 +35,7 @@ using System.Xml; | |||
35 | using log4net; | 35 | using log4net; |
36 | using OpenMetaverse; | 36 | using OpenMetaverse; |
37 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
38 | using OpenSim.Framework.Serialization.External; | ||
38 | 39 | ||
39 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
40 | using OpenSim.Region.Framework.Scenes.Serialization; | 41 | using OpenSim.Region.Framework.Scenes.Serialization; |
@@ -189,217 +190,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
189 | return Utils.StringToBytes(RewriteSOP(xml)); | 190 | return Utils.StringToBytes(RewriteSOP(xml)); |
190 | } | 191 | } |
191 | 192 | ||
192 | protected void TransformXml(XmlReader reader, XmlWriter writer) | ||
193 | { | ||
194 | // m_log.DebugFormat("[HG ASSET MAPPER]: Transforming XML"); | ||
195 | |||
196 | int sopDepth = -1; | ||
197 | UserAccount creator = null; | ||
198 | bool hasCreatorData = false; | ||
199 | |||
200 | while (reader.Read()) | ||
201 | { | ||
202 | // Console.WriteLine("Depth: {0}, name {1}", reader.Depth, reader.Name); | ||
203 | |||
204 | switch (reader.NodeType) | ||
205 | { | ||
206 | case XmlNodeType.Attribute: | ||
207 | // Console.WriteLine("FOUND ATTRIBUTE {0}", reader.Name); | ||
208 | writer.WriteAttributeString(reader.Prefix, reader.Name, reader.NamespaceURI, reader.Value); | ||
209 | break; | ||
210 | |||
211 | case XmlNodeType.CDATA: | ||
212 | writer.WriteCData(reader.Value); | ||
213 | break; | ||
214 | |||
215 | case XmlNodeType.Comment: | ||
216 | writer.WriteComment(reader.Value); | ||
217 | break; | ||
218 | |||
219 | case XmlNodeType.DocumentType: | ||
220 | writer.WriteDocType(reader.Name, reader.Value, null, null); | ||
221 | break; | ||
222 | |||
223 | case XmlNodeType.Element: | ||
224 | // m_log.DebugFormat("Depth {0} at element {1}", reader.Depth, reader.Name); | ||
225 | |||
226 | writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI); | ||
227 | |||
228 | if (reader.HasAttributes) | ||
229 | { | ||
230 | while (reader.MoveToNextAttribute()) | ||
231 | writer.WriteAttributeString(reader.Prefix, reader.Name, reader.NamespaceURI, reader.Value); | ||
232 | |||
233 | reader.MoveToElement(); | ||
234 | } | ||
235 | |||
236 | if (reader.LocalName == "SceneObjectPart") | ||
237 | { | ||
238 | if (sopDepth < 0) | ||
239 | { | ||
240 | sopDepth = reader.Depth; | ||
241 | // m_log.DebugFormat("[HG ASSET MAPPER]: Set sopDepth to {0}", sopDepth); | ||
242 | } | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | if (sopDepth >= 0 && reader.Depth == sopDepth + 1) | ||
247 | { | ||
248 | if (reader.Name == "CreatorID") | ||
249 | { | ||
250 | reader.Read(); | ||
251 | if (reader.NodeType == XmlNodeType.Element && reader.Name == "Guid" || reader.Name == "UUID") | ||
252 | { | ||
253 | reader.Read(); | ||
254 | |||
255 | if (reader.NodeType == XmlNodeType.Text) | ||
256 | { | ||
257 | UUID uuid = UUID.Zero; | ||
258 | UUID.TryParse(reader.Value, out uuid); | ||
259 | creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); | ||
260 | writer.WriteElementString("UUID", reader.Value); | ||
261 | reader.Read(); | ||
262 | } | ||
263 | else | ||
264 | { | ||
265 | // If we unexpected run across mixed content in this node, still carry on | ||
266 | // transforming the subtree (this replicates earlier behaviour). | ||
267 | TransformXml(reader, writer); | ||
268 | } | ||
269 | } | ||
270 | else | ||
271 | { | ||
272 | // If we unexpected run across mixed content in this node, still carry on | ||
273 | // transforming the subtree (this replicates earlier behaviour). | ||
274 | TransformXml(reader, writer); | ||
275 | } | ||
276 | } | ||
277 | else if (reader.Name == "CreatorData") | ||
278 | { | ||
279 | reader.Read(); | ||
280 | if (reader.NodeType == XmlNodeType.Text) | ||
281 | { | ||
282 | hasCreatorData = true; | ||
283 | writer.WriteString(reader.Value); | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | // If we unexpected run across mixed content in this node, still carry on | ||
288 | // transforming the subtree (this replicates earlier behaviour). | ||
289 | TransformXml(reader, writer); | ||
290 | } | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | |||
295 | if (reader.IsEmptyElement) | ||
296 | { | ||
297 | // m_log.DebugFormat("[HG ASSET MAPPER]: Writing end for empty element {0}", reader.Name); | ||
298 | writer.WriteEndElement(); | ||
299 | } | ||
300 | |||
301 | break; | ||
302 | |||
303 | case XmlNodeType.EndElement: | ||
304 | // m_log.DebugFormat("Depth {0} at EndElement", reader.Depth); | ||
305 | if (sopDepth == reader.Depth) | ||
306 | { | ||
307 | if (!hasCreatorData && creator != null) | ||
308 | writer.WriteElementString(reader.Prefix, "CreatorData", reader.NamespaceURI, string.Format("{0};{1} {2}", m_HomeURI, creator.FirstName, creator.LastName)); | ||
309 | |||
310 | // m_log.DebugFormat("[HG ASSET MAPPER]: Reset sopDepth"); | ||
311 | sopDepth = -1; | ||
312 | creator = null; | ||
313 | hasCreatorData = false; | ||
314 | } | ||
315 | writer.WriteEndElement(); | ||
316 | break; | ||
317 | |||
318 | case XmlNodeType.EntityReference: | ||
319 | writer.WriteEntityRef(reader.Name); | ||
320 | break; | ||
321 | |||
322 | case XmlNodeType.ProcessingInstruction: | ||
323 | writer.WriteProcessingInstruction(reader.Name, reader.Value); | ||
324 | break; | ||
325 | |||
326 | case XmlNodeType.Text: | ||
327 | writer.WriteString(reader.Value); | ||
328 | break; | ||
329 | |||
330 | case XmlNodeType.XmlDeclaration: | ||
331 | // For various reasons, not all serializations have xml declarations (or consistent ones) | ||
332 | // and as it's embedded inside a byte stream we don't need it anyway, so ignore. | ||
333 | break; | ||
334 | |||
335 | default: | ||
336 | m_log.WarnFormat( | ||
337 | "[HG ASSET MAPPER]: Unrecognized node {0} in asset XML transform in {1}", | ||
338 | reader.NodeType, m_scene.Name); | ||
339 | break; | ||
340 | } | ||
341 | } | ||
342 | } | ||
343 | |||
344 | protected string RewriteSOP(string xmlData) | 193 | protected string RewriteSOP(string xmlData) |
345 | { | 194 | { |
346 | // Console.WriteLine("Input XML [{0}]", xmlData); | 195 | // Console.WriteLine("Input XML [{0}]", xmlData); |
196 | return ExternalRepresentationUtils.RewriteSOP(xmlData, m_scene.Name, m_HomeURI, m_scene.UserAccountService, m_scene.RegionInfo.ScopeID); | ||
347 | 197 | ||
348 | using (StringWriter sw = new StringWriter()) | ||
349 | using (XmlTextWriter writer = new XmlTextWriter(sw)) | ||
350 | using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null)) | ||
351 | using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment })) | ||
352 | { | ||
353 | TransformXml(reader, writer); | ||
354 | |||
355 | // Console.WriteLine("Output: [{0}]", sw.ToString()); | ||
356 | |||
357 | return sw.ToString(); | ||
358 | } | ||
359 | |||
360 | // We are now taking the more complex streaming approach above because some assets can be very large | ||
361 | // and can trigger higher CPU use or possibly memory problems. | ||
362 | // XmlDocument doc = new XmlDocument(); | ||
363 | // doc.LoadXml(xml); | ||
364 | // XmlNodeList sops = doc.GetElementsByTagName("SceneObjectPart"); | ||
365 | // | ||
366 | // foreach (XmlNode sop in sops) | ||
367 | // { | ||
368 | // UserAccount creator = null; | ||
369 | // bool hasCreatorData = false; | ||
370 | // XmlNodeList nodes = sop.ChildNodes; | ||
371 | // foreach (XmlNode node in nodes) | ||
372 | // { | ||
373 | // if (node.Name == "CreatorID") | ||
374 | // { | ||
375 | // UUID uuid = UUID.Zero; | ||
376 | // UUID.TryParse(node.InnerText, out uuid); | ||
377 | // creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); | ||
378 | // } | ||
379 | // if (node.Name == "CreatorData" && node.InnerText != null && node.InnerText != string.Empty) | ||
380 | // hasCreatorData = true; | ||
381 | // | ||
382 | // //if (node.Name == "OwnerID") | ||
383 | // //{ | ||
384 | // // UserAccount owner = GetUser(node.InnerText); | ||
385 | // // if (owner != null) | ||
386 | // // node.InnerText = m_ProfileServiceURL + "/" + node.InnerText + "/" + owner.FirstName + " " + owner.LastName; | ||
387 | // //} | ||
388 | // } | ||
389 | // | ||
390 | // if (!hasCreatorData && creator != null) | ||
391 | // { | ||
392 | // XmlElement creatorData = doc.CreateElement("CreatorData"); | ||
393 | // creatorData.InnerText = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName; | ||
394 | // sop.AppendChild(creatorData); | ||
395 | // } | ||
396 | // } | ||
397 | // | ||
398 | // using (StringWriter wr = new StringWriter()) | ||
399 | // { | ||
400 | // doc.Save(wr); | ||
401 | // return wr.ToString(); | ||
402 | // } | ||
403 | } | 198 | } |
404 | 199 | ||
405 | // TODO: unused | 200 | // TODO: unused |
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs index 01814a1..e657f53 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs | |||
@@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library | |||
65 | { | 65 | { |
66 | InventoryFolderImpl folder = null; | 66 | InventoryFolderImpl folder = null; |
67 | InventoryCollection inv = new InventoryCollection(); | 67 | InventoryCollection inv = new InventoryCollection(); |
68 | inv.UserID = m_Library.Owner; | 68 | inv.OwnerID = m_Library.Owner; |
69 | 69 | ||
70 | if (folderID != m_Library.ID) | 70 | if (folderID != m_Library.ID) |
71 | { | 71 | { |
@@ -87,6 +87,34 @@ namespace OpenSim.Region.CoreModules.Framework.Library | |||
87 | return inv; | 87 | return inv; |
88 | } | 88 | } |
89 | 89 | ||
90 | public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) | ||
91 | { | ||
92 | InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length]; | ||
93 | int i = 0; | ||
94 | foreach (UUID fid in folderIDs) | ||
95 | { | ||
96 | invColl[i++] = GetFolderContent(principalID, fid); | ||
97 | } | ||
98 | |||
99 | return invColl; | ||
100 | } | ||
101 | |||
102 | public virtual InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs) | ||
103 | { | ||
104 | InventoryItemBase[] itemColl = new InventoryItemBase[itemIDs.Length]; | ||
105 | int i = 0; | ||
106 | InventoryItemBase item = new InventoryItemBase(); | ||
107 | item.Owner = principalID; | ||
108 | foreach (UUID fid in itemIDs) | ||
109 | { | ||
110 | item.ID = fid; | ||
111 | itemColl[i++] = GetItem(item); | ||
112 | } | ||
113 | |||
114 | return itemColl; | ||
115 | } | ||
116 | |||
117 | |||
90 | /// <summary> | 118 | /// <summary> |
91 | /// Add a new folder to the user's inventory | 119 | /// Add a new folder to the user's inventory |
92 | /// </summary> | 120 | /// </summary> |
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index ba71dc5..7ecbd26 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs | |||
@@ -154,7 +154,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
154 | 154 | ||
155 | #endregion ISharedRegionModule | 155 | #endregion ISharedRegionModule |
156 | 156 | ||
157 | 157 | ||
158 | #region Event Handlers | 158 | #region Event Handlers |
159 | 159 | ||
160 | void EventManager_OnPrimsLoaded(Scene s) | 160 | void EventManager_OnPrimsLoaded(Scene s) |
@@ -180,7 +180,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
180 | void HandleUUIDNameRequest(UUID uuid, IClientAPI client) | 180 | void HandleUUIDNameRequest(UUID uuid, IClientAPI client) |
181 | { | 181 | { |
182 | // m_log.DebugFormat( | 182 | // m_log.DebugFormat( |
183 | // "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}", | 183 | // "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}", |
184 | // uuid, remote_client.Name); | 184 | // uuid, remote_client.Name); |
185 | 185 | ||
186 | if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) | 186 | if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) |
@@ -212,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
212 | // appear to clear this when the user asks it to clear the cache, but others may not. | 212 | // appear to clear this when the user asks it to clear the cache, but others may not. |
213 | // | 213 | // |
214 | // So to avoid clients | 214 | // So to avoid clients |
215 | // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will | 215 | // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will |
216 | // instead drop the request entirely. | 216 | // instead drop the request entirely. |
217 | if (GetUser(uuid, out user)) | 217 | if (GetUser(uuid, out user)) |
218 | { | 218 | { |
@@ -220,7 +220,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
220 | } | 220 | } |
221 | // else | 221 | // else |
222 | // m_log.DebugFormat( | 222 | // m_log.DebugFormat( |
223 | // "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}", | 223 | // "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}", |
224 | // uuid, client.Name); | 224 | // uuid, client.Name); |
225 | }); | 225 | }); |
226 | } | 226 | } |
@@ -416,7 +416,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
416 | m_log.Debug("[USER MANAGEMENT MODULE]: GetServerURLs call failed ", e); | 416 | m_log.Debug("[USER MANAGEMENT MODULE]: GetServerURLs call failed ", e); |
417 | userdata.ServerURLs = new Dictionary<string, object>(); | 417 | userdata.ServerURLs = new Dictionary<string, object>(); |
418 | } | 418 | } |
419 | 419 | ||
420 | if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null) | 420 | if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null) |
421 | return userdata.ServerURLs[serverType].ToString(); | 421 | return userdata.ServerURLs[serverType].ToString(); |
422 | } | 422 | } |
@@ -620,7 +620,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
620 | AddUser(id, string.Empty, string.Empty, string.Empty); | 620 | AddUser(id, string.Empty, string.Empty, string.Empty); |
621 | } | 621 | } |
622 | else | 622 | else |
623 | { | 623 | { |
624 | string homeURL; | 624 | string homeURL; |
625 | string firstname = string.Empty; | 625 | string firstname = string.Empty; |
626 | string lastname = string.Empty; | 626 | string lastname = string.Empty; |
@@ -676,7 +676,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
676 | else | 676 | else |
677 | { | 677 | { |
678 | lock(m_UserCache) | 678 | lock(m_UserCache) |
679 | { | 679 | { |
680 | if(!m_UserCache.ContainsKey(id)) | 680 | if(!m_UserCache.ContainsKey(id)) |
681 | { | 681 | { |
682 | UserData newUser = new UserData(); | 682 | UserData newUser = new UserData(); |
@@ -726,6 +726,21 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
726 | "Show the bindings between user UUIDs and user names", | 726 | "Show the bindings between user UUIDs and user names", |
727 | String.Empty, | 727 | String.Empty, |
728 | HandleShowUsers); | 728 | HandleShowUsers); |
729 | |||
730 | MainConsole.Instance.Commands.AddCommand("Users", true, | ||
731 | "reset user cache", | ||
732 | "reset user cache", | ||
733 | "reset user cache to allow changed settings to be applied", | ||
734 | String.Empty, | ||
735 | HandleResetUserCache); | ||
736 | } | ||
737 | |||
738 | private void HandleResetUserCache(string module, string[] cmd) | ||
739 | { | ||
740 | lock(m_UserCache) | ||
741 | { | ||
742 | m_UserCache.Clear(); | ||
743 | } | ||
729 | } | 744 | } |
730 | 745 | ||
731 | private void HandleShowUser(string module, string[] cmd) | 746 | private void HandleShowUser(string module, string[] cmd) |
diff --git a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs b/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs index 1b1b319..64532df 100644 --- a/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/CoreModules/Properties/AssemblyInfo.cs | |||
@@ -30,7 +30,7 @@ using Mono.Addins; | |||
30 | // Build Number | 30 | // Build Number |
31 | // Revision | 31 | // Revision |
32 | // | 32 | // |
33 | [assembly: AssemblyVersion("0.8.1.*")] | 33 | [assembly: AssemblyVersion("0.8.2.*")] |
34 | 34 | ||
35 | 35 | ||
36 | [assembly: Addin("OpenSim.Region.CoreModules", OpenSim.VersionInfo.VersionNumber)] | 36 | [assembly: Addin("OpenSim.Region.CoreModules", OpenSim.VersionInfo.VersionNumber)] |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index e13ee42..6a83b42 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs | |||
@@ -389,6 +389,25 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
389 | return connector.GetFolderContent(userID, folderID); | 389 | return connector.GetFolderContent(userID, folderID); |
390 | } | 390 | } |
391 | 391 | ||
392 | public InventoryCollection[] GetMultipleFoldersContent(UUID userID, UUID[] folderIDs) | ||
393 | { | ||
394 | string invURL = GetInventoryServiceURL(userID); | ||
395 | |||
396 | if (invURL == null) // not there, forward to local inventory connector to resolve | ||
397 | lock (m_Lock) | ||
398 | return m_LocalGridInventoryService.GetMultipleFoldersContent(userID, folderIDs); | ||
399 | |||
400 | else | ||
401 | { | ||
402 | InventoryCollection[] coll = new InventoryCollection[folderIDs.Length]; | ||
403 | int i = 0; | ||
404 | foreach (UUID fid in folderIDs) | ||
405 | coll[i++] = GetFolderContent(userID, fid); | ||
406 | |||
407 | return coll; | ||
408 | } | ||
409 | } | ||
410 | |||
392 | public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) | 411 | public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) |
393 | { | 412 | { |
394 | //m_log.Debug("[HG INVENTORY CONNECTOR]: GetFolderItems " + folderID); | 413 | //m_log.Debug("[HG INVENTORY CONNECTOR]: GetFolderItems " + folderID); |
@@ -596,6 +615,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
596 | return connector.GetItem(item); | 615 | return connector.GetItem(item); |
597 | } | 616 | } |
598 | 617 | ||
618 | public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs) | ||
619 | { | ||
620 | if (itemIDs == null) | ||
621 | return new InventoryItemBase[0]; | ||
622 | //m_log.Debug("[HG INVENTORY CONNECTOR]: GetItem " + item.ID); | ||
623 | |||
624 | string invURL = GetInventoryServiceURL(userID); | ||
625 | |||
626 | if (invURL == null) // not there, forward to local inventory connector to resolve | ||
627 | lock (m_Lock) | ||
628 | return m_LocalGridInventoryService.GetMultipleItems(userID, itemIDs); | ||
629 | |||
630 | IInventoryService connector = GetConnector(invURL); | ||
631 | |||
632 | return connector.GetMultipleItems(userID, itemIDs); | ||
633 | } | ||
634 | |||
599 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) | 635 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) |
600 | { | 636 | { |
601 | if (folder == null) | 637 | if (folder == null) |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs index 499ca5e..71dc337 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs | |||
@@ -106,7 +106,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
106 | if (m_Inventories.TryGetValue(userID, out inv)) | 106 | if (m_Inventories.TryGetValue(userID, out inv)) |
107 | { | 107 | { |
108 | c = new InventoryCollection(); | 108 | c = new InventoryCollection(); |
109 | c.UserID = userID; | 109 | c.OwnerID = userID; |
110 | 110 | ||
111 | c.Folders = inv.Folders.FindAll(delegate(InventoryFolderBase f) | 111 | c.Folders = inv.Folders.FindAll(delegate(InventoryFolderBase f) |
112 | { | 112 | { |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs index cbe0e37..2f29a7c 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs | |||
@@ -195,6 +195,19 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
195 | return invCol; | 195 | return invCol; |
196 | } | 196 | } |
197 | 197 | ||
198 | public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) | ||
199 | { | ||
200 | InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length]; | ||
201 | int i = 0; | ||
202 | foreach (UUID fid in folderIDs) | ||
203 | { | ||
204 | invColl[i++] = GetFolderContent(principalID, fid); | ||
205 | } | ||
206 | |||
207 | return invColl; | ||
208 | |||
209 | } | ||
210 | |||
198 | public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) | 211 | public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) |
199 | { | 212 | { |
200 | return m_InventoryService.GetFolderItems(userID, folderID); | 213 | return m_InventoryService.GetFolderItems(userID, folderID); |
@@ -294,6 +307,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
294 | return item; | 307 | return item; |
295 | } | 308 | } |
296 | 309 | ||
310 | public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs) | ||
311 | { | ||
312 | return m_InventoryService.GetMultipleItems(userID, itemIDs); | ||
313 | } | ||
314 | |||
297 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) | 315 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) |
298 | { | 316 | { |
299 | return m_InventoryService.GetFolder(folder); | 317 | return m_InventoryService.GetFolder(folder); |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index 166e4a1..e0cc1e8 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs | |||
@@ -204,6 +204,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
204 | return invCol; | 204 | return invCol; |
205 | } | 205 | } |
206 | 206 | ||
207 | public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs) | ||
208 | { | ||
209 | return m_RemoteConnector.GetMultipleFoldersContent(principalID, folderIDs); | ||
210 | } | ||
211 | |||
207 | public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) | 212 | public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) |
208 | { | 213 | { |
209 | return m_RemoteConnector.GetFolderItems(userID, folderID); | 214 | return m_RemoteConnector.GetFolderItems(userID, folderID); |
@@ -298,6 +303,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
298 | return m_RemoteConnector.GetItem(item); | 303 | return m_RemoteConnector.GetItem(item); |
299 | } | 304 | } |
300 | 305 | ||
306 | public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs) | ||
307 | { | ||
308 | if (itemIDs == null) | ||
309 | return new InventoryItemBase[0]; | ||
310 | |||
311 | return m_RemoteConnector.GetMultipleItems(userID, itemIDs); | ||
312 | } | ||
313 | |||
301 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) | 314 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) |
302 | { | 315 | { |
303 | //m_log.DebugFormat("[XINVENTORY CONNECTOR]: GetFolder {0}", folder.ID); | 316 | //m_log.DebugFormat("[XINVENTORY CONNECTOR]: GetFolder {0}", folder.ID); |
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs index 4d99a6e..db66c83 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs | |||
@@ -335,7 +335,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver | |||
335 | if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home")) | 335 | if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home")) |
336 | { | 336 | { |
337 | //m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID); | 337 | //m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID); |
338 | string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), m_options["home"].ToString(), m_userAccountService, m_scopeID); | 338 | string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), string.Empty, m_options["home"].ToString(), m_userAccountService, m_scopeID); |
339 | asset.Data = Utils.StringToBytes(xml); | 339 | asset.Data = Utils.StringToBytes(xml); |
340 | } | 340 | } |
341 | return asset; | 341 | return asset; |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 13485bf..25e1454 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs | |||
@@ -98,11 +98,17 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
98 | // caches ExtendedLandData | 98 | // caches ExtendedLandData |
99 | private Cache parcelInfoCache; | 99 | private Cache parcelInfoCache; |
100 | 100 | ||
101 | |||
101 | /// <summary> | 102 | /// <summary> |
102 | /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions. | 103 | /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions. |
103 | /// </summary> | 104 | /// </summary> |
104 | private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>(); | 105 | private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>(); |
105 | 106 | ||
107 | // Enables limiting parcel layer info transmission when doing simple updates | ||
108 | private bool shouldLimitParcelLayerInfoToViewDistance { get; set; } | ||
109 | // "View distance" for sending parcel layer info if asked for from a view point in the region | ||
110 | private int parcelLayerViewDistance { get; set; } | ||
111 | |||
106 | #region INonSharedRegionModule Members | 112 | #region INonSharedRegionModule Members |
107 | 113 | ||
108 | public Type ReplaceableInterface | 114 | public Type ReplaceableInterface |
@@ -112,6 +118,14 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
112 | 118 | ||
113 | public void Initialise(IConfigSource source) | 119 | public void Initialise(IConfigSource source) |
114 | { | 120 | { |
121 | shouldLimitParcelLayerInfoToViewDistance = true; | ||
122 | parcelLayerViewDistance = 128; | ||
123 | IConfig landManagementConfig = source.Configs["LandManagement"]; | ||
124 | if (landManagementConfig != null) | ||
125 | { | ||
126 | shouldLimitParcelLayerInfoToViewDistance = landManagementConfig.GetBoolean("LimitParcelLayerUpdateDistance", shouldLimitParcelLayerInfoToViewDistance); | ||
127 | parcelLayerViewDistance = landManagementConfig.GetInt("ParcelLayerViewDistance", parcelLayerViewDistance); | ||
128 | } | ||
115 | } | 129 | } |
116 | 130 | ||
117 | public void AddRegion(Scene scene) | 131 | public void AddRegion(Scene scene) |
@@ -1129,11 +1143,26 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1129 | 1143 | ||
1130 | #region Parcel Updating | 1144 | #region Parcel Updating |
1131 | 1145 | ||
1146 | // Send parcel layer info for the whole region | ||
1147 | public void SendParcelOverlay(IClientAPI remote_client) | ||
1148 | { | ||
1149 | SendParcelOverlay(remote_client, 0, 0, (int)Constants.MaximumRegionSize); | ||
1150 | } | ||
1151 | |||
1132 | /// <summary> | 1152 | /// <summary> |
1133 | /// Where we send the ParcelOverlay packet to the client | 1153 | /// Send the parcel overlay blocks to the client. We send the overlay packets |
1154 | /// around a location and limited by the 'parcelLayerViewDistance'. This number | ||
1155 | /// is usually 128 and the code is arranged so it sends all the parcel overlay | ||
1156 | /// information for a whole region if the region is legacy sized (256x256). If | ||
1157 | /// the region is larger, only the parcel layer information is sent around | ||
1158 | /// the point specified. This reduces the problem of parcel layer information | ||
1159 | /// blocks increasing exponentially as region size increases. | ||
1134 | /// </summary> | 1160 | /// </summary> |
1135 | /// <param name="remote_client">The object representing the client</param> | 1161 | /// <param name="remote_client">The object representing the client</param> |
1136 | public void SendParcelOverlay(IClientAPI remote_client) | 1162 | /// <param name="xPlace">X position in the region to send surrounding parcel layer info</param> |
1163 | /// <param name="yPlace">y position in the region to send surrounding parcel layer info</param> | ||
1164 | /// <param name="layerViewDistance">Distance from x,y position to send parcel layer info</param> | ||
1165 | private void SendParcelOverlay(IClientAPI remote_client, int xPlace, int yPlace, int layerViewDistance) | ||
1137 | { | 1166 | { |
1138 | const int LAND_BLOCKS_PER_PACKET = 1024; | 1167 | const int LAND_BLOCKS_PER_PACKET = 1024; |
1139 | 1168 | ||
@@ -1141,15 +1170,58 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1141 | int byteArrayCount = 0; | 1170 | int byteArrayCount = 0; |
1142 | int sequenceID = 0; | 1171 | int sequenceID = 0; |
1143 | 1172 | ||
1173 | int xLow = 0; | ||
1174 | int xHigh = (int)m_scene.RegionInfo.RegionSizeX; | ||
1175 | int yLow = 0; | ||
1176 | int yHigh = (int)m_scene.RegionInfo.RegionSizeY; | ||
1177 | |||
1178 | if (shouldLimitParcelLayerInfoToViewDistance) | ||
1179 | { | ||
1180 | // Compute view distance around the given point | ||
1181 | int txLow = xPlace - layerViewDistance; | ||
1182 | int txHigh = xPlace + layerViewDistance; | ||
1183 | // If the distance is outside the region area, move the view distance to ba all in the region | ||
1184 | if (txLow < xLow) | ||
1185 | { | ||
1186 | txLow = xLow; | ||
1187 | txHigh = Math.Min(yLow + (layerViewDistance * 2), xHigh); | ||
1188 | } | ||
1189 | if (txHigh > xHigh) | ||
1190 | { | ||
1191 | txLow = Math.Max(xLow, xHigh - (layerViewDistance * 2)); | ||
1192 | txHigh = xHigh; | ||
1193 | } | ||
1194 | xLow = txLow; | ||
1195 | xHigh = txHigh; | ||
1196 | |||
1197 | int tyLow = yPlace - layerViewDistance; | ||
1198 | int tyHigh = yPlace + layerViewDistance; | ||
1199 | if (tyLow < yLow) | ||
1200 | { | ||
1201 | tyLow = yLow; | ||
1202 | tyHigh = Math.Min(yLow + (layerViewDistance * 2), yHigh); | ||
1203 | } | ||
1204 | if (tyHigh > yHigh) | ||
1205 | { | ||
1206 | tyLow = Math.Max(yLow, yHigh - (layerViewDistance * 2)); | ||
1207 | tyHigh = yHigh; | ||
1208 | } | ||
1209 | yLow = tyLow; | ||
1210 | yHigh = tyHigh; | ||
1211 | } | ||
1212 | // m_log.DebugFormat("{0} SendParcelOverlay: place=<{1},{2}>, vDist={3}, xLH=<{4},{5}, yLH=<{6},{7}>", | ||
1213 | // LogHeader, xPlace, yPlace, layerViewDistance, xLow, xHigh, yLow, yHigh); | ||
1214 | |||
1144 | // Layer data is in landUnit (4m) chunks | 1215 | // Layer data is in landUnit (4m) chunks |
1145 | for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++) | 1216 | for (int y = yLow; y < yHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++) |
1146 | { | 1217 | { |
1147 | for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++) | 1218 | for (int x = xLow; x < xHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++) |
1148 | { | 1219 | { |
1149 | byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * LandUnit, y * LandUnit), x, y, remote_client); | 1220 | byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * LandUnit, y * LandUnit), x, y, remote_client); |
1150 | byteArrayCount++; | 1221 | byteArrayCount++; |
1151 | if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) | 1222 | if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) |
1152 | { | 1223 | { |
1224 | // m_log.DebugFormat("{0} SendParcelOverlay, sending packet, bytes={1}", LogHeader, byteArray.Length); | ||
1153 | remote_client.SendLandParcelOverlay(byteArray, sequenceID); | 1225 | remote_client.SendLandParcelOverlay(byteArray, sequenceID); |
1154 | byteArrayCount = 0; | 1226 | byteArrayCount = 0; |
1155 | sequenceID++; | 1227 | sequenceID++; |
@@ -1162,6 +1234,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1162 | if (byteArrayCount != 0) | 1234 | if (byteArrayCount != 0) |
1163 | { | 1235 | { |
1164 | remote_client.SendLandParcelOverlay(byteArray, sequenceID); | 1236 | remote_client.SendLandParcelOverlay(byteArray, sequenceID); |
1237 | // m_log.DebugFormat("{0} SendParcelOverlay, complete sending packet, bytes={1}", LogHeader, byteArray.Length); | ||
1165 | } | 1238 | } |
1166 | } | 1239 | } |
1167 | 1240 | ||
@@ -1265,7 +1338,8 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1265 | temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client); | 1338 | temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client); |
1266 | } | 1339 | } |
1267 | 1340 | ||
1268 | SendParcelOverlay(remote_client); | 1341 | // Also send the layer data around the point of interest |
1342 | SendParcelOverlay(remote_client, (start_x + end_x) / 2, (start_y + end_y) / 2, parcelLayerViewDistance); | ||
1269 | } | 1343 | } |
1270 | 1344 | ||
1271 | public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client) | 1345 | public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client) |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Features/RectangleFeature.cs b/OpenSim/Region/CoreModules/World/Terrain/Features/RectangleFeature.cs deleted file mode 100644 index 33c3fbe..0000000 --- a/OpenSim/Region/CoreModules/World/Terrain/Features/RectangleFeature.cs +++ /dev/null | |||
@@ -1,149 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using OpenSim.Region.CoreModules.World.Terrain; | ||
30 | using OpenSim.Region.Framework.Interfaces; | ||
31 | |||
32 | namespace OpenSim.Region.CoreModules.World.Terrain.Features | ||
33 | { | ||
34 | public class RectangleFeature : TerrainFeature | ||
35 | { | ||
36 | public RectangleFeature(ITerrainModule module) : base(module) | ||
37 | { | ||
38 | } | ||
39 | |||
40 | public override string CreateFeature(ITerrainChannel map, string[] args) | ||
41 | { | ||
42 | string val; | ||
43 | string result; | ||
44 | if (args.Length < 7) | ||
45 | { | ||
46 | result = "Usage: " + GetUsage(); | ||
47 | } | ||
48 | else | ||
49 | { | ||
50 | result = String.Empty; | ||
51 | |||
52 | float targetElevation; | ||
53 | val = base.parseFloat(args[3], out targetElevation); | ||
54 | if (val != String.Empty) | ||
55 | { | ||
56 | result = val; | ||
57 | } | ||
58 | |||
59 | int xOrigin; | ||
60 | val = base.parseInt(args[4], out xOrigin); | ||
61 | if (val != String.Empty) | ||
62 | { | ||
63 | result = val; | ||
64 | } | ||
65 | else if (xOrigin < 0 || xOrigin >= map.Width) | ||
66 | { | ||
67 | result = "x-origin must be within the region"; | ||
68 | } | ||
69 | |||
70 | int yOrigin; | ||
71 | val = base.parseInt(args[5], out yOrigin); | ||
72 | if (val != String.Empty) | ||
73 | { | ||
74 | result = val; | ||
75 | } | ||
76 | else if (yOrigin < 0 || yOrigin >= map.Height) | ||
77 | { | ||
78 | result = "y-origin must be within the region"; | ||
79 | } | ||
80 | |||
81 | int xDelta; | ||
82 | val = base.parseInt(args[6], out xDelta); | ||
83 | if (val != String.Empty) | ||
84 | { | ||
85 | result = val; | ||
86 | } | ||
87 | else if (xDelta <= 0) | ||
88 | { | ||
89 | result = "x-size must be greater than zero"; | ||
90 | } | ||
91 | |||
92 | int yDelta; | ||
93 | if (args.Length > 7) | ||
94 | { | ||
95 | val = base.parseInt(args[7], out yDelta); | ||
96 | if (val != String.Empty) | ||
97 | { | ||
98 | result = val; | ||
99 | } | ||
100 | else if (yDelta <= 0) | ||
101 | { | ||
102 | result = "y-size must be greater than zero"; | ||
103 | } | ||
104 | } | ||
105 | else | ||
106 | { | ||
107 | // no y-size.. make it square | ||
108 | yDelta = xDelta; | ||
109 | } | ||
110 | |||
111 | // slightly more complex validation, if required. | ||
112 | if (result == String.Empty) | ||
113 | { | ||
114 | if (xOrigin + xDelta > map.Width) | ||
115 | { | ||
116 | result = "(x-origin + x-size) must be within the region size"; | ||
117 | } | ||
118 | else if (yOrigin + yDelta > map.Height) | ||
119 | { | ||
120 | result = "(y-origin + y-size) must be within the region size"; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | // if it's all good, then do the work | ||
125 | if (result == String.Empty) | ||
126 | { | ||
127 | int yPos = yOrigin + yDelta; | ||
128 | while(--yPos >= yOrigin) | ||
129 | { | ||
130 | int xPos = xOrigin + xDelta; | ||
131 | while(--xPos >= xOrigin) | ||
132 | { | ||
133 | map[xPos, yPos] = (double)targetElevation; | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | |||
139 | return result; | ||
140 | } | ||
141 | |||
142 | public override string GetUsage() | ||
143 | { | ||
144 | return "rectangle <height> <x-origin> <y-origin> <x-size> [<y-size>]"; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | } | ||
149 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainFeature.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs index 701a729..0e0a0e4 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainFeature.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs | |||
@@ -24,65 +24,53 @@ | |||
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 | using System; | ||
28 | using System.Reflection; | ||
29 | 27 | ||
28 | using System; | ||
30 | using OpenSim.Region.Framework.Interfaces; | 29 | using OpenSim.Region.Framework.Interfaces; |
31 | 30 | ||
32 | namespace OpenSim.Region.CoreModules.World.Terrain | 31 | namespace OpenSim.Region.CoreModules.World.Terrain |
33 | { | 32 | { |
34 | public abstract class TerrainFeature : ITerrainFeature | 33 | public interface ITerrainModifier |
35 | { | 34 | { |
36 | protected ITerrainModule m_module; | 35 | /// <summary> |
37 | 36 | /// Creates the feature. | |
38 | protected TerrainFeature(ITerrainModule module) | 37 | /// </summary> |
39 | { | 38 | /// <returns> |
40 | m_module = module; | 39 | /// Empty string if successful, otherwise error message. |
41 | } | 40 | /// </returns> |
42 | 41 | /// <param name='map'> | |
43 | public abstract string CreateFeature(ITerrainChannel map, string[] args); | 42 | /// ITerrainChannel holding terrain data. |
44 | 43 | /// </param> | |
45 | public abstract string GetUsage(); | 44 | /// <param name='args'> |
46 | 45 | /// command-line arguments from console. | |
47 | protected string parseFloat(String s, out float f) | 46 | /// </param> |
48 | { | 47 | string ModifyTerrain(ITerrainChannel map, string[] args); |
49 | string result; | ||
50 | double d; | ||
51 | if (Double.TryParse(s, out d)) | ||
52 | { | ||
53 | try | ||
54 | { | ||
55 | f = (float)d; | ||
56 | result = String.Empty; | ||
57 | } | ||
58 | catch(InvalidCastException) | ||
59 | { | ||
60 | result = String.Format("{0} is invalid", s); | ||
61 | f = -1.0f; | ||
62 | } | ||
63 | } | ||
64 | else | ||
65 | { | ||
66 | f = -1.0f; | ||
67 | result = String.Format("{0} is invalid", s); | ||
68 | } | ||
69 | return result; | ||
70 | } | ||
71 | 48 | ||
72 | protected string parseInt(String s, out int i) | 49 | /// <summary> |
73 | { | 50 | /// Gets a string describing the usage. |
74 | string result; | 51 | /// </summary> |
75 | if (Int32.TryParse(s, out i)) | 52 | /// <returns> |
76 | { | 53 | /// A string describing parameters for creating the feature. |
77 | result = String.Empty; | 54 | /// Format is "feature-name <arg1> <arg2> ..." |
78 | } | 55 | /// </returns> |
79 | else | 56 | string GetUsage(); |
80 | { | ||
81 | result = String.Format("{0} is invalid", s); | ||
82 | } | ||
83 | return result; | ||
84 | } | ||
85 | 57 | ||
58 | /// <summary> | ||
59 | /// Apply the appropriate operation on the specified map, at (x, y). | ||
60 | /// </summary> | ||
61 | /// <param name='map'> | ||
62 | /// Map. | ||
63 | /// </param> | ||
64 | /// <param name='data'> | ||
65 | /// Data. | ||
66 | /// </param> | ||
67 | /// <param name='x'> | ||
68 | /// X. | ||
69 | /// </param> | ||
70 | /// <param name='y'> | ||
71 | /// Y. | ||
72 | /// </param> | ||
73 | double operate(double[,] map, TerrainModifierData data, int x, int y); | ||
86 | } | 74 | } |
87 | 75 | ||
88 | } | 76 | } |
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs new file mode 100644 index 0000000..32f1de9 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/FillModifier.cs | |||
@@ -0,0 +1,93 @@ | |||
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 | using System; | ||
28 | |||
29 | using OpenSim.Region.CoreModules.World.Terrain; | ||
30 | using OpenSim.Region.Framework.Interfaces; | ||
31 | |||
32 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
33 | { | ||
34 | public class FillModifier : TerrainModifier | ||
35 | { | ||
36 | |||
37 | public FillModifier(ITerrainModule module) : base(module) | ||
38 | { | ||
39 | } | ||
40 | |||
41 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
42 | { | ||
43 | string result; | ||
44 | if (args.Length < 3) | ||
45 | { | ||
46 | result = "Usage: " + GetUsage(); | ||
47 | } | ||
48 | else | ||
49 | { | ||
50 | TerrainModifierData data; | ||
51 | result = this.parseParameters(args, out data); | ||
52 | |||
53 | // Context-specific validation | ||
54 | if (result == String.Empty) | ||
55 | { | ||
56 | if (data.shape == String.Empty) | ||
57 | { | ||
58 | data.shape = "rectangle"; | ||
59 | data.x0 = 0; | ||
60 | data.y0 = 0; | ||
61 | data.dx = map.Width; | ||
62 | data.dy = map.Height; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | // if it's all good, then do the work | ||
67 | if (result == String.Empty) | ||
68 | { | ||
69 | this.applyModification(map, data); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | return result; | ||
74 | } | ||
75 | |||
76 | public override string GetUsage() | ||
77 | { | ||
78 | string val = "fill <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]" | ||
79 | + "\nSets all points within the specified range to the specified value."; | ||
80 | return val; | ||
81 | } | ||
82 | |||
83 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
84 | { | ||
85 | double factor = this.computeBevel(data, x, y); | ||
86 | double result = data.elevation - (data.elevation - data.bevelevation) * factor; | ||
87 | return result; | ||
88 | } | ||
89 | |||
90 | } | ||
91 | |||
92 | } | ||
93 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs new file mode 100644 index 0000000..2ab4bcc --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/LowerModifier.cs | |||
@@ -0,0 +1,92 @@ | |||
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 | using System; | ||
28 | using OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
32 | { | ||
33 | public class LowerModifier : TerrainModifier | ||
34 | { | ||
35 | public LowerModifier(ITerrainModule module) : base(module) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
40 | { | ||
41 | string result; | ||
42 | if (args.Length < 3) | ||
43 | { | ||
44 | result = "Usage: " + GetUsage(); | ||
45 | } | ||
46 | else | ||
47 | { | ||
48 | TerrainModifierData data; | ||
49 | result = this.parseParameters(args, out data); | ||
50 | |||
51 | // Context-specific validation | ||
52 | if (result == String.Empty) | ||
53 | { | ||
54 | if (data.shape == String.Empty) | ||
55 | { | ||
56 | data.shape = "rectangle"; | ||
57 | data.x0 = 0; | ||
58 | data.y0 = 0; | ||
59 | data.dx = map.Width; | ||
60 | data.dy = map.Height; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | // if it's all good, then do the work | ||
65 | if (result == String.Empty) | ||
66 | { | ||
67 | this.applyModification(map, data); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | return result; | ||
72 | } | ||
73 | |||
74 | public override string GetUsage() | ||
75 | { | ||
76 | string val = "lower <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]" | ||
77 | + "\nLowers all points within the specified range by the specified amount."; | ||
78 | return val; | ||
79 | |||
80 | } | ||
81 | |||
82 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
83 | { | ||
84 | double factor = this.computeBevel(data, x, y); | ||
85 | double result = map[x, y] - (data.elevation - (data.elevation - data.bevelevation) * factor); | ||
86 | return result; | ||
87 | } | ||
88 | |||
89 | } | ||
90 | |||
91 | } | ||
92 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs new file mode 100644 index 0000000..0939c0a --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MaxModifier.cs | |||
@@ -0,0 +1,92 @@ | |||
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 | using System; | ||
28 | using OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
32 | { | ||
33 | public class MaxModifier : TerrainModifier | ||
34 | { | ||
35 | public MaxModifier(ITerrainModule module) : base(module) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
40 | { | ||
41 | string result; | ||
42 | if (args.Length < 3) | ||
43 | { | ||
44 | result = "Usage: " + GetUsage(); | ||
45 | } | ||
46 | else | ||
47 | { | ||
48 | TerrainModifierData data; | ||
49 | result = this.parseParameters(args, out data); | ||
50 | |||
51 | // Context-specific validation | ||
52 | if (result == String.Empty) | ||
53 | { | ||
54 | if (data.shape == String.Empty) | ||
55 | { | ||
56 | data.shape = "rectangle"; | ||
57 | data.x0 = 0; | ||
58 | data.y0 = 0; | ||
59 | data.dx = map.Width; | ||
60 | data.dy = map.Height; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | // if it's all good, then do the work | ||
65 | if (result == String.Empty) | ||
66 | { | ||
67 | this.applyModification(map, data); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | return result; | ||
72 | } | ||
73 | |||
74 | public override string GetUsage() | ||
75 | { | ||
76 | string val = "max <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]" | ||
77 | + "\nEnsures that all points within the specified range are no higher than the specified value."; | ||
78 | return val; | ||
79 | |||
80 | } | ||
81 | |||
82 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
83 | { | ||
84 | double factor = this.computeBevel(data, x, y); | ||
85 | double result = Math.Min(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]); | ||
86 | return result; | ||
87 | } | ||
88 | |||
89 | } | ||
90 | |||
91 | } | ||
92 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs new file mode 100644 index 0000000..cbbccc0 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/MinModifier.cs | |||
@@ -0,0 +1,92 @@ | |||
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 | using System; | ||
28 | using OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
32 | { | ||
33 | public class MinModifier : TerrainModifier | ||
34 | { | ||
35 | public MinModifier(ITerrainModule module) : base(module) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
40 | { | ||
41 | string result; | ||
42 | if (args.Length < 3) | ||
43 | { | ||
44 | result = "Usage: " + GetUsage(); | ||
45 | } | ||
46 | else | ||
47 | { | ||
48 | TerrainModifierData data; | ||
49 | result = this.parseParameters(args, out data); | ||
50 | |||
51 | // Context-specific validation | ||
52 | if (result == String.Empty) | ||
53 | { | ||
54 | if (data.shape == String.Empty) | ||
55 | { | ||
56 | data.shape = "rectangle"; | ||
57 | data.x0 = 0; | ||
58 | data.y0 = 0; | ||
59 | data.dx = map.Width; | ||
60 | data.dy = map.Height; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | // if it's all good, then do the work | ||
65 | if (result == String.Empty) | ||
66 | { | ||
67 | this.applyModification(map, data); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | return result; | ||
72 | } | ||
73 | |||
74 | public override string GetUsage() | ||
75 | { | ||
76 | string val = "min <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]" | ||
77 | + "\nEnsures that all points within the specified range are no lower than the specified value."; | ||
78 | return val; | ||
79 | |||
80 | } | ||
81 | |||
82 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
83 | { | ||
84 | double factor = this.computeBevel(data, x, y); | ||
85 | double result = Math.Max(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]); | ||
86 | return result; | ||
87 | } | ||
88 | |||
89 | } | ||
90 | |||
91 | } | ||
92 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs new file mode 100644 index 0000000..d6b95d0 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/NoiseModifier.cs | |||
@@ -0,0 +1,108 @@ | |||
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 | using System; | ||
28 | using OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | using OpenSim.Region.Framework.Scenes; | ||
31 | |||
32 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
33 | { | ||
34 | public class NoiseModifier : TerrainModifier | ||
35 | { | ||
36 | public NoiseModifier(ITerrainModule module) : base(module) | ||
37 | { | ||
38 | } | ||
39 | |||
40 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
41 | { | ||
42 | string result; | ||
43 | if (args.Length < 3) | ||
44 | { | ||
45 | result = "Usage: " + GetUsage(); | ||
46 | } | ||
47 | else | ||
48 | { | ||
49 | TerrainModifierData data; | ||
50 | result = this.parseParameters(args, out data); | ||
51 | |||
52 | // Context-specific validation | ||
53 | if (result == String.Empty) | ||
54 | { | ||
55 | if (data.bevel == "taper") | ||
56 | { | ||
57 | if (data.bevelevation < 0.0 || data.bevelevation > 1.0) | ||
58 | { | ||
59 | result = String.Format("Taper must be 0.0 to 1.0: {0}", data.bevelevation); | ||
60 | } | ||
61 | } | ||
62 | else | ||
63 | { | ||
64 | data.bevelevation = 1.0f; | ||
65 | } | ||
66 | |||
67 | if (data.elevation < 0.0 || data.elevation > 1.0) | ||
68 | { | ||
69 | result = String.Format("Noise strength must be 0.0 to 1.0: {0}", data.elevation); | ||
70 | } | ||
71 | |||
72 | if (data.shape == String.Empty) | ||
73 | { | ||
74 | data.shape = "rectangle"; | ||
75 | data.x0 = 0; | ||
76 | data.y0 = 0; | ||
77 | data.dx = map.Width; | ||
78 | data.dy = map.Height; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | // if it's all good, then do the work | ||
83 | if (result == String.Empty) | ||
84 | { | ||
85 | this.applyModification(map, data); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | return result; | ||
90 | } | ||
91 | |||
92 | public override string GetUsage() | ||
93 | { | ||
94 | string val = "noise <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]" | ||
95 | + "\nAdds noise to all points within the specified range."; | ||
96 | return val; | ||
97 | } | ||
98 | |||
99 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
100 | { | ||
101 | double factor = this.computeBevel(data, x, y); | ||
102 | double noise = TerrainUtil.PerlinNoise2D((double)x / map.GetLength(0), (double)y / map.GetLength(1), 8, 1.0); | ||
103 | return map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor) * (noise - .5); | ||
104 | } | ||
105 | |||
106 | } | ||
107 | |||
108 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs new file mode 100644 index 0000000..35fb9d6 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/RaiseModifier.cs | |||
@@ -0,0 +1,92 @@ | |||
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 | using System; | ||
28 | using OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
32 | { | ||
33 | public class RaiseModifier : TerrainModifier | ||
34 | { | ||
35 | public RaiseModifier(ITerrainModule module) : base(module) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
40 | { | ||
41 | string result; | ||
42 | if (args.Length < 3) | ||
43 | { | ||
44 | result = "Usage: " + GetUsage(); | ||
45 | } | ||
46 | else | ||
47 | { | ||
48 | TerrainModifierData data; | ||
49 | result = this.parseParameters(args, out data); | ||
50 | |||
51 | // Context-specific validation | ||
52 | if (result == String.Empty) | ||
53 | { | ||
54 | if (data.shape == String.Empty) | ||
55 | { | ||
56 | data.shape = "rectangle"; | ||
57 | data.x0 = 0; | ||
58 | data.y0 = 0; | ||
59 | data.dx = map.Width; | ||
60 | data.dy = map.Height; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | // if it's all good, then do the work | ||
65 | if (result == String.Empty) | ||
66 | { | ||
67 | this.applyModification(map, data); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | return result; | ||
72 | } | ||
73 | |||
74 | public override string GetUsage() | ||
75 | { | ||
76 | string val = "raise <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]" | ||
77 | + "\nRaises all points within the specified range by the specified amount."; | ||
78 | return val; | ||
79 | |||
80 | } | ||
81 | |||
82 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
83 | { | ||
84 | double factor = this.computeBevel(data, x, y); | ||
85 | double result = map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor); | ||
86 | return result; | ||
87 | } | ||
88 | |||
89 | } | ||
90 | |||
91 | } | ||
92 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs new file mode 100644 index 0000000..9f8d5b2 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/Modifiers/SmoothModifier.cs | |||
@@ -0,0 +1,131 @@ | |||
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 | using System; | ||
28 | using OpenSim.Region.CoreModules.World.Terrain; | ||
29 | using OpenSim.Region.Framework.Interfaces; | ||
30 | |||
31 | namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers | ||
32 | { | ||
33 | public class SmoothModifier : TerrainModifier | ||
34 | { | ||
35 | public SmoothModifier(ITerrainModule module) : base(module) | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public override string ModifyTerrain(ITerrainChannel map, string[] args) | ||
40 | { | ||
41 | string result; | ||
42 | if (args.Length < 3) | ||
43 | { | ||
44 | result = "Usage: " + GetUsage(); | ||
45 | } | ||
46 | else | ||
47 | { | ||
48 | TerrainModifierData data; | ||
49 | result = this.parseParameters(args, out data); | ||
50 | |||
51 | // Context-specific validation | ||
52 | if (result == String.Empty) | ||
53 | { | ||
54 | if (data.bevel == "taper") | ||
55 | { | ||
56 | if (data.bevelevation < 0.01 || data.bevelevation > 0.99) | ||
57 | { | ||
58 | result = String.Format("Taper must be 0.01 to 0.99: {0}", data.bevelevation); | ||
59 | } | ||
60 | } | ||
61 | else | ||
62 | { | ||
63 | data.bevelevation = 2.0f / 3.0f; | ||
64 | } | ||
65 | |||
66 | if (data.elevation < 0.0 || data.elevation > 1.0) | ||
67 | { | ||
68 | result = String.Format("Smoothing strength must be 0.0 to 1.0: {0}", data.elevation); | ||
69 | } | ||
70 | |||
71 | if (data.shape == String.Empty) | ||
72 | { | ||
73 | data.shape = "rectangle"; | ||
74 | data.x0 = 0; | ||
75 | data.y0 = 0; | ||
76 | data.dx = map.Width; | ||
77 | data.dy = map.Height; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | // if it's all good, then do the work | ||
82 | if (result == String.Empty) | ||
83 | { | ||
84 | this.applyModification(map, data); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | return result; | ||
89 | } | ||
90 | |||
91 | public override string GetUsage() | ||
92 | { | ||
93 | string val = "smooth <strength> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<fraction>]" | ||
94 | + "\nSmooths all points within the specified range using a simple averaging algorithm."; | ||
95 | return val; | ||
96 | } | ||
97 | |||
98 | public override double operate(double[,] map, TerrainModifierData data, int x, int y) | ||
99 | { | ||
100 | double[] scale = new double[3]; | ||
101 | scale[0] = data.elevation; | ||
102 | scale[1] = ((1.0 - scale[0]) * data.bevelevation) / 8.0; | ||
103 | scale[2] = ((1.0 - scale[0]) * (1.0 - data.bevelevation)) / 16.0; | ||
104 | int xMax = map.GetLength(0); | ||
105 | int yMax = map.GetLength(1); | ||
106 | double result; | ||
107 | if ((x == 0) || (y == 0) || (x == (xMax - 1)) || (y == (yMax - 1))) | ||
108 | { | ||
109 | result = map[x, y]; | ||
110 | } | ||
111 | else | ||
112 | { | ||
113 | result = 0.0; | ||
114 | for(int yPos = (y - 2); yPos < (y + 3); yPos++) | ||
115 | { | ||
116 | int yVal = (yPos <= 0) ? 0 : ((yPos < yMax) ? yPos : yMax - 1); | ||
117 | for(int xPos = (x - 2); xPos < (x + 3); xPos++) | ||
118 | { | ||
119 | int xVal = (xPos <= 0) ? 0 : ((xPos < xMax) ? xPos : xMax - 1); | ||
120 | int dist = Math.Max(Math.Abs(x - xVal), Math.Abs(y - yVal)); | ||
121 | result += map[xVal, yVal] * scale[dist]; | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | return result; | ||
126 | } | ||
127 | |||
128 | } | ||
129 | |||
130 | } | ||
131 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs new file mode 100644 index 0000000..7ebd08e --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifier.cs | |||
@@ -0,0 +1,378 @@ | |||
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 | using System; | ||
28 | using System.Reflection; | ||
29 | using log4net; | ||
30 | |||
31 | using OpenSim.Region.Framework.Interfaces; | ||
32 | |||
33 | namespace OpenSim.Region.CoreModules.World.Terrain | ||
34 | { | ||
35 | public abstract class TerrainModifier : ITerrainModifier | ||
36 | { | ||
37 | protected ITerrainModule m_module; | ||
38 | protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
39 | |||
40 | protected TerrainModifier(ITerrainModule module) | ||
41 | { | ||
42 | m_module = module; | ||
43 | } | ||
44 | |||
45 | public abstract string ModifyTerrain(ITerrainChannel map, string[] args); | ||
46 | |||
47 | public abstract string GetUsage(); | ||
48 | |||
49 | public abstract double operate(double[,] map, TerrainModifierData data, int x, int y); | ||
50 | |||
51 | protected String parseParameters(string[] args, out TerrainModifierData data) | ||
52 | { | ||
53 | string val; | ||
54 | string arg; | ||
55 | string result; | ||
56 | data = new TerrainModifierData(); | ||
57 | data.shape = String.Empty; | ||
58 | data.bevel = String.Empty; | ||
59 | data.dx = 0; | ||
60 | data.dy = 0; | ||
61 | if (args.Length < 4) | ||
62 | { | ||
63 | result = "Usage: " + GetUsage(); | ||
64 | } | ||
65 | else | ||
66 | { | ||
67 | result = this.parseFloat(args[3], out data.elevation); | ||
68 | } | ||
69 | if (result == String.Empty) | ||
70 | { | ||
71 | int index = 3; | ||
72 | while(++index < args.Length && result == String.Empty) | ||
73 | { | ||
74 | arg = args[index]; | ||
75 | // check for shape | ||
76 | if (arg.StartsWith("-rec=") || arg.StartsWith("-ell=")) | ||
77 | { | ||
78 | if (data.shape != String.Empty) | ||
79 | { | ||
80 | result = "Only 1 '-rec' or '-ell' parameter is permitted."; | ||
81 | } | ||
82 | else | ||
83 | { | ||
84 | data.shape = arg.StartsWith("-ell=") ? "ellipse" : "rectangle"; | ||
85 | val = arg.Substring(arg.IndexOf("=") + 1); | ||
86 | string[] coords = val.Split(new char[] {','}); | ||
87 | if ((coords.Length < 3) || (coords.Length > 4)) | ||
88 | { | ||
89 | result = String.Format("Bad format for shape parameter {0}", arg); | ||
90 | } | ||
91 | else | ||
92 | { | ||
93 | result = this.parseInt(coords[0], out data.x0); | ||
94 | if (result == String.Empty) | ||
95 | { | ||
96 | result = this.parseInt(coords[1], out data.y0); | ||
97 | } | ||
98 | if (result == String.Empty) | ||
99 | { | ||
100 | result = this.parseInt(coords[2], out data.dx); | ||
101 | } | ||
102 | if (result == String.Empty) | ||
103 | { | ||
104 | if (coords.Length == 4) | ||
105 | { | ||
106 | result = this.parseInt(coords[3], out data.dy); | ||
107 | } | ||
108 | else | ||
109 | { | ||
110 | data.dy = data.dx; | ||
111 | } | ||
112 | } | ||
113 | if (result == String.Empty) | ||
114 | { | ||
115 | if ((data.dx <= 0) || (data.dy <= 0)) | ||
116 | { | ||
117 | result = "Shape sizes must be positive integers"; | ||
118 | } | ||
119 | } | ||
120 | else | ||
121 | { | ||
122 | result = String.Format("Bad value in shape parameters {0}", arg); | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | else if (arg.StartsWith("-taper=")) | ||
128 | { | ||
129 | if (data.bevel != String.Empty) | ||
130 | { | ||
131 | result = "Only 1 '-taper' parameter is permitted."; | ||
132 | } | ||
133 | else | ||
134 | { | ||
135 | data.bevel = "taper"; | ||
136 | val = arg.Substring(arg.IndexOf("=") + 1); | ||
137 | result = this.parseFloat(val, out data.bevelevation); | ||
138 | if (result != String.Empty) | ||
139 | { | ||
140 | result = String.Format("Bad format for taper parameter {0}", arg); | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | result = String.Format("Unrecognized parameter {0}", arg); | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | return result; | ||
151 | } | ||
152 | |||
153 | protected string parseFloat(String s, out float f) | ||
154 | { | ||
155 | string result; | ||
156 | double d; | ||
157 | if (Double.TryParse(s, out d)) | ||
158 | { | ||
159 | try | ||
160 | { | ||
161 | f = (float)d; | ||
162 | result = String.Empty; | ||
163 | } | ||
164 | catch(InvalidCastException) | ||
165 | { | ||
166 | result = String.Format("{0} is invalid", s); | ||
167 | f = -1.0f; | ||
168 | } | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | f = -1.0f; | ||
173 | result = String.Format("{0} is invalid", s); | ||
174 | } | ||
175 | return result; | ||
176 | } | ||
177 | |||
178 | protected string parseInt(String s, out int i) | ||
179 | { | ||
180 | string result; | ||
181 | if (Int32.TryParse(s, out i)) | ||
182 | { | ||
183 | result = String.Empty; | ||
184 | } | ||
185 | else | ||
186 | { | ||
187 | result = String.Format("{0} is invalid", s); | ||
188 | } | ||
189 | return result; | ||
190 | } | ||
191 | |||
192 | protected void applyModification(ITerrainChannel map, TerrainModifierData data) | ||
193 | { | ||
194 | bool[,] mask; | ||
195 | int xMax; | ||
196 | int yMax; | ||
197 | int xMid; | ||
198 | int yMid; | ||
199 | if (data.shape == "ellipse") | ||
200 | { | ||
201 | mask = this.ellipticalMask(data.dx, data.dy); | ||
202 | xMax = mask.GetLength(0); | ||
203 | yMax = mask.GetLength(1); | ||
204 | xMid = xMax / 2 + xMax % 2; | ||
205 | yMid = yMax / 2 + yMax % 2; | ||
206 | } | ||
207 | else | ||
208 | { | ||
209 | mask = this.rectangularMask(data.dx, data.dy); | ||
210 | xMax = mask.GetLength(0); | ||
211 | yMax = mask.GetLength(1); | ||
212 | xMid = 0; | ||
213 | yMid = 0; | ||
214 | } | ||
215 | // m_log.DebugFormat("Apply {0} mask {1}x{2} @ {3},{4}", data.shape, xMax, yMax, xMid, yMid); | ||
216 | double[,] buffer = map.GetDoubles(); | ||
217 | int yDim = yMax; | ||
218 | while(--yDim >= 0) | ||
219 | { | ||
220 | int yPos = data.y0 + yDim - yMid; | ||
221 | if ((yPos >= 0) && (yPos < map.Height)) | ||
222 | { | ||
223 | int xDim = xMax; | ||
224 | while(--xDim >= 0) | ||
225 | { | ||
226 | int xPos = data.x0 + xDim - xMid; | ||
227 | if ((xPos >= 0) && (xPos < map.Width) && (mask[xDim, yDim])) | ||
228 | { | ||
229 | double endElevation = this.operate(buffer, data, xPos, yPos); | ||
230 | map[xPos, yPos] = endElevation; | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | protected double computeBevel(TerrainModifierData data, int x, int y) | ||
238 | { | ||
239 | int deltaX; | ||
240 | int deltaY; | ||
241 | int xMax; | ||
242 | int yMax; | ||
243 | double factor; | ||
244 | if (data.bevel == "taper") | ||
245 | { | ||
246 | if (data.shape == "ellipse") | ||
247 | { | ||
248 | deltaX = x - data.x0; | ||
249 | deltaY = y - data.y0; | ||
250 | xMax = data.dx; | ||
251 | yMax = data.dy; | ||
252 | factor = (double)((deltaX * deltaX) + (deltaY * deltaY)); | ||
253 | factor /= ((xMax * xMax) + (yMax * yMax)); | ||
254 | } | ||
255 | else | ||
256 | { | ||
257 | // pyramid | ||
258 | xMax = data.dx / 2 + data.dx % 2; | ||
259 | yMax = data.dy / 2 + data.dy % 2; | ||
260 | deltaX = Math.Abs(data.x0 + xMax - x); | ||
261 | deltaY = Math.Abs(data.y0 + yMax - y); | ||
262 | factor = Math.Max(((double)(deltaY) / yMax), ((double)(deltaX) / xMax)); | ||
263 | } | ||
264 | } | ||
265 | else | ||
266 | { | ||
267 | factor = 0.0; | ||
268 | } | ||
269 | return factor; | ||
270 | } | ||
271 | |||
272 | private bool[,] rectangularMask(int xSize, int ySize) | ||
273 | { | ||
274 | bool[,] mask = new bool[xSize, ySize]; | ||
275 | int yPos = ySize; | ||
276 | while(--yPos >= 0) | ||
277 | { | ||
278 | int xPos = xSize; | ||
279 | while(--xPos >= 0) | ||
280 | { | ||
281 | mask[xPos, yPos] = true; | ||
282 | } | ||
283 | } | ||
284 | return mask; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * Fast ellipse-based derivative of Bresenham algorithm. | ||
289 | * https://web.archive.org/web/20120225095359/http://homepage.smc.edu/kennedy_john/belipse.pdf | ||
290 | */ | ||
291 | private bool[,] ellipticalMask(int xRadius, int yRadius) | ||
292 | { | ||
293 | long twoASquared = 2L * xRadius * xRadius; | ||
294 | long twoBSquared = 2L * yRadius * yRadius; | ||
295 | |||
296 | bool[,] mask = new bool[2 * xRadius + 1, 2 * yRadius + 1]; | ||
297 | |||
298 | long ellipseError = 0L; | ||
299 | long stoppingX = twoBSquared * xRadius; | ||
300 | long stoppingY = 0L; | ||
301 | long xChange = yRadius * yRadius * (1L - 2L * xRadius); | ||
302 | long yChange = xRadius * xRadius; | ||
303 | |||
304 | int xPos = xRadius; | ||
305 | int yPos = 0; | ||
306 | |||
307 | // first set of points | ||
308 | while(stoppingX >= stoppingY) | ||
309 | { | ||
310 | int yUpper = yRadius + yPos; | ||
311 | int yLower = yRadius - yPos; | ||
312 | // fill in the mask | ||
313 | int xNow = xPos; | ||
314 | while(xNow >= 0) | ||
315 | { | ||
316 | mask[xRadius + xNow, yUpper] = true; | ||
317 | mask[xRadius - xNow, yUpper] = true; | ||
318 | mask[xRadius + xNow, yLower] = true; | ||
319 | mask[xRadius - xNow, yLower] = true; | ||
320 | --xNow; | ||
321 | } | ||
322 | yPos++; | ||
323 | stoppingY += twoASquared; | ||
324 | ellipseError += yChange; | ||
325 | yChange += twoASquared; | ||
326 | if ((2L * ellipseError + xChange) > 0L) | ||
327 | { | ||
328 | xPos--; | ||
329 | stoppingX -= twoBSquared; | ||
330 | ellipseError += xChange; | ||
331 | xChange += twoBSquared; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | // second set of points | ||
336 | xPos = 0; | ||
337 | yPos = yRadius; | ||
338 | xChange = yRadius * yRadius; | ||
339 | yChange = xRadius * xRadius * (1L - 2L * yRadius); | ||
340 | |||
341 | ellipseError = 0L; | ||
342 | stoppingX = 0L; | ||
343 | stoppingY = twoASquared * yRadius; | ||
344 | |||
345 | while(stoppingX <= stoppingY) | ||
346 | { | ||
347 | int xUpper = xRadius + xPos; | ||
348 | int xLower = xRadius - xPos; | ||
349 | // fill in the mask | ||
350 | int yNow = yPos; | ||
351 | while(yNow >= 0) | ||
352 | { | ||
353 | mask[xUpper, yRadius + yNow] = true; | ||
354 | mask[xUpper, yRadius - yNow] = true; | ||
355 | mask[xLower, yRadius + yNow] = true; | ||
356 | mask[xLower, yRadius - yNow] = true; | ||
357 | --yNow; | ||
358 | } | ||
359 | xPos++; | ||
360 | stoppingX += twoBSquared; | ||
361 | ellipseError += xChange; | ||
362 | xChange += twoBSquared; | ||
363 | if ((2L * ellipseError + yChange) > 0L) | ||
364 | { | ||
365 | yPos--; | ||
366 | stoppingY -= twoASquared; | ||
367 | ellipseError += yChange; | ||
368 | yChange += twoASquared; | ||
369 | } | ||
370 | } | ||
371 | return mask; | ||
372 | } | ||
373 | |||
374 | |||
375 | } | ||
376 | |||
377 | } | ||
378 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs new file mode 100644 index 0000000..4e0f8d7 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModifierData.cs | |||
@@ -0,0 +1,17 @@ | |||
1 | using System; | ||
2 | |||
3 | namespace OpenSim.Region.CoreModules.World.Terrain | ||
4 | { | ||
5 | public struct TerrainModifierData | ||
6 | { | ||
7 | public float elevation; | ||
8 | public string shape; | ||
9 | public int x0; | ||
10 | public int y0; | ||
11 | public int dx; | ||
12 | public int dy; | ||
13 | public string bevel; | ||
14 | public float bevelevation; | ||
15 | } | ||
16 | } | ||
17 | |||
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 3bb8040..cec17e2 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs | |||
@@ -24,7 +24,6 @@ | |||
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 | |||
28 | using System; | 27 | using System; |
29 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
30 | using System.IO; | 29 | using System.IO; |
@@ -42,7 +41,7 @@ using OpenSim.Framework; | |||
42 | using OpenSim.Framework.Console; | 41 | using OpenSim.Framework.Console; |
43 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; | 42 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; |
44 | using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; | 43 | using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; |
45 | using OpenSim.Region.CoreModules.World.Terrain.Features; | 44 | using OpenSim.Region.CoreModules.World.Terrain.Modifiers; |
46 | using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes; | 45 | using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes; |
47 | using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; | 46 | using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; |
48 | using OpenSim.Region.Framework.Interfaces; | 47 | using OpenSim.Region.Framework.Interfaces; |
@@ -75,14 +74,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
75 | 74 | ||
76 | #endregion | 75 | #endregion |
77 | 76 | ||
78 | /// <summary> | ||
79 | /// Terrain Features | ||
80 | /// </summary> | ||
81 | public enum TerrainFeatures: byte | ||
82 | { | ||
83 | Rectangle = 1, | ||
84 | } | ||
85 | |||
86 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 77 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
87 | 78 | ||
88 | #pragma warning disable 414 | 79 | #pragma warning disable 414 |
@@ -90,26 +81,19 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
90 | #pragma warning restore 414 | 81 | #pragma warning restore 414 |
91 | 82 | ||
92 | private readonly Commander m_commander = new Commander("terrain"); | 83 | private readonly Commander m_commander = new Commander("terrain"); |
93 | |||
94 | private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects = | 84 | private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects = |
95 | new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>(); | 85 | new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>(); |
96 | |||
97 | private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>(); | 86 | private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>(); |
98 | |||
99 | private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects = | 87 | private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects = |
100 | new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>(); | 88 | new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>(); |
101 | |||
102 | private Dictionary<string, ITerrainEffect> m_plugineffects; | 89 | private Dictionary<string, ITerrainEffect> m_plugineffects; |
103 | 90 | private Dictionary<string, ITerrainModifier> m_modifyOperations = | |
104 | private Dictionary<string, ITerrainFeature> m_featureEffects = | 91 | new Dictionary<string, ITerrainModifier>(); |
105 | new Dictionary<string, ITerrainFeature>(); | ||
106 | |||
107 | private ITerrainChannel m_channel; | 92 | private ITerrainChannel m_channel; |
108 | private ITerrainChannel m_revert; | 93 | private ITerrainChannel m_revert; |
109 | private Scene m_scene; | 94 | private Scene m_scene; |
110 | private volatile bool m_tainted; | 95 | private volatile bool m_tainted; |
111 | private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5); | 96 | private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5); |
112 | |||
113 | private String m_InitialTerrain = "pinhead-island"; | 97 | private String m_InitialTerrain = "pinhead-island"; |
114 | 98 | ||
115 | // If true, send terrain patch updates to clients based on their view distance | 99 | // If true, send terrain patch updates to clients based on their view distance |
@@ -136,14 +120,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
136 | { | 120 | { |
137 | return (updateCount > 0); | 121 | return (updateCount > 0); |
138 | } | 122 | } |
123 | |||
139 | public void SetByXY(int x, int y, bool state) | 124 | public void SetByXY(int x, int y, bool state) |
140 | { | 125 | { |
141 | this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state); | 126 | this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state); |
142 | } | 127 | } |
128 | |||
143 | public bool GetByPatch(int patchX, int patchY) | 129 | public bool GetByPatch(int patchX, int patchY) |
144 | { | 130 | { |
145 | return updated[patchX, patchY]; | 131 | return updated[patchX, patchY]; |
146 | } | 132 | } |
133 | |||
147 | public void SetByPatch(int patchX, int patchY, bool state) | 134 | public void SetByPatch(int patchX, int patchY, bool state) |
148 | { | 135 | { |
149 | bool prevState = updated[patchX, patchY]; | 136 | bool prevState = updated[patchX, patchY]; |
@@ -153,11 +140,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
153 | updateCount--; | 140 | updateCount--; |
154 | updated[patchX, patchY] = state; | 141 | updated[patchX, patchY] = state; |
155 | } | 142 | } |
143 | |||
156 | public void SetAll(bool state) | 144 | public void SetAll(bool state) |
157 | { | 145 | { |
158 | updateCount = 0; | 146 | updateCount = 0; |
159 | for (int xx = 0; xx < updated.GetLength(0); xx++) | 147 | for(int xx = 0; xx < updated.GetLength(0); xx++) |
160 | for (int yy = 0; yy < updated.GetLength(1); yy++) | 148 | for(int yy = 0; yy < updated.GetLength(1); yy++) |
161 | updated[xx, yy] = state; | 149 | updated[xx, yy] = state; |
162 | if (state) | 150 | if (state) |
163 | updateCount = updated.GetLength(0) * updated.GetLength(1); | 151 | updateCount = updated.GetLength(0) * updated.GetLength(1); |
@@ -174,9 +162,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
174 | terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize) | 162 | terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize) |
175 | ); | 163 | ); |
176 | } | 164 | } |
177 | for (int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize) | 165 | for(int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize) |
178 | { | 166 | { |
179 | for (int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize) | 167 | for(int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize) |
180 | { | 168 | { |
181 | // Only set tainted. The patch bit may be set if the patch was to be sent later. | 169 | // Only set tainted. The patch bit may be set if the patch was to be sent later. |
182 | if (terrData.IsTaintedAt(xx, yy, false)) | 170 | if (terrData.IsTaintedAt(xx, yy, false)) |
@@ -201,8 +189,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
201 | 189 | ||
202 | #region ICommandableModule Members | 190 | #region ICommandableModule Members |
203 | 191 | ||
204 | public ICommander CommandInterface | 192 | public ICommander CommandInterface { |
205 | { | ||
206 | get { return m_commander; } | 193 | get { return m_commander; } |
207 | } | 194 | } |
208 | 195 | ||
@@ -230,7 +217,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
230 | m_scene = scene; | 217 | m_scene = scene; |
231 | 218 | ||
232 | // Install terrain module in the simulator | 219 | // Install terrain module in the simulator |
233 | lock (m_scene) | 220 | lock(m_scene) |
234 | { | 221 | { |
235 | if (m_scene.Heightmap == null) | 222 | if (m_scene.Heightmap == null) |
236 | { | 223 | { |
@@ -262,7 +249,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
262 | string supportedFilesSeparatorForTileSave = ""; | 249 | string supportedFilesSeparatorForTileSave = ""; |
263 | 250 | ||
264 | m_supportFileExtensionsForTileSave = ""; | 251 | m_supportFileExtensionsForTileSave = ""; |
265 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 252 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
266 | { | 253 | { |
267 | m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")"; | 254 | m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")"; |
268 | supportedFilesSeparator = ", "; | 255 | supportedFilesSeparator = ", "; |
@@ -285,7 +272,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
285 | 272 | ||
286 | public void RemoveRegion(Scene scene) | 273 | public void RemoveRegion(Scene scene) |
287 | { | 274 | { |
288 | lock (m_scene) | 275 | lock(m_scene) |
289 | { | 276 | { |
290 | // remove the commands | 277 | // remove the commands |
291 | m_scene.UnregisterModuleCommander(m_commander.Name); | 278 | m_scene.UnregisterModuleCommander(m_commander.Name); |
@@ -304,13 +291,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
304 | { | 291 | { |
305 | } | 292 | } |
306 | 293 | ||
307 | public Type ReplaceableInterface | 294 | public Type ReplaceableInterface { |
308 | { | ||
309 | get { return null; } | 295 | get { return null; } |
310 | } | 296 | } |
311 | 297 | ||
312 | public string Name | 298 | public string Name { |
313 | { | ||
314 | get { return "TerrainModule"; } | 299 | get { return "TerrainModule"; } |
315 | } | 300 | } |
316 | 301 | ||
@@ -329,11 +314,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
329 | /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> | 314 | /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> |
330 | public void LoadFromFile(string filename) | 315 | public void LoadFromFile(string filename) |
331 | { | 316 | { |
332 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 317 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
333 | { | 318 | { |
334 | if (filename.EndsWith(loader.Key)) | 319 | if (filename.EndsWith(loader.Key)) |
335 | { | 320 | { |
336 | lock (m_scene) | 321 | lock(m_scene) |
337 | { | 322 | { |
338 | try | 323 | try |
339 | { | 324 | { |
@@ -349,20 +334,20 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
349 | m_channel = channel; | 334 | m_channel = channel; |
350 | UpdateRevertMap(); | 335 | UpdateRevertMap(); |
351 | } | 336 | } |
352 | catch (NotImplementedException) | 337 | catch(NotImplementedException) |
353 | { | 338 | { |
354 | m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + | 339 | m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + |
355 | " parser does not support file loading. (May be save only)"); | 340 | " parser does not support file loading. (May be save only)"); |
356 | throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value)); | 341 | throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value)); |
357 | } | 342 | } |
358 | catch (FileNotFoundException) | 343 | catch(FileNotFoundException) |
359 | { | 344 | { |
360 | m_log.Error( | 345 | m_log.Error( |
361 | "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)"); | 346 | "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)"); |
362 | throw new TerrainException( | 347 | throw new TerrainException( |
363 | String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename)); | 348 | String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename)); |
364 | } | 349 | } |
365 | catch (ArgumentException e) | 350 | catch(ArgumentException e) |
366 | { | 351 | { |
367 | m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message); | 352 | m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message); |
368 | throw new TerrainException( | 353 | throw new TerrainException( |
@@ -386,7 +371,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
386 | { | 371 | { |
387 | try | 372 | try |
388 | { | 373 | { |
389 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 374 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
390 | { | 375 | { |
391 | if (filename.EndsWith(loader.Key)) | 376 | if (filename.EndsWith(loader.Key)) |
392 | { | 377 | { |
@@ -396,7 +381,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
396 | } | 381 | } |
397 | } | 382 | } |
398 | } | 383 | } |
399 | catch (IOException ioe) | 384 | catch(IOException ioe) |
400 | { | 385 | { |
401 | m_log.Error(String.Format("[TERRAIN]: Unable to save to {0}, {1}", filename, ioe.Message)); | 386 | m_log.Error(String.Format("[TERRAIN]: Unable to save to {0}, {1}", filename, ioe.Message)); |
402 | } | 387 | } |
@@ -429,11 +414,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
429 | public void LoadFromStream(string filename, Vector3 displacement, | 414 | public void LoadFromStream(string filename, Vector3 displacement, |
430 | float radianRotation, Vector2 rotationDisplacement, Stream stream) | 415 | float radianRotation, Vector2 rotationDisplacement, Stream stream) |
431 | { | 416 | { |
432 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 417 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
433 | { | 418 | { |
434 | if (filename.EndsWith(loader.Key)) | 419 | if (filename.EndsWith(loader.Key)) |
435 | { | 420 | { |
436 | lock (m_scene) | 421 | lock(m_scene) |
437 | { | 422 | { |
438 | try | 423 | try |
439 | { | 424 | { |
@@ -441,7 +426,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
441 | m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement); | 426 | m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement); |
442 | UpdateRevertMap(); | 427 | UpdateRevertMap(); |
443 | } | 428 | } |
444 | catch (NotImplementedException) | 429 | catch(NotImplementedException) |
445 | { | 430 | { |
446 | m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + | 431 | m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + |
447 | " parser does not support file loading. (May be save only)"); | 432 | " parser does not support file loading. (May be save only)"); |
@@ -501,7 +486,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
501 | { | 486 | { |
502 | try | 487 | try |
503 | { | 488 | { |
504 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 489 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
505 | { | 490 | { |
506 | if (filename.EndsWith(loader.Key)) | 491 | if (filename.EndsWith(loader.Key)) |
507 | { | 492 | { |
@@ -510,7 +495,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
510 | } | 495 | } |
511 | } | 496 | } |
512 | } | 497 | } |
513 | catch (NotImplementedException) | 498 | catch(NotImplementedException) |
514 | { | 499 | { |
515 | m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented."); | 500 | m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented."); |
516 | throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented")); | 501 | throw new TerrainException(String.Format("Unable to save heightmap: saving of this file format not implemented")); |
@@ -519,12 +504,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
519 | 504 | ||
520 | // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients. | 505 | // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients. |
521 | // ITerrainModule.TaintTerrain() | 506 | // ITerrainModule.TaintTerrain() |
522 | public void TaintTerrain () | 507 | public void TaintTerrain() |
523 | { | 508 | { |
524 | lock (m_perClientPatchUpdates) | 509 | lock(m_perClientPatchUpdates) |
525 | { | 510 | { |
526 | // Set the flags for all clients so the tainted patches will be sent out | 511 | // Set the flags for all clients so the tainted patches will be sent out |
527 | foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) | 512 | foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) |
528 | { | 513 | { |
529 | pups.SetAll(m_scene.Heightmap.GetTerrainData()); | 514 | pups.SetAll(m_scene.Heightmap.GetTerrainData()); |
530 | } | 515 | } |
@@ -539,7 +524,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
539 | ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); | 524 | ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); |
540 | if (presence != null) | 525 | if (presence != null) |
541 | { | 526 | { |
542 | lock (m_perClientPatchUpdates) | 527 | lock(m_perClientPatchUpdates) |
543 | { | 528 | { |
544 | PatchUpdates pups; | 529 | PatchUpdates pups; |
545 | if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups)) | 530 | if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups)) |
@@ -566,13 +551,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
566 | m_plugineffects = new Dictionary<string, ITerrainEffect>(); | 551 | m_plugineffects = new Dictionary<string, ITerrainEffect>(); |
567 | LoadPlugins(Assembly.GetCallingAssembly()); | 552 | LoadPlugins(Assembly.GetCallingAssembly()); |
568 | string plugineffectsPath = "Terrain"; | 553 | string plugineffectsPath = "Terrain"; |
569 | 554 | ||
570 | // Load the files in the Terrain/ dir | 555 | // Load the files in the Terrain/ dir |
571 | if (!Directory.Exists(plugineffectsPath)) | 556 | if (!Directory.Exists(plugineffectsPath)) |
572 | return; | 557 | return; |
573 | 558 | ||
574 | string[] files = Directory.GetFiles(plugineffectsPath); | 559 | string[] files = Directory.GetFiles(plugineffectsPath); |
575 | foreach (string file in files) | 560 | foreach(string file in files) |
576 | { | 561 | { |
577 | m_log.Info("Loading effects in " + file); | 562 | m_log.Info("Loading effects in " + file); |
578 | try | 563 | try |
@@ -580,7 +565,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
580 | Assembly library = Assembly.LoadFrom(file); | 565 | Assembly library = Assembly.LoadFrom(file); |
581 | LoadPlugins(library); | 566 | LoadPlugins(library); |
582 | } | 567 | } |
583 | catch (BadImageFormatException) | 568 | catch(BadImageFormatException) |
584 | { | 569 | { |
585 | } | 570 | } |
586 | } | 571 | } |
@@ -588,7 +573,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
588 | 573 | ||
589 | private void LoadPlugins(Assembly library) | 574 | private void LoadPlugins(Assembly library) |
590 | { | 575 | { |
591 | foreach (Type pluginType in library.GetTypes()) | 576 | foreach(Type pluginType in library.GetTypes()) |
592 | { | 577 | { |
593 | try | 578 | try |
594 | { | 579 | { |
@@ -610,7 +595,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
610 | m_log.Info("L ... " + typeName); | 595 | m_log.Info("L ... " + typeName); |
611 | } | 596 | } |
612 | } | 597 | } |
613 | catch (AmbiguousMatchException) | 598 | catch(AmbiguousMatchException) |
614 | { | 599 | { |
615 | } | 600 | } |
616 | } | 601 | } |
@@ -618,7 +603,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
618 | 603 | ||
619 | public void InstallPlugin(string pluginName, ITerrainEffect effect) | 604 | public void InstallPlugin(string pluginName, ITerrainEffect effect) |
620 | { | 605 | { |
621 | lock (m_plugineffects) | 606 | lock(m_plugineffects) |
622 | { | 607 | { |
623 | if (!m_plugineffects.ContainsKey(pluginName)) | 608 | if (!m_plugineffects.ContainsKey(pluginName)) |
624 | { | 609 | { |
@@ -661,8 +646,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
661 | m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea(); | 646 | m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea(); |
662 | m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert); | 647 | m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert); |
663 | 648 | ||
664 | // Terrain Feature effects | 649 | // Terrain Modifier operations |
665 | m_featureEffects["rectangle"] = new RectangleFeature(this); | 650 | m_modifyOperations["min"] = new MinModifier(this); |
651 | m_modifyOperations["max"] = new MaxModifier(this); | ||
652 | m_modifyOperations["raise"] = new RaiseModifier(this); | ||
653 | m_modifyOperations["lower"] = new LowerModifier(this); | ||
654 | m_modifyOperations["fill"] = new FillModifier(this); | ||
655 | m_modifyOperations["smooth"] = new SmoothModifier(this); | ||
656 | m_modifyOperations["noise"] = new NoiseModifier(this); | ||
666 | 657 | ||
667 | // Filesystem load/save loaders | 658 | // Filesystem load/save loaders |
668 | m_loaders[".r32"] = new RAW32(); | 659 | m_loaders[".r32"] = new RAW32(); |
@@ -707,22 +698,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
707 | /// <param name="fileStartY">Where to begin our slice</param> | 698 | /// <param name="fileStartY">Where to begin our slice</param> |
708 | public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) | 699 | public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) |
709 | { | 700 | { |
710 | int offsetX = (int) m_scene.RegionInfo.RegionLocX - fileStartX; | 701 | int offsetX = (int)m_scene.RegionInfo.RegionLocX - fileStartX; |
711 | int offsetY = (int) m_scene.RegionInfo.RegionLocY - fileStartY; | 702 | int offsetY = (int)m_scene.RegionInfo.RegionLocY - fileStartY; |
712 | 703 | ||
713 | if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) | 704 | if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) |
714 | { | 705 | { |
715 | // this region is included in the tile request | 706 | // this region is included in the tile request |
716 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 707 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
717 | { | 708 | { |
718 | if (filename.EndsWith(loader.Key)) | 709 | if (filename.EndsWith(loader.Key)) |
719 | { | 710 | { |
720 | lock (m_scene) | 711 | lock(m_scene) |
721 | { | 712 | { |
722 | ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, | 713 | ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, |
723 | fileWidth, fileHeight, | 714 | fileWidth, fileHeight, |
724 | (int) m_scene.RegionInfo.RegionSizeX, | 715 | (int)m_scene.RegionInfo.RegionSizeX, |
725 | (int) m_scene.RegionInfo.RegionSizeY); | 716 | (int)m_scene.RegionInfo.RegionSizeY); |
726 | m_scene.Heightmap = channel; | 717 | m_scene.Heightmap = channel; |
727 | m_channel = channel; | 718 | m_channel = channel; |
728 | UpdateRevertMap(); | 719 | UpdateRevertMap(); |
@@ -761,11 +752,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
761 | } | 752 | } |
762 | 753 | ||
763 | // this region is included in the tile request | 754 | // this region is included in the tile request |
764 | foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) | 755 | foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders) |
765 | { | 756 | { |
766 | if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave()) | 757 | if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave()) |
767 | { | 758 | { |
768 | lock (m_scene) | 759 | lock(m_scene) |
769 | { | 760 | { |
770 | loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, | 761 | loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, |
771 | fileWidth, fileHeight, | 762 | fileWidth, fileHeight, |
@@ -777,7 +768,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
777 | fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1, | 768 | fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1, |
778 | m_scene.RegionInfo.RegionName, filename); | 769 | m_scene.RegionInfo.RegionName, filename); |
779 | } | 770 | } |
780 | 771 | ||
781 | return; | 772 | return; |
782 | } | 773 | } |
783 | } | 774 | } |
@@ -799,9 +790,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
799 | TerrainData terrData = m_channel.GetTerrainData(); | 790 | TerrainData terrData = m_channel.GetTerrainData(); |
800 | 791 | ||
801 | bool shouldTaint = false; | 792 | bool shouldTaint = false; |
802 | for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) | 793 | for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) |
803 | { | 794 | { |
804 | for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) | 795 | for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) |
805 | { | 796 | { |
806 | if (terrData.IsTaintedAt(x, y)) | 797 | if (terrData.IsTaintedAt(x, y)) |
807 | { | 798 | { |
@@ -856,7 +847,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
856 | 847 | ||
857 | string[] tmpArgs = new string[args.Length - 2]; | 848 | string[] tmpArgs = new string[args.Length - 2]; |
858 | int i; | 849 | int i; |
859 | for (i = 2; i < args.Length; i++) | 850 | for(i = 2; i < args.Length; i++) |
860 | tmpArgs[i - 2] = args[i]; | 851 | tmpArgs[i - 2] = args[i]; |
861 | 852 | ||
862 | m_commander.ProcessConsoleCommand(args[1], tmpArgs); | 853 | m_commander.ProcessConsoleCommand(args[1], tmpArgs); |
@@ -874,7 +865,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
874 | client.OnLandUndo += client_OnLandUndo; | 865 | client.OnLandUndo += client_OnLandUndo; |
875 | client.OnUnackedTerrain += client_OnUnackedTerrain; | 866 | client.OnUnackedTerrain += client_OnUnackedTerrain; |
876 | } | 867 | } |
877 | 868 | ||
878 | /// <summary> | 869 | /// <summary> |
879 | /// Installs terrain brush hook to IClientAPI | 870 | /// Installs terrain brush hook to IClientAPI |
880 | /// </summary> | 871 | /// </summary> |
@@ -890,10 +881,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
890 | presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain; | 881 | presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain; |
891 | } | 882 | } |
892 | 883 | ||
893 | lock (m_perClientPatchUpdates) | 884 | lock(m_perClientPatchUpdates) |
894 | m_perClientPatchUpdates.Remove(client); | 885 | m_perClientPatchUpdates.Remove(client); |
895 | } | 886 | } |
896 | 887 | ||
897 | /// <summary> | 888 | /// <summary> |
898 | /// Scan over changes in the terrain and limit height changes. This enforces the | 889 | /// Scan over changes in the terrain and limit height changes. This enforces the |
899 | /// non-estate owner limits on rate of terrain editting. | 890 | /// non-estate owner limits on rate of terrain editting. |
@@ -904,12 +895,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
904 | TerrainData terrData = m_channel.GetTerrainData(); | 895 | TerrainData terrData = m_channel.GetTerrainData(); |
905 | 896 | ||
906 | bool wasLimited = false; | 897 | bool wasLimited = false; |
907 | for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) | 898 | for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize) |
908 | { | 899 | { |
909 | for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) | 900 | for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize) |
910 | { | 901 | { |
911 | if (terrData.IsTaintedAt(x, y, false /* clearOnTest */)) | 902 | if (terrData.IsTaintedAt(x, y, false /* clearOnTest */)) |
912 | { | 903 | { |
913 | // If we should respect the estate settings then | 904 | // If we should respect the estate settings then |
914 | // fixup and height deltas that don't respect them. | 905 | // fixup and height deltas that don't respect them. |
915 | // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values. | 906 | // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values. |
@@ -933,9 +924,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
933 | 924 | ||
934 | // loop through the height map for this patch and compare it against | 925 | // loop through the height map for this patch and compare it against |
935 | // the revert map | 926 | // the revert map |
936 | for (int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) | 927 | for(int x = xStart; x < xStart + Constants.TerrainPatchSize; x++) |
937 | { | 928 | { |
938 | for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) | 929 | for(int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) |
939 | { | 930 | { |
940 | float requestedHeight = terrData[x, y]; | 931 | float requestedHeight = terrData[x, y]; |
941 | float bakedHeight = (float)m_revert[x, y]; | 932 | float bakedHeight = (float)m_revert[x, y]; |
@@ -959,7 +950,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
959 | 950 | ||
960 | private void client_OnLandUndo(IClientAPI client) | 951 | private void client_OnLandUndo(IClientAPI client) |
961 | { | 952 | { |
962 | lock (m_undo) | 953 | lock(m_undo) |
963 | { | 954 | { |
964 | if (m_undo.Count > 0) | 955 | if (m_undo.Count > 0) |
965 | { | 956 | { |
@@ -981,19 +972,19 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
981 | if (m_sendTerrainUpdatesByViewDistance) | 972 | if (m_sendTerrainUpdatesByViewDistance) |
982 | { | 973 | { |
983 | // Add that this patch needs to be sent to the accounting for each client. | 974 | // Add that this patch needs to be sent to the accounting for each client. |
984 | lock (m_perClientPatchUpdates) | 975 | lock(m_perClientPatchUpdates) |
985 | { | 976 | { |
986 | m_scene.ForEachScenePresence(presence => | 977 | m_scene.ForEachScenePresence(presence => |
978 | { | ||
979 | PatchUpdates thisClientUpdates; | ||
980 | if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) | ||
987 | { | 981 | { |
988 | PatchUpdates thisClientUpdates; | 982 | // There is a ScenePresence without a send patch map. Create one. |
989 | if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) | 983 | thisClientUpdates = new PatchUpdates(terrData, presence); |
990 | { | 984 | m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); |
991 | // There is a ScenePresence without a send patch map. Create one. | ||
992 | thisClientUpdates = new PatchUpdates(terrData, presence); | ||
993 | m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates); | ||
994 | } | ||
995 | thisClientUpdates.SetByXY(x, y, true); | ||
996 | } | 985 | } |
986 | thisClientUpdates.SetByXY(x, y, true); | ||
987 | } | ||
997 | ); | 988 | ); |
998 | } | 989 | } |
999 | } | 990 | } |
@@ -1005,11 +996,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1005 | float[] heightMap = new float[10]; | 996 | float[] heightMap = new float[10]; |
1006 | m_scene.ForEachClient( | 997 | m_scene.ForEachClient( |
1007 | delegate(IClientAPI controller) | 998 | delegate(IClientAPI controller) |
1008 | { | 999 | { |
1009 | controller.SendLayerData(x / Constants.TerrainPatchSize, | 1000 | controller.SendLayerData(x / Constants.TerrainPatchSize, |
1010 | y / Constants.TerrainPatchSize, | 1001 | y / Constants.TerrainPatchSize, |
1011 | heightMap); | 1002 | heightMap); |
1012 | } | 1003 | } |
1013 | ); | 1004 | ); |
1014 | } | 1005 | } |
1015 | } | 1006 | } |
@@ -1019,12 +1010,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1019 | public int PatchX; | 1010 | public int PatchX; |
1020 | public int PatchY; | 1011 | public int PatchY; |
1021 | public float Dist; | 1012 | public float Dist; |
1013 | |||
1022 | public PatchesToSend(int pX, int pY, float pDist) | 1014 | public PatchesToSend(int pX, int pY, float pDist) |
1023 | { | 1015 | { |
1024 | PatchX = pX; | 1016 | PatchX = pX; |
1025 | PatchY = pY; | 1017 | PatchY = pY; |
1026 | Dist = pDist; | 1018 | Dist = pDist; |
1027 | } | 1019 | } |
1020 | |||
1028 | public int CompareTo(PatchesToSend other) | 1021 | public int CompareTo(PatchesToSend other) |
1029 | { | 1022 | { |
1030 | return Dist.CompareTo(other.Dist); | 1023 | return Dist.CompareTo(other.Dist); |
@@ -1036,9 +1029,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1036 | // Loop through all the per-client info and send any patches necessary. | 1029 | // Loop through all the per-client info and send any patches necessary. |
1037 | private void CheckSendingPatchesToClients() | 1030 | private void CheckSendingPatchesToClients() |
1038 | { | 1031 | { |
1039 | lock (m_perClientPatchUpdates) | 1032 | lock(m_perClientPatchUpdates) |
1040 | { | 1033 | { |
1041 | foreach (PatchUpdates pups in m_perClientPatchUpdates.Values) | 1034 | foreach(PatchUpdates pups in m_perClientPatchUpdates.Values) |
1042 | { | 1035 | { |
1043 | if (pups.HasUpdates()) | 1036 | if (pups.HasUpdates()) |
1044 | { | 1037 | { |
@@ -1062,7 +1055,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1062 | int[] yPieces = new int[toSend.Count]; | 1055 | int[] yPieces = new int[toSend.Count]; |
1063 | float[] patchPieces = new float[toSend.Count * 2]; | 1056 | float[] patchPieces = new float[toSend.Count * 2]; |
1064 | int pieceIndex = 0; | 1057 | int pieceIndex = 0; |
1065 | foreach (PatchesToSend pts in toSend) | 1058 | foreach(PatchesToSend pts in toSend) |
1066 | { | 1059 | { |
1067 | patchPieces[pieceIndex++] = pts.PatchX; | 1060 | patchPieces[pieceIndex++] = pts.PatchX; |
1068 | patchPieces[pieceIndex++] = pts.PatchY; | 1061 | patchPieces[pieceIndex++] = pts.PatchY; |
@@ -1083,25 +1076,25 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1083 | return ret; | 1076 | return ret; |
1084 | 1077 | ||
1085 | // Compute the area of patches within our draw distance | 1078 | // Compute the area of patches within our draw distance |
1086 | int startX = (((int) (presence.AbsolutePosition.X - presence.DrawDistance))/Constants.TerrainPatchSize) - 2; | 1079 | int startX = (((int)(presence.AbsolutePosition.X - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; |
1087 | startX = Math.Max(startX, 0); | 1080 | startX = Math.Max(startX, 0); |
1088 | startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize); | 1081 | startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); |
1089 | int startY = (((int) (presence.AbsolutePosition.Y - presence.DrawDistance))/Constants.TerrainPatchSize) - 2; | 1082 | int startY = (((int)(presence.AbsolutePosition.Y - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2; |
1090 | startY = Math.Max(startY, 0); | 1083 | startY = Math.Max(startY, 0); |
1091 | startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize); | 1084 | startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); |
1092 | int endX = (((int) (presence.AbsolutePosition.X + presence.DrawDistance))/Constants.TerrainPatchSize) + 2; | 1085 | int endX = (((int)(presence.AbsolutePosition.X + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; |
1093 | endX = Math.Max(endX, 0); | 1086 | endX = Math.Max(endX, 0); |
1094 | endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize); | 1087 | endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize); |
1095 | int endY = (((int) (presence.AbsolutePosition.Y + presence.DrawDistance))/Constants.TerrainPatchSize) + 2; | 1088 | int endY = (((int)(presence.AbsolutePosition.Y + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2; |
1096 | endY = Math.Max(endY, 0); | 1089 | endY = Math.Max(endY, 0); |
1097 | endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize); | 1090 | endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize); |
1098 | // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, start=<{4},{5}>, end=<{6},{7}>", | 1091 | // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, start=<{4},{5}>, end=<{6},{7}>", |
1099 | // LogHeader, m_scene.RegionInfo.RegionName, | 1092 | // LogHeader, m_scene.RegionInfo.RegionName, |
1100 | // presence.DrawDistance, presence.AbsolutePosition, | 1093 | // presence.DrawDistance, presence.AbsolutePosition, |
1101 | // startX, startY, endX, endY); | 1094 | // startX, startY, endX, endY); |
1102 | for (int x = startX; x < endX; x++) | 1095 | for(int x = startX; x < endX; x++) |
1103 | { | 1096 | { |
1104 | for (int y = startY; y < endY; y++) | 1097 | for(int y = startY; y < endY; y++) |
1105 | { | 1098 | { |
1106 | //Need to make sure we don't send the same ones over and over | 1099 | //Need to make sure we don't send the same ones over and over |
1107 | Vector3 presencePos = presence.AbsolutePosition; | 1100 | Vector3 presencePos = presence.AbsolutePosition; |
@@ -1133,28 +1126,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1133 | bool allowed = false; | 1126 | bool allowed = false; |
1134 | if (north == south && east == west) | 1127 | if (north == south && east == west) |
1135 | { | 1128 | { |
1136 | if (m_painteffects.ContainsKey((StandardTerrainEffects) action)) | 1129 | if (m_painteffects.ContainsKey((StandardTerrainEffects)action)) |
1137 | { | 1130 | { |
1138 | bool[,] allowMask = new bool[m_channel.Width,m_channel.Height]; | 1131 | bool[,] allowMask = new bool[m_channel.Width, m_channel.Height]; |
1139 | allowMask.Initialize(); | 1132 | allowMask.Initialize(); |
1140 | int n = size + 1; | 1133 | int n = size + 1; |
1141 | if (n > 2) | 1134 | if (n > 2) |
1142 | n = 4; | 1135 | n = 4; |
1143 | 1136 | ||
1144 | int zx = (int) (west + 0.5); | 1137 | int zx = (int)(west + 0.5); |
1145 | int zy = (int) (north + 0.5); | 1138 | int zy = (int)(north + 0.5); |
1146 | 1139 | ||
1147 | int dx; | 1140 | int dx; |
1148 | for (dx=-n; dx<=n; dx++) | 1141 | for(dx=-n; dx<=n; dx++) |
1149 | { | 1142 | { |
1150 | int dy; | 1143 | int dy; |
1151 | for (dy=-n; dy<=n; dy++) | 1144 | for(dy=-n; dy<=n; dy++) |
1152 | { | 1145 | { |
1153 | int x = zx + dx; | 1146 | int x = zx + dx; |
1154 | int y = zy + dy; | 1147 | int y = zy + dy; |
1155 | if (x>=0 && y>=0 && x<m_channel.Width && y<m_channel.Height) | 1148 | if (x >= 0 && y >= 0 && x < m_channel.Width && y < m_channel.Height) |
1156 | { | 1149 | { |
1157 | if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) | 1150 | if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) |
1158 | { | 1151 | { |
1159 | allowMask[x, y] = true; | 1152 | allowMask[x, y] = true; |
1160 | allowed = true; | 1153 | allowed = true; |
@@ -1165,7 +1158,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1165 | if (allowed) | 1158 | if (allowed) |
1166 | { | 1159 | { |
1167 | StoreUndoState(); | 1160 | StoreUndoState(); |
1168 | m_painteffects[(StandardTerrainEffects) action].PaintEffect( | 1161 | m_painteffects[(StandardTerrainEffects)action].PaintEffect( |
1169 | m_channel, allowMask, west, south, height, size, seconds); | 1162 | m_channel, allowMask, west, south, height, size, seconds); |
1170 | 1163 | ||
1171 | //revert changes outside estate limits | 1164 | //revert changes outside estate limits |
@@ -1180,22 +1173,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1180 | } | 1173 | } |
1181 | else | 1174 | else |
1182 | { | 1175 | { |
1183 | if (m_floodeffects.ContainsKey((StandardTerrainEffects) action)) | 1176 | if (m_floodeffects.ContainsKey((StandardTerrainEffects)action)) |
1184 | { | 1177 | { |
1185 | bool[,] fillArea = new bool[m_channel.Width,m_channel.Height]; | 1178 | bool[,] fillArea = new bool[m_channel.Width, m_channel.Height]; |
1186 | fillArea.Initialize(); | 1179 | fillArea.Initialize(); |
1187 | 1180 | ||
1188 | int x; | 1181 | int x; |
1189 | for (x = 0; x < m_channel.Width; x++) | 1182 | for(x = 0; x < m_channel.Width; x++) |
1190 | { | 1183 | { |
1191 | int y; | 1184 | int y; |
1192 | for (y = 0; y < m_channel.Height; y++) | 1185 | for(y = 0; y < m_channel.Height; y++) |
1193 | { | 1186 | { |
1194 | if (x < east && x > west) | 1187 | if (x < east && x > west) |
1195 | { | 1188 | { |
1196 | if (y < north && y > south) | 1189 | if (y < north && y > south) |
1197 | { | 1190 | { |
1198 | if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0))) | 1191 | if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0))) |
1199 | { | 1192 | { |
1200 | fillArea[x, y] = true; | 1193 | fillArea[x, y] = true; |
1201 | allowed = true; | 1194 | allowed = true; |
@@ -1208,7 +1201,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1208 | if (allowed) | 1201 | if (allowed) |
1209 | { | 1202 | { |
1210 | StoreUndoState(); | 1203 | StoreUndoState(); |
1211 | m_floodeffects[(StandardTerrainEffects) action].FloodEffect(m_channel, fillArea, size); | 1204 | m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size); |
1212 | 1205 | ||
1213 | //revert changes outside estate limits | 1206 | //revert changes outside estate limits |
1214 | if (!god) | 1207 | if (!god) |
@@ -1232,7 +1225,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1232 | InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter | 1225 | InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter |
1233 | } | 1226 | } |
1234 | } | 1227 | } |
1235 | 1228 | ||
1236 | protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY) | 1229 | protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY) |
1237 | { | 1230 | { |
1238 | //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY); | 1231 | //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY); |
@@ -1243,7 +1236,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1243 | 1236 | ||
1244 | private void StoreUndoState() | 1237 | private void StoreUndoState() |
1245 | { | 1238 | { |
1246 | lock (m_undo) | 1239 | lock(m_undo) |
1247 | { | 1240 | { |
1248 | if (m_undo.Count > 0) | 1241 | if (m_undo.Count > 0) |
1249 | { | 1242 | { |
@@ -1264,21 +1257,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1264 | 1257 | ||
1265 | private void InterfaceLoadFile(Object[] args) | 1258 | private void InterfaceLoadFile(Object[] args) |
1266 | { | 1259 | { |
1267 | LoadFromFile((string) args[0]); | 1260 | LoadFromFile((string)args[0]); |
1268 | } | 1261 | } |
1269 | 1262 | ||
1270 | private void InterfaceLoadTileFile(Object[] args) | 1263 | private void InterfaceLoadTileFile(Object[] args) |
1271 | { | 1264 | { |
1272 | LoadFromFile((string) args[0], | 1265 | LoadFromFile((string)args[0], |
1273 | (int) args[1], | 1266 | (int)args[1], |
1274 | (int) args[2], | 1267 | (int)args[2], |
1275 | (int) args[3], | 1268 | (int)args[3], |
1276 | (int) args[4]); | 1269 | (int)args[4]); |
1277 | } | 1270 | } |
1278 | 1271 | ||
1279 | private void InterfaceSaveFile(Object[] args) | 1272 | private void InterfaceSaveFile(Object[] args) |
1280 | { | 1273 | { |
1281 | SaveToFile((string) args[0]); | 1274 | SaveToFile((string)args[0]); |
1282 | } | 1275 | } |
1283 | 1276 | ||
1284 | private void InterfaceSaveTileFile(Object[] args) | 1277 | private void InterfaceSaveTileFile(Object[] args) |
@@ -1298,8 +1291,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1298 | private void InterfaceRevertTerrain(Object[] args) | 1291 | private void InterfaceRevertTerrain(Object[] args) |
1299 | { | 1292 | { |
1300 | int x, y; | 1293 | int x, y; |
1301 | for (x = 0; x < m_channel.Width; x++) | 1294 | for(x = 0; x < m_channel.Width; x++) |
1302 | for (y = 0; y < m_channel.Height; y++) | 1295 | for(y = 0; y < m_channel.Height; y++) |
1303 | m_channel[x, y] = m_revert[x, y]; | 1296 | m_channel[x, y] = m_revert[x, y]; |
1304 | 1297 | ||
1305 | } | 1298 | } |
@@ -1310,9 +1303,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1310 | 1303 | ||
1311 | if (direction.ToLower().StartsWith("y")) | 1304 | if (direction.ToLower().StartsWith("y")) |
1312 | { | 1305 | { |
1313 | for (int x = 0; x < m_channel.Width; x++) | 1306 | for(int x = 0; x < m_channel.Width; x++) |
1314 | { | 1307 | { |
1315 | for (int y = 0; y < m_channel.Height / 2; y++) | 1308 | for(int y = 0; y < m_channel.Height / 2; y++) |
1316 | { | 1309 | { |
1317 | double height = m_channel[x, y]; | 1310 | double height = m_channel[x, y]; |
1318 | double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y]; | 1311 | double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y]; |
@@ -1324,9 +1317,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1324 | } | 1317 | } |
1325 | else if (direction.ToLower().StartsWith("x")) | 1318 | else if (direction.ToLower().StartsWith("x")) |
1326 | { | 1319 | { |
1327 | for (int y = 0; y < m_channel.Height; y++) | 1320 | for(int y = 0; y < m_channel.Height; y++) |
1328 | { | 1321 | { |
1329 | for (int x = 0; x < m_channel.Width / 2; x++) | 1322 | for(int x = 0; x < m_channel.Width / 2; x++) |
1330 | { | 1323 | { |
1331 | double height = m_channel[x, y]; | 1324 | double height = m_channel[x, y]; |
1332 | double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y]; | 1325 | double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y]; |
@@ -1365,9 +1358,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1365 | int width = m_channel.Width; | 1358 | int width = m_channel.Width; |
1366 | int height = m_channel.Height; | 1359 | int height = m_channel.Height; |
1367 | 1360 | ||
1368 | for (int x = 0; x < width; x++) | 1361 | for(int x = 0; x < width; x++) |
1369 | { | 1362 | { |
1370 | for (int y = 0; y < height; y++) | 1363 | for(int y = 0; y < height; y++) |
1371 | { | 1364 | { |
1372 | double currHeight = m_channel[x, y]; | 1365 | double currHeight = m_channel[x, y]; |
1373 | if (currHeight < currMin) | 1366 | if (currHeight < currMin) |
@@ -1388,12 +1381,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1388 | //m_log.InfoFormat("Scale = {0}", scale); | 1381 | //m_log.InfoFormat("Scale = {0}", scale); |
1389 | 1382 | ||
1390 | // scale the heightmap accordingly | 1383 | // scale the heightmap accordingly |
1391 | for (int x = 0; x < width; x++) | 1384 | for(int x = 0; x < width; x++) |
1392 | { | 1385 | { |
1393 | for (int y = 0; y < height; y++) | 1386 | for(int y = 0; y < height; y++) |
1394 | { | 1387 | { |
1395 | double currHeight = m_channel[x, y] - currMin; | 1388 | double currHeight = m_channel[x, y] - currMin; |
1396 | m_channel[x, y] = desiredMin + (currHeight * scale); | 1389 | m_channel[x, y] = desiredMin + (currHeight * scale); |
1397 | } | 1390 | } |
1398 | } | 1391 | } |
1399 | 1392 | ||
@@ -1404,42 +1397,42 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1404 | private void InterfaceElevateTerrain(Object[] args) | 1397 | private void InterfaceElevateTerrain(Object[] args) |
1405 | { | 1398 | { |
1406 | int x, y; | 1399 | int x, y; |
1407 | for (x = 0; x < m_channel.Width; x++) | 1400 | for(x = 0; x < m_channel.Width; x++) |
1408 | for (y = 0; y < m_channel.Height; y++) | 1401 | for(y = 0; y < m_channel.Height; y++) |
1409 | m_channel[x, y] += (double) args[0]; | 1402 | m_channel[x, y] += (double)args[0]; |
1410 | } | 1403 | } |
1411 | 1404 | ||
1412 | private void InterfaceMultiplyTerrain(Object[] args) | 1405 | private void InterfaceMultiplyTerrain(Object[] args) |
1413 | { | 1406 | { |
1414 | int x, y; | 1407 | int x, y; |
1415 | for (x = 0; x < m_channel.Width; x++) | 1408 | for(x = 0; x < m_channel.Width; x++) |
1416 | for (y = 0; y < m_channel.Height; y++) | 1409 | for(y = 0; y < m_channel.Height; y++) |
1417 | m_channel[x, y] *= (double) args[0]; | 1410 | m_channel[x, y] *= (double)args[0]; |
1418 | } | 1411 | } |
1419 | 1412 | ||
1420 | private void InterfaceLowerTerrain(Object[] args) | 1413 | private void InterfaceLowerTerrain(Object[] args) |
1421 | { | 1414 | { |
1422 | int x, y; | 1415 | int x, y; |
1423 | for (x = 0; x < m_channel.Width; x++) | 1416 | for(x = 0; x < m_channel.Width; x++) |
1424 | for (y = 0; y < m_channel.Height; y++) | 1417 | for(y = 0; y < m_channel.Height; y++) |
1425 | m_channel[x, y] -= (double) args[0]; | 1418 | m_channel[x, y] -= (double)args[0]; |
1426 | } | 1419 | } |
1427 | 1420 | ||
1428 | public void InterfaceFillTerrain(Object[] args) | 1421 | public void InterfaceFillTerrain(Object[] args) |
1429 | { | 1422 | { |
1430 | int x, y; | 1423 | int x, y; |
1431 | 1424 | ||
1432 | for (x = 0; x < m_channel.Width; x++) | 1425 | for(x = 0; x < m_channel.Width; x++) |
1433 | for (y = 0; y < m_channel.Height; y++) | 1426 | for(y = 0; y < m_channel.Height; y++) |
1434 | m_channel[x, y] = (double) args[0]; | 1427 | m_channel[x, y] = (double)args[0]; |
1435 | } | 1428 | } |
1436 | 1429 | ||
1437 | private void InterfaceMinTerrain(Object[] args) | 1430 | private void InterfaceMinTerrain(Object[] args) |
1438 | { | 1431 | { |
1439 | int x, y; | 1432 | int x, y; |
1440 | for (x = 0; x < m_channel.Width; x++) | 1433 | for(x = 0; x < m_channel.Width; x++) |
1441 | { | 1434 | { |
1442 | for (y = 0; y < m_channel.Height; y++) | 1435 | for(y = 0; y < m_channel.Height; y++) |
1443 | { | 1436 | { |
1444 | m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); | 1437 | m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); |
1445 | } | 1438 | } |
@@ -1449,9 +1442,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1449 | private void InterfaceMaxTerrain(Object[] args) | 1442 | private void InterfaceMaxTerrain(Object[] args) |
1450 | { | 1443 | { |
1451 | int x, y; | 1444 | int x, y; |
1452 | for (x = 0; x < m_channel.Width; x++) | 1445 | for(x = 0; x < m_channel.Width; x++) |
1453 | { | 1446 | { |
1454 | for (y = 0; y < m_channel.Height; y++) | 1447 | for(y = 0; y < m_channel.Height; y++) |
1455 | { | 1448 | { |
1456 | m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); | 1449 | m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); |
1457 | } | 1450 | } |
@@ -1480,10 +1473,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1480 | double sum = 0; | 1473 | double sum = 0; |
1481 | 1474 | ||
1482 | int x; | 1475 | int x; |
1483 | for (x = 0; x < m_channel.Width; x++) | 1476 | for(x = 0; x < m_channel.Width; x++) |
1484 | { | 1477 | { |
1485 | int y; | 1478 | int y; |
1486 | for (y = 0; y < m_channel.Height; y++) | 1479 | for(y = 0; y < m_channel.Height; y++) |
1487 | { | 1480 | { |
1488 | sum += m_channel[x, y]; | 1481 | sum += m_channel[x, y]; |
1489 | if (max < m_channel[x, y]) | 1482 | if (max < m_channel[x, y]) |
@@ -1501,7 +1494,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1501 | 1494 | ||
1502 | private void InterfaceEnableExperimentalBrushes(Object[] args) | 1495 | private void InterfaceEnableExperimentalBrushes(Object[] args) |
1503 | { | 1496 | { |
1504 | if ((bool) args[0]) | 1497 | if ((bool)args[0]) |
1505 | { | 1498 | { |
1506 | m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere(); | 1499 | m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere(); |
1507 | m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere(); | 1500 | m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere(); |
@@ -1520,7 +1513,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1520 | if (firstArg == "list") | 1513 | if (firstArg == "list") |
1521 | { | 1514 | { |
1522 | MainConsole.Instance.Output("List of loaded plugins"); | 1515 | MainConsole.Instance.Output("List of loaded plugins"); |
1523 | foreach (KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects) | 1516 | foreach(KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects) |
1524 | { | 1517 | { |
1525 | MainConsole.Instance.Output(kvp.Key); | 1518 | MainConsole.Instance.Output(kvp.Key); |
1526 | } | 1519 | } |
@@ -1665,46 +1658,65 @@ namespace OpenSim.Region.CoreModules.World.Terrain | |||
1665 | // Add this to our scene so scripts can call these functions | 1658 | // Add this to our scene so scripts can call these functions |
1666 | m_scene.RegisterModuleCommander(m_commander); | 1659 | m_scene.RegisterModuleCommander(m_commander); |
1667 | 1660 | ||
1668 | // Add Feature command to Scene, since Command object requires fixed-length arglists | 1661 | // Add Modify command to Scene, since Command object requires fixed-length arglists |
1669 | m_scene.AddCommand("Terrain", this, "terrain feature", | 1662 | m_scene.AddCommand("Terrain", this, "terrain modify", |
1670 | "terrain feature <type> <parameters...>", "Constructs a feature of the requested type.", FeatureCommand); | 1663 | "terrain modify <operation> <value> [<area>] [<taper>]", |
1664 | "Modifies the terrain as instructed." + | ||
1665 | "\nEach operation can be limited to an area of effect:" + | ||
1666 | "\n * -ell=x,y,rx[,ry] constrains the operation to an ellipse centred at x,y" + | ||
1667 | "\n * -rec=x,y,dx[,dy] constrains the operation to a rectangle based at x,y" + | ||
1668 | "\nEach operation can have its effect tapered based on distance from centre:" + | ||
1669 | "\n * elliptical operations taper as cones" + | ||
1670 | "\n * rectangular operations taper as pyramids" | ||
1671 | , | ||
1672 | ModifyCommand); | ||
1671 | 1673 | ||
1672 | } | 1674 | } |
1673 | 1675 | ||
1674 | public void FeatureCommand(string module, string[] cmd) | 1676 | public void ModifyCommand(string module, string[] cmd) |
1675 | { | 1677 | { |
1676 | string result; | 1678 | string result; |
1677 | if (cmd.Length > 2) | 1679 | Scene scene = SceneManager.Instance.CurrentScene; |
1680 | if ((scene != null) && (scene != m_scene)) | ||
1681 | { | ||
1682 | result = String.Empty; | ||
1683 | } | ||
1684 | else if (cmd.Length > 2) | ||
1678 | { | 1685 | { |
1679 | string featureType = cmd[2]; | 1686 | string operationType = cmd[2]; |
1687 | |||
1680 | 1688 | ||
1681 | ITerrainFeature feature; | 1689 | ITerrainModifier operation; |
1682 | if (!m_featureEffects.TryGetValue(featureType, out feature)) | 1690 | if (!m_modifyOperations.TryGetValue(operationType, out operation)) |
1683 | { | 1691 | { |
1684 | result = String.Format("Terrain Feature \"{0}\" not found.", featureType); | 1692 | result = String.Format("Terrain Modify \"{0}\" not found.", operationType); |
1685 | } | 1693 | } |
1686 | else if ((cmd.Length > 3) && (cmd[3] == "usage")) | 1694 | else if ((cmd.Length > 3) && (cmd[3] == "usage")) |
1687 | { | 1695 | { |
1688 | result = "Usage: " + feature.GetUsage(); | 1696 | result = "Usage: " + operation.GetUsage(); |
1689 | } | 1697 | } |
1690 | else | 1698 | else |
1691 | { | 1699 | { |
1692 | result = feature.CreateFeature(m_channel, cmd); | 1700 | result = operation.ModifyTerrain(m_channel, cmd); |
1693 | } | 1701 | } |
1694 | 1702 | ||
1695 | if(result == String.Empty) | 1703 | if (result == String.Empty) |
1696 | { | 1704 | { |
1697 | result = "Created Feature"; | 1705 | result = "Modified terrain"; |
1698 | m_log.DebugFormat("Created terrain feature {0}", featureType); | 1706 | m_log.DebugFormat("Performed terrain operation {0}", operationType); |
1699 | } | 1707 | } |
1700 | } | 1708 | } |
1701 | else | 1709 | else |
1702 | { | 1710 | { |
1703 | result = "Usage: <feature-name> <arg1> <arg2>..."; | 1711 | result = "Usage: <operation-name> <arg1> <arg2>..."; |
1712 | } | ||
1713 | if (result != String.Empty) | ||
1714 | { | ||
1715 | MainConsole.Instance.Output(result); | ||
1704 | } | 1716 | } |
1705 | MainConsole.Instance.Output(result); | ||
1706 | } | 1717 | } |
1707 | #endregion | 1718 | |
1719 | #endregion | ||
1708 | 1720 | ||
1709 | } | 1721 | } |
1710 | } | 1722 | } |
diff --git a/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs b/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs index 637387a..e60d3ae 100644 --- a/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/DataSnapshot/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/Framework/Properties/AssemblyInfo.cs b/OpenSim/Region/Framework/Properties/AssemblyInfo.cs index fd9ab3d..97dea1f 100644 --- a/OpenSim/Region/Framework/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Framework/Properties/AssemblyInfo.cs | |||
@@ -31,6 +31,6 @@ using Mono.Addins; | |||
31 | // Build Number | 31 | // Build Number |
32 | // Revision | 32 | // Revision |
33 | // | 33 | // |
34 | [assembly: AssemblyVersion("0.8.1.*")] | 34 | [assembly: AssemblyVersion("0.8.2.*")] |
35 | [assembly: AddinRoot("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] | 35 | [assembly: AddinRoot("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] |
36 | 36 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 31900ec..905bde2 100755 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -1653,7 +1653,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1653 | 1653 | ||
1654 | // These variables will be used to save the precise frame time using the | 1654 | // These variables will be used to save the precise frame time using the |
1655 | // Stopwatch class of Microsoft SDK; the times are recorded at the start | 1655 | // Stopwatch class of Microsoft SDK; the times are recorded at the start |
1656 | // and end of a parcticular section of code, and then used to calculate | 1656 | // and end of a particular section of code, and then used to calculate |
1657 | // the frame times, which are the sums of the sections for each given name | 1657 | // the frame times, which are the sums of the sections for each given name |
1658 | double preciseTotalFrameTime = 0.0; | 1658 | double preciseTotalFrameTime = 0.0; |
1659 | double preciseSimFrameTime = 0.0; | 1659 | double preciseSimFrameTime = 0.0; |
@@ -1698,7 +1698,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1698 | // input took | 1698 | // input took |
1699 | simFrameStopwatch.Stop(); | 1699 | simFrameStopwatch.Stop(); |
1700 | preciseSimFrameTime = | 1700 | preciseSimFrameTime = |
1701 | simFrameStopwatch.Elapsed.TotalMilliseconds; | 1701 | simFrameStopwatch.Elapsed.TotalMilliseconds; |
1702 | terrainMS = Util.EnvironmentTickCountSubtract(tmpMS); | 1702 | terrainMS = Util.EnvironmentTickCountSubtract(tmpMS); |
1703 | } | 1703 | } |
1704 | 1704 | ||
@@ -1717,7 +1717,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1717 | // Begin the stopwatch to track the time to prepare physics | 1717 | // Begin the stopwatch to track the time to prepare physics |
1718 | physicsFrameStopwatch.Start(); | 1718 | physicsFrameStopwatch.Start(); |
1719 | if (PhysicsEnabled && Frame % m_update_physics == 0) | 1719 | if (PhysicsEnabled && Frame % m_update_physics == 0) |
1720 | m_sceneGraph.UpdatePreparePhysics(); | 1720 | m_sceneGraph.UpdatePreparePhysics(); |
1721 | 1721 | ||
1722 | // Get the time it took to prepare the physics, this | 1722 | // Get the time it took to prepare the physics, this |
1723 | // would report the most precise time that physics was | 1723 | // would report the most precise time that physics was |
@@ -1738,7 +1738,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1738 | // took | 1738 | // took |
1739 | simFrameStopwatch.Stop(); | 1739 | simFrameStopwatch.Stop(); |
1740 | preciseSimFrameTime += | 1740 | preciseSimFrameTime += |
1741 | simFrameStopwatch.Elapsed.TotalMilliseconds; | 1741 | simFrameStopwatch.Elapsed.TotalMilliseconds; |
1742 | agentMS = Util.EnvironmentTickCountSubtract(tmpMS); | 1742 | agentMS = Util.EnvironmentTickCountSubtract(tmpMS); |
1743 | 1743 | ||
1744 | // Perform the main physics update. This will do the actual work of moving objects and avatars according to their | 1744 | // Perform the main physics update. This will do the actual work of moving objects and avatars according to their |
@@ -1851,7 +1851,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1851 | // Get the elapsed time for the simulation frame | 1851 | // Get the elapsed time for the simulation frame |
1852 | simFrameStopwatch.Stop(); | 1852 | simFrameStopwatch.Stop(); |
1853 | preciseSimFrameTime += | 1853 | preciseSimFrameTime += |
1854 | simFrameStopwatch.Elapsed.TotalMilliseconds; | 1854 | simFrameStopwatch.Elapsed.TotalMilliseconds; |
1855 | 1855 | ||
1856 | if (!UpdateOnTimer) | 1856 | if (!UpdateOnTimer) |
1857 | { | 1857 | { |
@@ -1872,7 +1872,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1872 | // Get the total frame time | 1872 | // Get the total frame time |
1873 | totalFrameStopwatch.Stop(); | 1873 | totalFrameStopwatch.Stop(); |
1874 | preciseTotalFrameTime = | 1874 | preciseTotalFrameTime = |
1875 | totalFrameStopwatch.Elapsed.TotalMilliseconds; | 1875 | totalFrameStopwatch.Elapsed.TotalMilliseconds; |
1876 | 1876 | ||
1877 | // Restart the stopwatch for the total time of the next frame | 1877 | // Restart the stopwatch for the total time of the next frame |
1878 | totalFrameStopwatch.Restart(); | 1878 | totalFrameStopwatch.Restart(); |
@@ -1897,7 +1897,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1897 | // Send the correct time values to the stats reporter for the | 1897 | // Send the correct time values to the stats reporter for the |
1898 | // frame times | 1898 | // frame times |
1899 | StatsReporter.addFrameTimeMilliseconds(preciseTotalFrameTime, | 1899 | StatsReporter.addFrameTimeMilliseconds(preciseTotalFrameTime, |
1900 | preciseSimFrameTime, precisePhysicsFrameTime, 0.0); | 1900 | preciseSimFrameTime, precisePhysicsFrameTime, 0.0); |
1901 | 1901 | ||
1902 | // Send the correct number of frames that the physics library | 1902 | // Send the correct number of frames that the physics library |
1903 | // has processed to the stats reporter | 1903 | // has processed to the stats reporter |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 0a1a226..866a43c 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -2672,20 +2672,27 @@ namespace OpenSim.Region.Framework.Scenes | |||
2672 | } | 2672 | } |
2673 | else | 2673 | else |
2674 | { | 2674 | { |
2675 | //NonPhysicalGrabMovement(pos); | 2675 | NonPhysicalGrabMovement(pos); |
2676 | } | 2676 | } |
2677 | } | 2677 | } |
2678 | else | 2678 | else |
2679 | { | 2679 | { |
2680 | //NonPhysicalGrabMovement(pos); | 2680 | NonPhysicalGrabMovement(pos); |
2681 | } | 2681 | } |
2682 | } | 2682 | } |
2683 | } | 2683 | } |
2684 | 2684 | ||
2685 | /// <summary> | ||
2686 | /// Apply possition for grabbing non-physical linksets (Ctrl+Drag) | ||
2687 | /// This MUST be blocked for linksets that contain touch scripts because the viewer triggers grab on the touch | ||
2688 | /// event (Viewer Bug?) This would allow anyone to drag a linkset with a touch script. SL behaviour is also to | ||
2689 | /// block grab on prims with touch events. | ||
2690 | /// </summary> | ||
2691 | /// <param name="pos">New Position</param> | ||
2685 | public void NonPhysicalGrabMovement(Vector3 pos) | 2692 | public void NonPhysicalGrabMovement(Vector3 pos) |
2686 | { | 2693 | { |
2687 | AbsolutePosition = pos; | 2694 | if(!IsAttachment && ScriptCount() == 0) |
2688 | m_rootPart.SendTerseUpdateToAllClients(); | 2695 | UpdateGroupPosition(pos); |
2689 | } | 2696 | } |
2690 | 2697 | ||
2691 | /// <summary> | 2698 | /// <summary> |
@@ -2781,17 +2788,28 @@ namespace OpenSim.Region.Framework.Scenes | |||
2781 | } | 2788 | } |
2782 | else | 2789 | else |
2783 | { | 2790 | { |
2784 | //NonPhysicalSpinMovement(pos); | 2791 | NonPhysicalSpinMovement(newOrientation); |
2785 | } | 2792 | } |
2786 | } | 2793 | } |
2787 | else | 2794 | else |
2788 | { | 2795 | { |
2789 | //NonPhysicalSpinMovement(pos); | 2796 | NonPhysicalSpinMovement(newOrientation); |
2790 | } | 2797 | } |
2791 | } | 2798 | } |
2792 | } | 2799 | } |
2793 | 2800 | ||
2794 | /// <summary> | 2801 | /// <summary> |
2802 | /// Apply rotation for spinning non-physical linksets (Ctrl+Shift+Drag) | ||
2803 | /// As with dragging, scripted objects must be blocked from spinning | ||
2804 | /// </summary> | ||
2805 | /// <param name="newOrientation">New Rotation</param> | ||
2806 | private void NonPhysicalSpinMovement(Quaternion newOrientation) | ||
2807 | { | ||
2808 | if(!IsAttachment && ScriptCount() == 0) | ||
2809 | UpdateGroupRotationR(newOrientation); | ||
2810 | } | ||
2811 | |||
2812 | /// <summary> | ||
2795 | /// Set the name of a prim | 2813 | /// Set the name of a prim |
2796 | /// </summary> | 2814 | /// </summary> |
2797 | /// <param name="name"></param> | 2815 | /// <param name="name"></param> |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs new file mode 100644 index 0000000..927d8e8 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSerializationTests.cs | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Threading; | ||
32 | using System.Xml; | ||
33 | using System.Linq; | ||
34 | using Nini.Config; | ||
35 | using NUnit.Framework; | ||
36 | using OpenMetaverse; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Framework.Serialization.External; | ||
39 | using OpenSim.Framework.Communications; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using OpenSim.Region.Framework.Scenes.Serialization; | ||
42 | using OpenSim.Services.Interfaces; | ||
43 | using OpenSim.Tests.Common; | ||
44 | |||
45 | namespace OpenSim.Region.Framework.Scenes.Tests | ||
46 | { | ||
47 | /// <summary> | ||
48 | /// Basic scene object serialization tests. | ||
49 | /// </summary> | ||
50 | [TestFixture] | ||
51 | public class SceneObjectSerializationTests : OpenSimTestCase | ||
52 | { | ||
53 | |||
54 | /// <summary> | ||
55 | /// Serialize and deserialize. | ||
56 | /// </summary> | ||
57 | [Test] | ||
58 | public void TestSerialDeserial() | ||
59 | { | ||
60 | TestHelpers.InMethod(); | ||
61 | |||
62 | Scene scene = new SceneHelpers().SetupScene(); | ||
63 | int partsToTestCount = 3; | ||
64 | |||
65 | SceneObjectGroup so | ||
66 | = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10); | ||
67 | SceneObjectPart[] parts = so.Parts; | ||
68 | so.Name = "obj1"; | ||
69 | so.Description = "xpto"; | ||
70 | |||
71 | string xml = SceneObjectSerializer.ToXml2Format(so); | ||
72 | Assert.That(!string.IsNullOrEmpty(xml), "SOG serialization resulted in empty or null string"); | ||
73 | |||
74 | XmlDocument doc = new XmlDocument(); | ||
75 | doc.LoadXml(xml); | ||
76 | XmlNodeList nodes = doc.GetElementsByTagName("SceneObjectPart"); | ||
77 | Assert.That(nodes.Count, Is.EqualTo(3), "SOG serialization resulted in wrong number of SOPs"); | ||
78 | |||
79 | SceneObjectGroup so2 = SceneObjectSerializer.FromXml2Format(xml); | ||
80 | Assert.IsNotNull(so2, "SOG deserialization resulted in null object"); | ||
81 | Assert.That(so2.Name == so.Name, "Name of deserialized object does not match original name"); | ||
82 | Assert.That(so2.Description == so.Description, "Description of deserialized object does not match original name"); | ||
83 | } | ||
84 | |||
85 | /// <summary> | ||
86 | /// This checks for a bug reported in mantis #7514 | ||
87 | /// </summary> | ||
88 | [Test] | ||
89 | public void TestNamespaceAttribute() | ||
90 | { | ||
91 | TestHelpers.InMethod(); | ||
92 | |||
93 | Scene scene = new SceneHelpers().SetupScene(); | ||
94 | UserAccount account = new UserAccount(UUID.Zero, UUID.Random(), "Test", "User", string.Empty); | ||
95 | scene.UserAccountService.StoreUserAccount(account); | ||
96 | int partsToTestCount = 1; | ||
97 | |||
98 | SceneObjectGroup so | ||
99 | = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10); | ||
100 | SceneObjectPart[] parts = so.Parts; | ||
101 | so.Name = "obj1"; | ||
102 | so.Description = "xpto"; | ||
103 | so.OwnerID = account.PrincipalID; | ||
104 | so.RootPart.CreatorID = so.OwnerID; | ||
105 | |||
106 | string xml = SceneObjectSerializer.ToXml2Format(so); | ||
107 | Assert.That(!string.IsNullOrEmpty(xml), "SOG serialization resulted in empty or null string"); | ||
108 | |||
109 | xml = ExternalRepresentationUtils.RewriteSOP(xml, "Test Scene", "http://localhost", scene.UserAccountService, UUID.Zero); | ||
110 | //Console.WriteLine(xml); | ||
111 | |||
112 | XmlDocument doc = new XmlDocument(); | ||
113 | doc.LoadXml(xml); | ||
114 | |||
115 | XmlNodeList nodes = doc.GetElementsByTagName("SceneObjectPart"); | ||
116 | Assert.That(nodes.Count, Is.GreaterThan(0), "SOG serialization resulted in no SOPs"); | ||
117 | foreach (XmlAttribute a in nodes[0].Attributes) | ||
118 | { | ||
119 | int count = a.Name.Count(c => c == ':'); | ||
120 | Assert.That(count, Is.EqualTo(1), "Cannot have multiple ':' in attribute name in SOP"); | ||
121 | } | ||
122 | nodes = doc.GetElementsByTagName("CreatorData"); | ||
123 | Assert.That(nodes.Count, Is.GreaterThan(0), "SOG serialization resulted in no CreatorData"); | ||
124 | foreach (XmlAttribute a in nodes[0].Attributes) | ||
125 | { | ||
126 | int count = a.Name.Count(c => c == ':'); | ||
127 | Assert.That(count, Is.EqualTo(1), "Cannot have multiple ':' in attribute name in CreatorData"); | ||
128 | } | ||
129 | |||
130 | SceneObjectGroup so2 = SceneObjectSerializer.FromXml2Format(xml); | ||
131 | Assert.IsNotNull(so2, "SOG deserialization resulted in null object"); | ||
132 | Assert.AreNotEqual(so.RootPart.CreatorIdentification, so2.RootPart.CreatorIdentification, "RewriteSOP failed to transform CreatorData."); | ||
133 | Assert.That(so2.RootPart.CreatorIdentification.Contains("http://"), "RewriteSOP failed to add the homeURL to CreatorData"); | ||
134 | } | ||
135 | } | ||
136 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs b/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs index d028374..f8ad958 100644 --- a/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/OptionalModules/Properties/AssemblyInfo.cs | |||
@@ -30,7 +30,7 @@ using Mono.Addins; | |||
30 | // Build Number | 30 | // Build Number |
31 | // Revision | 31 | // Revision |
32 | // | 32 | // |
33 | [assembly: AssemblyVersion("0.8.1.*")] | 33 | [assembly: AssemblyVersion("0.8.2.*")] |
34 | 34 | ||
35 | 35 | ||
36 | [assembly: Addin("OpenSim.Region.OptionalModules", OpenSim.VersionInfo.VersionNumber)] | 36 | [assembly: Addin("OpenSim.Region.OptionalModules", OpenSim.VersionInfo.VersionNumber)] |
diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs index 28dc5f5..ceb3332 100644 --- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs +++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs | |||
@@ -115,6 +115,9 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup | |||
115 | 115 | ||
116 | private delegate T DefaultGetter<T>(string settingName, T defaultValue); | 116 | private delegate T DefaultGetter<T>(string settingName, T defaultValue); |
117 | private bool m_enabled; | 117 | private bool m_enabled; |
118 | private ICommandConsole m_console; | ||
119 | private List<Scene> m_Scenes = new List<Scene> (); | ||
120 | |||
118 | 121 | ||
119 | /// <summary> | 122 | /// <summary> |
120 | /// Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState! | 123 | /// Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState! |
@@ -206,8 +209,20 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup | |||
206 | /// Currently a no-op for AutoBackup because we have to wait for region to be fully loaded. | 209 | /// Currently a no-op for AutoBackup because we have to wait for region to be fully loaded. |
207 | /// </summary> | 210 | /// </summary> |
208 | /// <param name="scene"></param> | 211 | /// <param name="scene"></param> |
209 | void IRegionModuleBase.AddRegion(Scene scene) | 212 | void IRegionModuleBase.AddRegion (Scene scene) |
210 | { | 213 | { |
214 | if (!this.m_enabled) { | ||
215 | return; | ||
216 | } | ||
217 | lock (m_Scenes) { | ||
218 | m_Scenes.Add (scene); | ||
219 | } | ||
220 | m_console = MainConsole.Instance; | ||
221 | |||
222 | m_console.Commands.AddCommand ( | ||
223 | "AutoBackup", false, "dobackup", | ||
224 | "dobackup", | ||
225 | "do backup.", DoBackup); | ||
211 | } | 226 | } |
212 | 227 | ||
213 | /// <summary> | 228 | /// <summary> |
@@ -220,7 +235,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup | |||
220 | { | 235 | { |
221 | return; | 236 | return; |
222 | } | 237 | } |
223 | 238 | m_Scenes.Remove (scene); | |
224 | if (this.m_states.ContainsKey(scene)) | 239 | if (this.m_states.ContainsKey(scene)) |
225 | { | 240 | { |
226 | AutoBackupModuleState abms = this.m_states[scene]; | 241 | AutoBackupModuleState abms = this.m_states[scene]; |
@@ -275,6 +290,28 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup | |||
275 | 290 | ||
276 | #endregion | 291 | #endregion |
277 | 292 | ||
293 | private void DoBackup (string module, string[] args) | ||
294 | { | ||
295 | if (args.Length != 2) { | ||
296 | MainConsole.Instance.OutputFormat ("Usage: dobackup <regionname>"); | ||
297 | return; | ||
298 | } | ||
299 | bool found = false; | ||
300 | string name = args [1]; | ||
301 | lock (m_Scenes) { | ||
302 | foreach (Scene s in m_Scenes) { | ||
303 | string test = s.Name.ToString (); | ||
304 | if (test == name) { | ||
305 | found = true; | ||
306 | DoRegionBackup (s); | ||
307 | } | ||
308 | } | ||
309 | if (!found) { | ||
310 | MainConsole.Instance.OutputFormat ("No such region {0}. Nothing to backup", name); | ||
311 | } | ||
312 | } | ||
313 | } | ||
314 | |||
278 | /// <summary> | 315 | /// <summary> |
279 | /// Set up internal state for a given scene. Fairly complex code. | 316 | /// Set up internal state for a given scene. Fairly complex code. |
280 | /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene. | 317 | /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene. |
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs index eba0675..7d054dd 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs | |||
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices; | |||
55 | // You can specify all values by your own or you can build default build and revision | 55 | // You can specify all values by your own or you can build default build and revision |
56 | // numbers with the '*' character (the default): | 56 | // numbers with the '*' character (the default): |
57 | 57 | ||
58 | [assembly : AssemblyVersion("0.8.1.*")] | 58 | [assembly : AssemblyVersion("0.8.2.*")] |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs index 4de5b47..4f90eee 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs index 1486ba8..c5867b2 100644 --- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs | |||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices; | |||
32 | // You can specify all the values or you can default the Build and Revision Numbers | 32 | // You can specify all the values or you can default the Build and Revision Numbers |
33 | // by using the '*' as shown below: | 33 | // by using the '*' as shown below: |
34 | // [assembly: AssemblyVersion("1.0.*")] | 34 | // [assembly: AssemblyVersion("1.0.*")] |
35 | [assembly: AssemblyVersion("0.8.1.*")] | 35 | [assembly: AssemblyVersion("0.8.2.*")] |
36 | 36 | ||
diff --git a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs index 202ef20..33f60e4 100644 --- a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs | |||
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices; | |||
55 | // You can specify all values by your own or you can build default build and revision | 55 | // You can specify all values by your own or you can build default build and revision |
56 | // numbers with the '*' character (the default): | 56 | // numbers with the '*' character (the default): |
57 | 57 | ||
58 | [assembly : AssemblyVersion("0.8.1.*")] | 58 | [assembly : AssemblyVersion("0.8.2.*")] |
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index d96de4a..42231b5 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -84,7 +84,8 @@ namespace OpenSim.Region.Physics.Meshing | |||
84 | private List<List<Vector3>> mConvexHulls = null; | 84 | private List<List<Vector3>> mConvexHulls = null; |
85 | private List<Vector3> mBoundingHull = null; | 85 | private List<Vector3> mBoundingHull = null; |
86 | 86 | ||
87 | private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); | 87 | // Mesh cache. Static so it can be shared across instances of this class |
88 | private static Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); | ||
88 | 89 | ||
89 | public Meshmerizer(IConfigSource config) | 90 | public Meshmerizer(IConfigSource config) |
90 | { | 91 | { |
@@ -927,8 +928,11 @@ namespace OpenSim.Region.Physics.Meshing | |||
927 | if (shouldCache) | 928 | if (shouldCache) |
928 | { | 929 | { |
929 | key = primShape.GetMeshKey(size, lod); | 930 | key = primShape.GetMeshKey(size, lod); |
930 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | 931 | lock (m_uniqueMeshes) |
931 | return mesh; | 932 | { |
933 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | ||
934 | return mesh; | ||
935 | } | ||
932 | } | 936 | } |
933 | 937 | ||
934 | if (size.X < 0.01f) size.X = 0.01f; | 938 | if (size.X < 0.01f) size.X = 0.01f; |
@@ -954,7 +958,10 @@ namespace OpenSim.Region.Physics.Meshing | |||
954 | 958 | ||
955 | if (shouldCache) | 959 | if (shouldCache) |
956 | { | 960 | { |
957 | m_uniqueMeshes.Add(key, mesh); | 961 | lock (m_uniqueMeshes) |
962 | { | ||
963 | m_uniqueMeshes.Add(key, mesh); | ||
964 | } | ||
958 | } | 965 | } |
959 | } | 966 | } |
960 | 967 | ||
diff --git a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs index 2b083fe..ec968c0 100644 --- a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs index b95f7f4..076da78 100644 --- a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs | |||
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices; | |||
55 | // You can specify all values by your own or you can build default build and revision | 55 | // You can specify all values by your own or you can build default build and revision |
56 | // numbers with the '*' character (the default): | 56 | // numbers with the '*' character (the default): |
57 | 57 | ||
58 | [assembly : AssemblyVersion("0.8.1.*")] | 58 | [assembly : AssemblyVersion("0.8.2.*")] |
diff --git a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs index 125d38a..fc1ffba 100644 --- a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs | |||
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices; | |||
55 | // You can specify all values by your own or you can build default build and revision | 55 | // You can specify all values by your own or you can build default build and revision |
56 | // numbers with the '*' character (the default): | 56 | // numbers with the '*' character (the default): |
57 | 57 | ||
58 | [assembly : AssemblyVersion("0.8.1.*")] | 58 | [assembly : AssemblyVersion("0.8.2.*")] |
diff --git a/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs b/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs index e8b29f9..11b89d2 100644 --- a/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/RegionCombinerModule/Properties/AssemblyInfo.cs | |||
@@ -30,7 +30,7 @@ using Mono.Addins; | |||
30 | // Build Number | 30 | // Build Number |
31 | // Revision | 31 | // Revision |
32 | // | 32 | // |
33 | [assembly: AssemblyVersion("0.8.1.*")] | 33 | [assembly: AssemblyVersion("0.8.2.*")] |
34 | 34 | ||
35 | [assembly: Addin("OpenSim.RegionModules.RegionCombinerModule", OpenSim.VersionInfo.VersionNumber)] | 35 | [assembly: Addin("OpenSim.RegionModules.RegionCombinerModule", OpenSim.VersionInfo.VersionNumber)] |
36 | [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] | 36 | [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 40b7c35..089a5a8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -28,6 +28,8 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
31 | using System.Runtime.Remoting.Lifetime; | 33 | using System.Runtime.Remoting.Lifetime; |
32 | using System.Text; | 34 | using System.Text; |
33 | using System.Threading; | 35 | using System.Threading; |
@@ -35,7 +37,9 @@ using System.Text.RegularExpressions; | |||
35 | using Nini.Config; | 37 | using Nini.Config; |
36 | using log4net; | 38 | using log4net; |
37 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | using OpenMetaverse.Assets; | ||
38 | using OpenMetaverse.Packets; | 41 | using OpenMetaverse.Packets; |
42 | using OpenMetaverse.Rendering; | ||
39 | using OpenSim; | 43 | using OpenSim; |
40 | using OpenSim.Framework; | 44 | using OpenSim.Framework; |
41 | 45 | ||
@@ -182,6 +186,55 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
182 | protected bool m_restrictEmail = false; | 186 | protected bool m_restrictEmail = false; |
183 | protected ISoundModule m_SoundModule = null; | 187 | protected ISoundModule m_SoundModule = null; |
184 | 188 | ||
189 | protected float m_avatarHeightCorrection = 0.2f; | ||
190 | protected bool m_useSimpleBoxesInGetBoundingBox = false; | ||
191 | protected bool m_addStatsInGetBoundingBox = false; | ||
192 | |||
193 | //LSL Avatar Bounding Box (lABB), lower (1) and upper (2), | ||
194 | //standing (Std), Groundsitting (Grs), Sitting (Sit), | ||
195 | //along X, Y and Z axes, constants (0) and coefficients (1) | ||
196 | protected float m_lABB1StdX0 = -0.275f; | ||
197 | protected float m_lABB2StdX0 = 0.275f; | ||
198 | protected float m_lABB1StdY0 = -0.35f; | ||
199 | protected float m_lABB2StdY0 = 0.35f; | ||
200 | protected float m_lABB1StdZ0 = -0.1f; | ||
201 | protected float m_lABB1StdZ1 = -0.5f; | ||
202 | protected float m_lABB2StdZ0 = 0.1f; | ||
203 | protected float m_lABB2StdZ1 = 0.5f; | ||
204 | protected float m_lABB1GrsX0 = -0.3875f; | ||
205 | protected float m_lABB2GrsX0 = 0.3875f; | ||
206 | protected float m_lABB1GrsY0 = -0.5f; | ||
207 | protected float m_lABB2GrsY0 = 0.5f; | ||
208 | protected float m_lABB1GrsZ0 = -0.05f; | ||
209 | protected float m_lABB1GrsZ1 = -0.375f; | ||
210 | protected float m_lABB2GrsZ0 = 0.5f; | ||
211 | protected float m_lABB2GrsZ1 = 0.0f; | ||
212 | protected float m_lABB1SitX0 = -0.5875f; | ||
213 | protected float m_lABB2SitX0 = 0.1875f; | ||
214 | protected float m_lABB1SitY0 = -0.35f; | ||
215 | protected float m_lABB2SitY0 = 0.35f; | ||
216 | protected float m_lABB1SitZ0 = -0.35f; | ||
217 | protected float m_lABB1SitZ1 = -0.375f; | ||
218 | protected float m_lABB2SitZ0 = -0.25f; | ||
219 | protected float m_lABB2SitZ1 = 0.25f; | ||
220 | |||
221 | protected float m_primSafetyCoeffX = 2.414214f; | ||
222 | protected float m_primSafetyCoeffY = 2.414214f; | ||
223 | protected float m_primSafetyCoeffZ = 1.618034f; | ||
224 | protected bool m_useCastRayV3 = false; | ||
225 | protected float m_floatToleranceInCastRay = 0.000001f; | ||
226 | protected float m_floatTolerance2InCastRay = 0.0001f; | ||
227 | protected DetailLevel m_primLodInCastRay = DetailLevel.Medium; | ||
228 | protected DetailLevel m_sculptLodInCastRay = DetailLevel.Medium; | ||
229 | protected DetailLevel m_meshLodInCastRay = DetailLevel.Highest; | ||
230 | protected DetailLevel m_avatarLodInCastRay = DetailLevel.Medium; | ||
231 | protected int m_maxHitsInCastRay = 16; | ||
232 | protected int m_maxHitsPerPrimInCastRay = 16; | ||
233 | protected int m_maxHitsPerObjectInCastRay = 16; | ||
234 | protected bool m_detectExitsInCastRay = false; | ||
235 | protected bool m_filterPartsInCastRay = false; | ||
236 | protected bool m_doAttachmentsInCastRay = false; | ||
237 | |||
185 | //An array of HTTP/1.1 headers that are not allowed to be used | 238 | //An array of HTTP/1.1 headers that are not allowed to be used |
186 | //as custom headers by llHTTPRequest. | 239 | //as custom headers by llHTTPRequest. |
187 | private string[] HttpStandardHeaders = | 240 | private string[] HttpStandardHeaders = |
@@ -257,6 +310,49 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
257 | if (lslConfig != null) | 310 | if (lslConfig != null) |
258 | { | 311 | { |
259 | m_restrictEmail = lslConfig.GetBoolean("RestrictEmail", m_restrictEmail); | 312 | m_restrictEmail = lslConfig.GetBoolean("RestrictEmail", m_restrictEmail); |
313 | m_avatarHeightCorrection = lslConfig.GetFloat("AvatarHeightCorrection", m_avatarHeightCorrection); | ||
314 | m_useSimpleBoxesInGetBoundingBox = lslConfig.GetBoolean("UseSimpleBoxesInGetBoundingBox", m_useSimpleBoxesInGetBoundingBox); | ||
315 | m_addStatsInGetBoundingBox = lslConfig.GetBoolean("AddStatsInGetBoundingBox", m_addStatsInGetBoundingBox); | ||
316 | m_lABB1StdX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingXconst", m_lABB1StdX0); | ||
317 | m_lABB2StdX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingXconst", m_lABB2StdX0); | ||
318 | m_lABB1StdY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingYconst", m_lABB1StdY0); | ||
319 | m_lABB2StdY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingYconst", m_lABB2StdY0); | ||
320 | m_lABB1StdZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZconst", m_lABB1StdZ0); | ||
321 | m_lABB1StdZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxStandingZcoeff", m_lABB1StdZ1); | ||
322 | m_lABB2StdZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZconst", m_lABB2StdZ0); | ||
323 | m_lABB2StdZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxStandingZcoeff", m_lABB2StdZ1); | ||
324 | m_lABB1GrsX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingXconst", m_lABB1GrsX0); | ||
325 | m_lABB2GrsX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingXconst", m_lABB2GrsX0); | ||
326 | m_lABB1GrsY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingYconst", m_lABB1GrsY0); | ||
327 | m_lABB2GrsY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingYconst", m_lABB2GrsY0); | ||
328 | m_lABB1GrsZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZconst", m_lABB1GrsZ0); | ||
329 | m_lABB1GrsZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxGroundsittingZcoeff", m_lABB1GrsZ1); | ||
330 | m_lABB2GrsZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZconst", m_lABB2GrsZ0); | ||
331 | m_lABB2GrsZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxGroundsittingZcoeff", m_lABB2GrsZ1); | ||
332 | m_lABB1SitX0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingXconst", m_lABB1SitX0); | ||
333 | m_lABB2SitX0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingXconst", m_lABB2SitX0); | ||
334 | m_lABB1SitY0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingYconst", m_lABB1SitY0); | ||
335 | m_lABB2SitY0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingYconst", m_lABB2SitY0); | ||
336 | m_lABB1SitZ0 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZconst", m_lABB1SitZ0); | ||
337 | m_lABB1SitZ1 = lslConfig.GetFloat("LowerAvatarBoundingBoxSittingZcoeff", m_lABB1SitZ1); | ||
338 | m_lABB2SitZ0 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZconst", m_lABB2SitZ0); | ||
339 | m_lABB2SitZ1 = lslConfig.GetFloat("UpperAvatarBoundingBoxSittingZcoeff", m_lABB2SitZ1); | ||
340 | m_primSafetyCoeffX = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientX", m_primSafetyCoeffX); | ||
341 | m_primSafetyCoeffY = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientY", m_primSafetyCoeffY); | ||
342 | m_primSafetyCoeffZ = lslConfig.GetFloat("PrimBoundingBoxSafetyCoefficientZ", m_primSafetyCoeffZ); | ||
343 | m_useCastRayV3 = lslConfig.GetBoolean("UseLlCastRayV3", m_useCastRayV3); | ||
344 | m_floatToleranceInCastRay = lslConfig.GetFloat("FloatToleranceInLlCastRay", m_floatToleranceInCastRay); | ||
345 | m_floatTolerance2InCastRay = lslConfig.GetFloat("FloatTolerance2InLlCastRay", m_floatTolerance2InCastRay); | ||
346 | m_primLodInCastRay = (DetailLevel)lslConfig.GetInt("PrimDetailLevelInLlCastRay", (int)m_primLodInCastRay); | ||
347 | m_sculptLodInCastRay = (DetailLevel)lslConfig.GetInt("SculptDetailLevelInLlCastRay", (int)m_sculptLodInCastRay); | ||
348 | m_meshLodInCastRay = (DetailLevel)lslConfig.GetInt("MeshDetailLevelInLlCastRay", (int)m_meshLodInCastRay); | ||
349 | m_avatarLodInCastRay = (DetailLevel)lslConfig.GetInt("AvatarDetailLevelInLlCastRay", (int)m_avatarLodInCastRay); | ||
350 | m_maxHitsInCastRay = lslConfig.GetInt("MaxHitsInLlCastRay", m_maxHitsInCastRay); | ||
351 | m_maxHitsPerPrimInCastRay = lslConfig.GetInt("MaxHitsPerPrimInLlCastRay", m_maxHitsPerPrimInCastRay); | ||
352 | m_maxHitsPerObjectInCastRay = lslConfig.GetInt("MaxHitsPerObjectInLlCastRay", m_maxHitsPerObjectInCastRay); | ||
353 | m_detectExitsInCastRay = lslConfig.GetBoolean("DetectExitHitsInLlCastRay", m_detectExitsInCastRay); | ||
354 | m_filterPartsInCastRay = lslConfig.GetBoolean("FilterPartsInLlCastRay", m_filterPartsInCastRay); | ||
355 | m_doAttachmentsInCastRay = lslConfig.GetBoolean("DoAttachmentsInLlCastRay", m_doAttachmentsInCastRay); | ||
260 | } | 356 | } |
261 | 357 | ||
262 | IConfig smtpConfig = seConfigSource.Configs["SMTP"]; | 358 | IConfig smtpConfig = seConfigSource.Configs["SMTP"]; |
@@ -7725,13 +7821,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
7725 | { | 7821 | { |
7726 | profilecut.y = 1f; | 7822 | profilecut.y = 1f; |
7727 | } | 7823 | } |
7728 | if (profilecut.y - profilecut.x < 0.05f) | 7824 | if (profilecut.y - profilecut.x < 0.02f) |
7729 | { | 7825 | { |
7730 | profilecut.x = profilecut.y - 0.05f; | 7826 | profilecut.x = profilecut.y - 0.02f; |
7731 | if (profilecut.x < 0.0f) | 7827 | if (profilecut.x < 0.0f) |
7732 | { | 7828 | { |
7733 | profilecut.x = 0.0f; | 7829 | profilecut.x = 0.0f; |
7734 | profilecut.y = 0.05f; | 7830 | profilecut.y = 0.02f; |
7735 | } | 7831 | } |
7736 | } | 7832 | } |
7737 | shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x); | 7833 | shapeBlock.ProfileBegin = (ushort)(50000 * profilecut.x); |
@@ -9584,80 +9680,441 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
9584 | } | 9680 | } |
9585 | 9681 | ||
9586 | /// <summary> | 9682 | /// <summary> |
9587 | /// A partial implementation. | 9683 | /// Full implementation of llGetBoundingBox according to SL 2015-04-15. |
9684 | /// http://wiki.secondlife.com/wiki/LlGetBoundingBox | ||
9588 | /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox | 9685 | /// http://lslwiki.net/lslwiki/wakka.php?wakka=llGetBoundingBox |
9589 | /// So far only valid for standing/flying/ground sitting avatars and single prim objects. | 9686 | /// Returns local bounding box of avatar without attachments |
9590 | /// If the object has multiple prims and/or a sitting avatar then the bounding | 9687 | /// if target is non-seated avatar or prim/mesh in avatar attachment. |
9591 | /// box is for the root prim only. | 9688 | /// Returns local bounding box of object including seated avatars |
9689 | /// if target is seated avatar or prim/mesh in object. | ||
9690 | /// Uses meshing of prims for high accuracy | ||
9691 | /// or less accurate box models for speed. | ||
9592 | /// </summary> | 9692 | /// </summary> |
9593 | public LSL_List llGetBoundingBox(string obj) | 9693 | public LSL_List llGetBoundingBox(string obj) |
9594 | { | 9694 | { |
9595 | m_host.AddScriptLPS(1); | 9695 | m_host.AddScriptLPS(1); |
9696 | |||
9697 | // Get target avatar if non-seated avatar or attachment, or prim and object | ||
9596 | UUID objID = UUID.Zero; | 9698 | UUID objID = UUID.Zero; |
9699 | UUID.TryParse(obj, out objID); | ||
9700 | ScenePresence agent = World.GetScenePresence(objID); | ||
9701 | if (agent != null) | ||
9702 | { | ||
9703 | if (agent.ParentPart != null) | ||
9704 | { | ||
9705 | objID = agent.ParentPart.UUID; | ||
9706 | agent = null; | ||
9707 | } | ||
9708 | } | ||
9709 | SceneObjectGroup group = null; | ||
9710 | SceneObjectPart target = World.GetSceneObjectPart(objID); | ||
9711 | if (target != null) | ||
9712 | { | ||
9713 | group = target.ParentGroup; | ||
9714 | if (group.IsAttachment) { | ||
9715 | objID = group.AttachedAvatar; | ||
9716 | agent = World.GetScenePresence(objID); | ||
9717 | group = null; | ||
9718 | target = null; | ||
9719 | } | ||
9720 | } | ||
9721 | |||
9722 | // Initialize but break if no target | ||
9597 | LSL_List result = new LSL_List(); | 9723 | LSL_List result = new LSL_List(); |
9598 | if (!UUID.TryParse(obj, out objID)) | 9724 | int groupCount = 0; |
9725 | int partCount = 0; | ||
9726 | int vertexCount = 0; | ||
9727 | if (target == null && agent == null) | ||
9599 | { | 9728 | { |
9600 | result.Add(new LSL_Vector()); | 9729 | result.Add(new LSL_Vector()); |
9601 | result.Add(new LSL_Vector()); | 9730 | result.Add(new LSL_Vector()); |
9731 | if (m_addStatsInGetBoundingBox) | ||
9732 | result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); | ||
9602 | return result; | 9733 | return result; |
9603 | } | 9734 | } |
9604 | ScenePresence presence = World.GetScenePresence(objID); | 9735 | Vector3 minPosition = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); |
9605 | if (presence != null) | 9736 | Vector3 maxPosition = new Vector3(float.MinValue, float.MinValue, float.MinValue); |
9737 | |||
9738 | // Try to get a mesher | ||
9739 | IRendering primMesher = null; | ||
9740 | List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); | ||
9741 | if (renderers.Count > 0) | ||
9742 | primMesher = RenderingLoader.LoadRenderer(renderers[0]); | ||
9743 | |||
9744 | // Get bounding box of just avatar, seated or not | ||
9745 | if (agent != null) | ||
9746 | { | ||
9747 | bool hasParent = false; | ||
9748 | Vector3 lower; | ||
9749 | Vector3 upper; | ||
9750 | BoundingBoxOfScenePresence(agent, out lower, out upper); | ||
9751 | Vector3 offset = Vector3.Zero; | ||
9752 | |||
9753 | // Since local bounding box unrotated and untilted, keep it simple | ||
9754 | AddBoundingBoxOfSimpleBox(lower, upper, offset, agent.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9755 | partCount++; | ||
9756 | groupCount++; | ||
9757 | |||
9758 | // Return lower and upper bounding box corners | ||
9759 | result.Add(new LSL_Vector(minPosition)); | ||
9760 | result.Add(new LSL_Vector(maxPosition)); | ||
9761 | if (m_addStatsInGetBoundingBox) | ||
9762 | result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); | ||
9763 | return result; | ||
9764 | } | ||
9765 | // Get bounding box of object including seated avatars | ||
9766 | else if (group != null) | ||
9606 | { | 9767 | { |
9607 | if (presence.ParentID == 0) // not sat on an object | 9768 | // Merge bounding boxes of all parts (prims and mesh) |
9769 | foreach (SceneObjectPart part in group.Parts) | ||
9608 | { | 9770 | { |
9609 | LSL_Vector lower; | 9771 | bool hasParent = (!part.IsRoot); |
9610 | LSL_Vector upper; | 9772 | // When requested or if no mesher, keep it simple |
9611 | if (presence.Animator.Animations.ImplicitDefaultAnimation.AnimID | 9773 | if (m_useSimpleBoxesInGetBoundingBox || primMesher == null) |
9612 | == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) | ||
9613 | { | 9774 | { |
9614 | // This is for ground sitting avatars | 9775 | AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount); |
9615 | float height = presence.Appearance.AvatarHeight / 2.66666667f; | ||
9616 | lower = new LSL_Vector(-0.3375f, -0.45f, height * -1.0f); | ||
9617 | upper = new LSL_Vector(0.3375f, 0.45f, 0.0f); | ||
9618 | } | 9776 | } |
9777 | // Do the full mounty | ||
9619 | else | 9778 | else |
9620 | { | 9779 | { |
9621 | // This is for standing/flying avatars | 9780 | Primitive omvPrim = part.Shape.ToOmvPrimitive(part.OffsetPosition, part.RotationOffset); |
9622 | float height = presence.Appearance.AvatarHeight / 2.0f; | 9781 | byte[] sculptAsset = null; |
9623 | lower = new LSL_Vector(-0.225f, -0.3f, height * -1.0f); | 9782 | if (omvPrim.Sculpt != null) |
9624 | upper = new LSL_Vector(0.225f, 0.3f, height + 0.05f); | 9783 | sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); |
9784 | |||
9785 | // When part is mesh | ||
9786 | // Quirk: Only imports as incompletely populated faceted mesh object, so needs an own handler. | ||
9787 | if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) | ||
9788 | { | ||
9789 | AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); | ||
9790 | FacetedMesh mesh = null; | ||
9791 | FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out mesh); | ||
9792 | meshAsset = null; | ||
9793 | if (mesh != null) | ||
9794 | { | ||
9795 | AddBoundingBoxOfFacetedMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9796 | mesh = null; | ||
9797 | } | ||
9798 | } | ||
9799 | |||
9800 | // When part is sculpt | ||
9801 | // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. | ||
9802 | else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) | ||
9803 | { | ||
9804 | IJ2KDecoder imgDecoder = World.RequestModuleInterface<IJ2KDecoder>(); | ||
9805 | if (imgDecoder != null) | ||
9806 | { | ||
9807 | Image sculpt = imgDecoder.DecodeToImage(sculptAsset); | ||
9808 | if (sculpt != null) | ||
9809 | { | ||
9810 | SimpleMesh mesh = primMesher.GenerateSimpleSculptMesh(omvPrim, (Bitmap)sculpt, DetailLevel.Medium); | ||
9811 | sculpt.Dispose(); | ||
9812 | if (mesh != null) | ||
9813 | { | ||
9814 | AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9815 | mesh = null; | ||
9816 | } | ||
9817 | } | ||
9818 | } | ||
9819 | } | ||
9820 | |||
9821 | // When part is prim | ||
9822 | else if (omvPrim.Sculpt == null) | ||
9823 | { | ||
9824 | SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); | ||
9825 | if (mesh != null) | ||
9826 | { | ||
9827 | AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9828 | mesh = null; | ||
9829 | } | ||
9830 | } | ||
9831 | |||
9832 | // When all else fails, try fallback to simple box | ||
9833 | else | ||
9834 | { | ||
9835 | AddBoundingBoxOfSimpleBox(part.Scale * -0.5f, part.Scale * 0.5f, part.OffsetPosition, part.RotationOffset, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9836 | } | ||
9625 | } | 9837 | } |
9626 | result.Add(lower); | 9838 | partCount++; |
9627 | result.Add(upper); | ||
9628 | return result; | ||
9629 | } | 9839 | } |
9840 | } | ||
9841 | |||
9842 | // Merge bounding boxes of seated avatars | ||
9843 | foreach (ScenePresence sp in group.GetSittingAvatars()) | ||
9844 | { | ||
9845 | Vector3 lower; | ||
9846 | Vector3 upper; | ||
9847 | BoundingBoxOfScenePresence(sp, out lower, out upper); | ||
9848 | Vector3 offset = sp.OffsetPosition; | ||
9849 | |||
9850 | bool hasParent = true; | ||
9851 | // When requested or if no mesher, keep it simple | ||
9852 | if (m_useSimpleBoxesInGetBoundingBox || primMesher == null) | ||
9853 | { | ||
9854 | AddBoundingBoxOfSimpleBox(lower, upper, offset, sp.Rotation, hasParent, ref minPosition, ref maxPosition, ref vertexCount); | ||
9855 | } | ||
9856 | // Do the full mounty | ||
9630 | else | 9857 | else |
9631 | { | 9858 | { |
9632 | // sitting on an object so we need the bounding box of that | 9859 | // Prim shapes don't do center offsets, so add it here. |
9633 | // which should include the avatar so set the UUID to the | 9860 | offset = offset + (lower + upper) * 0.5f * sp.Rotation; |
9634 | // UUID of the object the avatar is sat on and allow it to fall through | 9861 | Primitive omvPrim = MakeOpenMetaversePrim(upper - lower, offset, sp.Rotation, ScriptBaseClass.PRIM_TYPE_SPHERE); |
9635 | // to processing an object | 9862 | SimpleMesh mesh = primMesher.GenerateSimpleMesh(omvPrim, DetailLevel.Medium); |
9636 | SceneObjectPart p = World.GetSceneObjectPart(presence.ParentID); | 9863 | AddBoundingBoxOfSimpleMesh(mesh, omvPrim, hasParent, ref minPosition, ref maxPosition, ref vertexCount); |
9637 | objID = p.UUID; | 9864 | mesh = null; |
9638 | } | 9865 | } |
9866 | partCount++; | ||
9867 | } | ||
9868 | |||
9869 | groupCount++; | ||
9870 | |||
9871 | // Return lower and upper bounding box corners | ||
9872 | result.Add(new LSL_Vector(minPosition)); | ||
9873 | result.Add(new LSL_Vector(maxPosition)); | ||
9874 | if (m_addStatsInGetBoundingBox) | ||
9875 | result.Add(new LSL_Vector((float)groupCount, (float)partCount, (float)vertexCount)); | ||
9876 | |||
9877 | primMesher = null; | ||
9878 | return result; | ||
9879 | } | ||
9880 | |||
9881 | /// <summary> | ||
9882 | /// Helper to calculate bounding box of an avatar. | ||
9883 | /// </summary> | ||
9884 | private void BoundingBoxOfScenePresence(ScenePresence sp, out Vector3 lower, out Vector3 upper) | ||
9885 | { | ||
9886 | // Adjust from OS model | ||
9887 | // avatar height = visual height - 0.2, bounding box height = visual height | ||
9888 | // to SL model | ||
9889 | // avatar height = visual height, bounding box height = visual height + 0.2 | ||
9890 | float height = sp.Appearance.AvatarHeight + m_avatarHeightCorrection; | ||
9891 | |||
9892 | // According to avatar bounding box in SL 2015-04-18: | ||
9893 | // standing = <-0.275,-0.35,-0.1-0.5*h> : <0.275,0.35,0.1+0.5*h> | ||
9894 | // groundsitting = <-0.3875,-0.5,-0.05-0.375*h> : <0.3875,0.5,0.5> | ||
9895 | // sitting = <-0.5875,-0.35,-0.35-0.375*h> : <0.1875,0.35,-0.25+0.25*h> | ||
9896 | |||
9897 | // When avatar is sitting | ||
9898 | if (sp.ParentPart != null) | ||
9899 | { | ||
9900 | lower = new Vector3(m_lABB1SitX0, m_lABB1SitY0, m_lABB1SitZ0 + m_lABB1SitZ1 * height); | ||
9901 | upper = new Vector3(m_lABB2SitX0, m_lABB2SitY0, m_lABB2SitZ0 + m_lABB2SitZ1 * height); | ||
9639 | } | 9902 | } |
9640 | SceneObjectPart part = World.GetSceneObjectPart(objID); | 9903 | // When avatar is groundsitting |
9641 | // Currently only works for single prims without a sitting avatar | 9904 | else if (sp.Animator.Animations.ImplicitDefaultAnimation.AnimID == DefaultAvatarAnimations.AnimsUUID["SIT_GROUND_CONSTRAINED"]) |
9642 | if (part != null) | ||
9643 | { | 9905 | { |
9644 | Vector3 halfSize = part.Scale / 2.0f; | 9906 | lower = new Vector3(m_lABB1GrsX0, m_lABB1GrsY0, m_lABB1GrsZ0 + m_lABB1GrsZ1 * height); |
9645 | LSL_Vector lower = (new LSL_Vector(halfSize)) * -1.0f; | 9907 | upper = new Vector3(m_lABB2GrsX0, m_lABB2GrsY0, m_lABB2GrsZ0 + m_lABB2GrsZ1 * height); |
9646 | LSL_Vector upper = new LSL_Vector(halfSize); | ||
9647 | result.Add(lower); | ||
9648 | result.Add(upper); | ||
9649 | return result; | ||
9650 | } | 9908 | } |
9909 | // When avatar is standing or flying | ||
9910 | else | ||
9911 | { | ||
9912 | lower = new Vector3(m_lABB1StdX0, m_lABB1StdY0, m_lABB1StdZ0 + m_lABB1StdZ1 * height); | ||
9913 | upper = new Vector3(m_lABB2StdX0, m_lABB2StdY0, m_lABB2StdZ0 + m_lABB2StdZ1 * height); | ||
9914 | } | ||
9915 | } | ||
9651 | 9916 | ||
9652 | // Not found so return empty values | 9917 | /// <summary> |
9653 | result.Add(new LSL_Vector()); | 9918 | /// Helper to approximate a part with a simple box. |
9654 | result.Add(new LSL_Vector()); | 9919 | /// </summary> |
9655 | return result; | 9920 | private void AddBoundingBoxOfSimpleBox(Vector3 corner1, Vector3 corner2, Vector3 offset, Quaternion rotation, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) |
9921 | { | ||
9922 | // Parse the 8 box corners | ||
9923 | for (int i = 0; i < 8; i++) | ||
9924 | { | ||
9925 | // Calculate each box corner | ||
9926 | Vector3 position = corner1; | ||
9927 | if ((i & 1) != 0) | ||
9928 | position.X = corner2.X; | ||
9929 | if ((i & 2) != 0) | ||
9930 | position.Y = corner2.Y; | ||
9931 | if ((i & 4) != 0) | ||
9932 | position.Z = corner2.Z; | ||
9933 | // Rotate part unless part is root | ||
9934 | if (hasParent) | ||
9935 | position = position * rotation; | ||
9936 | position = position + offset; | ||
9937 | // Adjust lower and upper bounding box corners if needed | ||
9938 | lower = Vector3.Min(lower, position); | ||
9939 | upper = Vector3.Max(upper, position); | ||
9940 | count++; | ||
9941 | } | ||
9656 | } | 9942 | } |
9657 | 9943 | ||
9944 | /// <summary> | ||
9945 | /// Helper to parse a meshed prim and needed especially | ||
9946 | /// for accuracy with tortured prims and sculpts. | ||
9947 | /// </summary> | ||
9948 | private void AddBoundingBoxOfSimpleMesh(SimpleMesh mesh, Primitive prim, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) | ||
9949 | { | ||
9950 | // Quirk: A meshed box contains 10 instead of the 8 necessary vertices. | ||
9951 | if (mesh != null) | ||
9952 | { | ||
9953 | // Parse each vertex in mesh | ||
9954 | foreach (Vertex vertex in mesh.Vertices) | ||
9955 | { | ||
9956 | Vector3 position = vertex.Position; | ||
9957 | position = position * prim.Scale; | ||
9958 | // Rotate part unless part is root | ||
9959 | if (hasParent) | ||
9960 | position = position * prim.Rotation; | ||
9961 | position = position + prim.Position; | ||
9962 | // Adjust lower and upper bounding box corners if needed | ||
9963 | lower = Vector3.Min(lower, position); | ||
9964 | upper = Vector3.Max(upper, position); | ||
9965 | count++; | ||
9966 | } | ||
9967 | } | ||
9968 | } | ||
9969 | |||
9970 | /// <summary> | ||
9971 | /// Helper to parse mesh because no method exists | ||
9972 | /// to parse mesh assets to SimpleMesh. | ||
9973 | /// </summary> | ||
9974 | private void AddBoundingBoxOfFacetedMesh(FacetedMesh mesh, Primitive prim, bool hasParent, ref Vector3 lower, ref Vector3 upper, ref int count) | ||
9975 | { | ||
9976 | if (mesh != null) | ||
9977 | { | ||
9978 | // Parse each face in mesh | ||
9979 | // since vertex array isn't populated. | ||
9980 | // This parses each unique vertex 3-6 times. | ||
9981 | foreach (Face face in mesh.Faces) | ||
9982 | { | ||
9983 | // Parse each vertex in face | ||
9984 | foreach (Vertex vertex in face.Vertices) | ||
9985 | { | ||
9986 | Vector3 position = vertex.Position; | ||
9987 | position = position * prim.Scale; | ||
9988 | // Rotate part unless part is root | ||
9989 | if (hasParent) | ||
9990 | position = position * prim.Rotation; | ||
9991 | position = position + prim.Position; | ||
9992 | // Adjust lower and upper bounding box corners if needed | ||
9993 | lower = Vector3.Min(lower, position); | ||
9994 | upper = Vector3.Max(upper, position); | ||
9995 | count++; | ||
9996 | } | ||
9997 | } | ||
9998 | } | ||
9999 | } | ||
10000 | |||
10001 | /// <summary> | ||
10002 | /// Helper to make up an OpenMetaverse prim | ||
10003 | /// needed to create mesh from parts. | ||
10004 | /// </summary> | ||
10005 | private Primitive MakeOpenMetaversePrim(Vector3 scale, Vector3 position, Quaternion rotation, int primType) | ||
10006 | { | ||
10007 | // Initialize and set common parameters | ||
10008 | Primitive prim = new OpenMetaverse.Primitive(); | ||
10009 | prim.Scale = scale; | ||
10010 | prim.Position = position; | ||
10011 | prim.Rotation = rotation; | ||
10012 | prim.PrimData.PathShearX = 0.0f; | ||
10013 | prim.PrimData.PathShearY = 0.0f; | ||
10014 | prim.PrimData.PathBegin = 0.0f; | ||
10015 | prim.PrimData.PathEnd = 1.0f; | ||
10016 | prim.PrimData.PathScaleX = 1.0f; | ||
10017 | prim.PrimData.PathScaleY = 1.0f; | ||
10018 | prim.PrimData.PathTaperX = 0.0f; | ||
10019 | prim.PrimData.PathTaperY = 0.0f; | ||
10020 | prim.PrimData.PathTwistBegin = 0.0f; | ||
10021 | prim.PrimData.PathTwist = 0.0f; | ||
10022 | prim.PrimData.ProfileBegin = 0.0f; | ||
10023 | prim.PrimData.ProfileEnd = 1.0f; | ||
10024 | prim.PrimData.ProfileHollow = 0.0f; | ||
10025 | prim.PrimData.ProfileCurve = (ProfileCurve)1; | ||
10026 | prim.PrimData.ProfileHole = (HoleType)0; | ||
10027 | prim.PrimData.PathCurve = (PathCurve)16; | ||
10028 | prim.PrimData.PathRadiusOffset = 0.0f; | ||
10029 | prim.PrimData.PathRevolutions = 1.0f; | ||
10030 | prim.PrimData.PathSkew = 0.0f; | ||
10031 | prim.PrimData.PCode = OpenMetaverse.PCode.Prim; | ||
10032 | prim.PrimData.State = (byte)0; | ||
10033 | |||
10034 | // Set type specific parameters | ||
10035 | switch (primType) | ||
10036 | { | ||
10037 | // Set specific parameters for box | ||
10038 | case ScriptBaseClass.PRIM_TYPE_BOX: | ||
10039 | prim.PrimData.PathScaleY = 1.0f; | ||
10040 | prim.PrimData.ProfileCurve = (ProfileCurve)1; | ||
10041 | prim.PrimData.PathCurve = (PathCurve)16; | ||
10042 | break; | ||
10043 | // Set specific parameters for cylinder | ||
10044 | case ScriptBaseClass.PRIM_TYPE_CYLINDER: | ||
10045 | prim.PrimData.PathScaleY = 1.0f; | ||
10046 | prim.PrimData.ProfileCurve = (ProfileCurve)0; | ||
10047 | prim.PrimData.PathCurve = (PathCurve)16; | ||
10048 | break; | ||
10049 | // Set specific parameters for prism | ||
10050 | case ScriptBaseClass.PRIM_TYPE_PRISM: | ||
10051 | prim.PrimData.PathScaleY = 1.0f; | ||
10052 | prim.PrimData.ProfileCurve = (ProfileCurve)3; | ||
10053 | prim.PrimData.PathCurve = (PathCurve)16; | ||
10054 | break; | ||
10055 | // Set specific parameters for sphere | ||
10056 | case ScriptBaseClass.PRIM_TYPE_SPHERE: | ||
10057 | prim.PrimData.PathScaleY = 1.0f; | ||
10058 | prim.PrimData.ProfileCurve = (ProfileCurve)5; | ||
10059 | prim.PrimData.PathCurve = (PathCurve)32; | ||
10060 | break; | ||
10061 | // Set specific parameters for torus | ||
10062 | case ScriptBaseClass.PRIM_TYPE_TORUS: | ||
10063 | prim.PrimData.PathScaleY = 0.5f; | ||
10064 | prim.PrimData.ProfileCurve = (ProfileCurve)0; | ||
10065 | prim.PrimData.PathCurve = (PathCurve)32; | ||
10066 | break; | ||
10067 | // Set specific parameters for tube | ||
10068 | case ScriptBaseClass.PRIM_TYPE_TUBE: | ||
10069 | prim.PrimData.PathScaleY = 0.5f; | ||
10070 | prim.PrimData.ProfileCurve = (ProfileCurve)1; | ||
10071 | prim.PrimData.PathCurve = (PathCurve)32; | ||
10072 | break; | ||
10073 | // Set specific parameters for ring | ||
10074 | case ScriptBaseClass.PRIM_TYPE_RING: | ||
10075 | prim.PrimData.PathScaleY = 0.5f; | ||
10076 | prim.PrimData.ProfileCurve = (ProfileCurve)3; | ||
10077 | prim.PrimData.PathCurve = (PathCurve)32; | ||
10078 | break; | ||
10079 | // Set specific parameters for sculpt | ||
10080 | case ScriptBaseClass.PRIM_TYPE_SCULPT: | ||
10081 | prim.PrimData.PathScaleY = 1.0f; | ||
10082 | prim.PrimData.ProfileCurve = (ProfileCurve)5; | ||
10083 | prim.PrimData.PathCurve = (PathCurve)32; | ||
10084 | break; | ||
10085 | // Default to specific parameters for box | ||
10086 | default: | ||
10087 | prim.PrimData.PathScaleY = 1.0f; | ||
10088 | prim.PrimData.ProfileCurve = (ProfileCurve)1; | ||
10089 | prim.PrimData.PathCurve = (PathCurve)16; | ||
10090 | break; | ||
10091 | } | ||
10092 | |||
10093 | return prim; | ||
10094 | } | ||
10095 | |||
10096 | /// <summary> | ||
10097 | /// Implementation of llGetGeometricCenter according to SL 2015-04-30. | ||
10098 | /// http://wiki.secondlife.com/wiki/LlGetGeometricCenter | ||
10099 | /// Returns the average position offset of all linked parts, | ||
10100 | /// including the root prim and seated avatars, | ||
10101 | /// relative to the root prim in local coordinates. | ||
10102 | /// </summary> | ||
9658 | public LSL_Vector llGetGeometricCenter() | 10103 | public LSL_Vector llGetGeometricCenter() |
9659 | { | 10104 | { |
9660 | return new LSL_Vector(m_host.GetGeometricCenter()); | 10105 | // Subtract whatever position the root prim has to make it zero |
10106 | Vector3 offset = m_host.ParentGroup.RootPart.OffsetPosition * -1.0f; | ||
10107 | |||
10108 | // Add all prim/part position offsets | ||
10109 | foreach (SceneObjectPart part in m_host.ParentGroup.Parts) | ||
10110 | offset = offset + part.OffsetPosition; | ||
10111 | // Add all avatar/scene presence position offsets | ||
10112 | foreach (ScenePresence sp in m_host.ParentGroup.GetSittingAvatars()) | ||
10113 | offset = offset + sp.OffsetPosition; | ||
10114 | |||
10115 | // Calculate and return the average offset | ||
10116 | offset = offset / (float)(m_host.ParentGroup.PrimCount + m_host.ParentGroup.GetSittingAvatarsCount()); | ||
10117 | return new LSL_Vector(offset); | ||
9661 | } | 10118 | } |
9662 | 10119 | ||
9663 | public LSL_List GetEntityParams(ISceneEntity entity, LSL_List rules) | 10120 | public LSL_List GetEntityParams(ISceneEntity entity, LSL_List rules) |
@@ -12600,6 +13057,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
12600 | case ScriptBaseClass.OBJECT_TEMP_ON_REZ: | 13057 | case ScriptBaseClass.OBJECT_TEMP_ON_REZ: |
12601 | ret.Add(new LSL_Integer(0)); | 13058 | ret.Add(new LSL_Integer(0)); |
12602 | break; | 13059 | break; |
13060 | case ScriptBaseClass.OBJECT_RENDER_WEIGHT: | ||
13061 | ret.Add(new LSL_Integer(-1)); | ||
13062 | break; | ||
13063 | case ScriptBaseClass.OBJECT_HOVER_HEIGHT: | ||
13064 | ret.Add(new LSL_Float(0)); | ||
13065 | break; | ||
13066 | case ScriptBaseClass.OBJECT_BODY_SHAPE_TYPE: | ||
13067 | LSL_Float shapeType; | ||
13068 | if (av.Appearance.VisualParams[(int)AvatarAppearance.VPElement.SHAPE_MALE] != 0) | ||
13069 | shapeType = new LSL_Float(1); | ||
13070 | else | ||
13071 | shapeType = new LSL_Float(0); | ||
13072 | ret.Add(shapeType); | ||
13073 | break; | ||
13074 | case ScriptBaseClass.OBJECT_LAST_OWNER_ID: | ||
13075 | ret.Add(new LSL_Key(ScriptBaseClass.NULL_KEY)); | ||
13076 | break; | ||
12603 | default: | 13077 | default: |
12604 | // Invalid or unhandled constant. | 13078 | // Invalid or unhandled constant. |
12605 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); | 13079 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); |
@@ -12764,6 +13238,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
12764 | case ScriptBaseClass.OBJECT_TEMP_ON_REZ: | 13238 | case ScriptBaseClass.OBJECT_TEMP_ON_REZ: |
12765 | ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0)); | 13239 | ret.Add(new LSL_Integer(obj.ParentGroup.IsTemporary ? 1 : 0)); |
12766 | break; | 13240 | break; |
13241 | case ScriptBaseClass.OBJECT_RENDER_WEIGHT: | ||
13242 | ret.Add(new LSL_Integer(0)); | ||
13243 | break; | ||
13244 | case ScriptBaseClass.OBJECT_HOVER_HEIGHT: | ||
13245 | ret.Add(new LSL_Float(0)); | ||
13246 | break; | ||
13247 | case ScriptBaseClass.OBJECT_BODY_SHAPE_TYPE: | ||
13248 | ret.Add(new LSL_Float(-1)); | ||
13249 | break; | ||
13250 | case ScriptBaseClass.OBJECT_LAST_OWNER_ID: | ||
13251 | ret.Add(new LSL_Key(obj.ParentGroup.LastOwnerID.ToString())); | ||
13252 | break; | ||
12767 | default: | 13253 | default: |
12768 | // Invalid or unhandled constant. | 13254 | // Invalid or unhandled constant. |
12769 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); | 13255 | ret.Add(new LSL_Integer(ScriptBaseClass.OBJECT_UNKNOWN_DETAIL)); |
@@ -13335,6 +13821,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
13335 | 13821 | ||
13336 | public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) | 13822 | public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) |
13337 | { | 13823 | { |
13824 | // Use llCastRay V3 if configured | ||
13825 | if (m_useCastRayV3) | ||
13826 | return llCastRayV3(start, end, options); | ||
13827 | |||
13338 | LSL_List list = new LSL_List(); | 13828 | LSL_List list = new LSL_List(); |
13339 | 13829 | ||
13340 | m_host.AddScriptLPS(1); | 13830 | m_host.AddScriptLPS(1); |
@@ -13524,6 +14014,732 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
13524 | return list; | 14014 | return list; |
13525 | } | 14015 | } |
13526 | 14016 | ||
14017 | /// <summary> | ||
14018 | /// Implementation of llCastRay similar to SL 2015-04-21. | ||
14019 | /// http://wiki.secondlife.com/wiki/LlCastRay | ||
14020 | /// Uses pure geometry, bounding shapes, meshing and no physics | ||
14021 | /// for prims, sculpts, meshes, avatars and terrain. | ||
14022 | /// Implements all flags, reject types and data flags. | ||
14023 | /// Can handle both objects/groups and prims/parts, by config. | ||
14024 | /// May sometimes be inaccurate owing to calculation precision, | ||
14025 | /// meshing detail level and a bug in libopenmetaverse PrimMesher. | ||
14026 | /// </summary> | ||
14027 | public LSL_List llCastRayV3(LSL_Vector start, LSL_Vector end, LSL_List options) | ||
14028 | { | ||
14029 | // Initialize | ||
14030 | m_host.AddScriptLPS(1); | ||
14031 | List<RayHit> rayHits = new List<RayHit>(); | ||
14032 | LSL_List result = new LSL_List(); | ||
14033 | float tol = m_floatToleranceInCastRay; | ||
14034 | Vector3 pos1Ray = start; | ||
14035 | Vector3 pos2Ray = end; | ||
14036 | |||
14037 | // Get input options | ||
14038 | int rejectTypes = 0; | ||
14039 | int dataFlags = 0; | ||
14040 | int maxHits = 1; | ||
14041 | bool detectPhantom = false; | ||
14042 | for (int i = 0; i < options.Length; i += 2) | ||
14043 | { | ||
14044 | if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_REJECT_TYPES) | ||
14045 | rejectTypes = options.GetLSLIntegerItem(i + 1); | ||
14046 | else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DATA_FLAGS) | ||
14047 | dataFlags = options.GetLSLIntegerItem(i + 1); | ||
14048 | else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_MAX_HITS) | ||
14049 | maxHits = options.GetLSLIntegerItem(i + 1); | ||
14050 | else if (options.GetLSLIntegerItem(i) == ScriptBaseClass.RC_DETECT_PHANTOM) | ||
14051 | detectPhantom = (options.GetLSLIntegerItem(i + 1) != 0); | ||
14052 | } | ||
14053 | if (maxHits > m_maxHitsInCastRay) | ||
14054 | maxHits = m_maxHitsInCastRay; | ||
14055 | bool rejectAgents = ((rejectTypes & ScriptBaseClass.RC_REJECT_AGENTS) != 0); | ||
14056 | bool rejectPhysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_PHYSICAL) != 0); | ||
14057 | bool rejectNonphysical = ((rejectTypes & ScriptBaseClass.RC_REJECT_NONPHYSICAL) != 0); | ||
14058 | bool rejectLand = ((rejectTypes & ScriptBaseClass.RC_REJECT_LAND) != 0); | ||
14059 | bool getNormal = ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) != 0); | ||
14060 | bool getRootKey = ((dataFlags & ScriptBaseClass.RC_GET_ROOT_KEY) != 0); | ||
14061 | bool getLinkNum = ((dataFlags & ScriptBaseClass.RC_GET_LINK_NUM) != 0); | ||
14062 | |||
14063 | // Calculate some basic parameters | ||
14064 | Vector3 vecRay = pos2Ray - pos1Ray; | ||
14065 | float rayLength = vecRay.Length(); | ||
14066 | |||
14067 | // Try to get a mesher and return failure if none, degenerate ray, or max 0 hits | ||
14068 | IRendering primMesher = null; | ||
14069 | List<string> renderers = RenderingLoader.ListRenderers(Util.ExecutingDirectory()); | ||
14070 | if (renderers.Count < 1 || rayLength < tol || m_maxHitsInCastRay < 1) | ||
14071 | { | ||
14072 | result.Add(new LSL_Integer(ScriptBaseClass.RCERR_UNKNOWN)); | ||
14073 | return result; | ||
14074 | } | ||
14075 | primMesher = RenderingLoader.LoadRenderer(renderers[0]); | ||
14076 | |||
14077 | // Iterate over all objects/groups and prims/parts in region | ||
14078 | World.ForEachSOG( | ||
14079 | delegate(SceneObjectGroup group) | ||
14080 | { | ||
14081 | // Check group filters unless part filters are configured | ||
14082 | bool isPhysical = (group.RootPart != null && group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical); | ||
14083 | bool isNonphysical = !isPhysical; | ||
14084 | bool isPhantom = group.IsPhantom || group.IsVolumeDetect; | ||
14085 | bool isAttachment = group.IsAttachment; | ||
14086 | bool doGroup = true; | ||
14087 | if (isPhysical && rejectPhysical) | ||
14088 | doGroup = false; | ||
14089 | if (isNonphysical && rejectNonphysical) | ||
14090 | doGroup = false; | ||
14091 | if (isPhantom && detectPhantom) | ||
14092 | doGroup = true; | ||
14093 | if (m_filterPartsInCastRay) | ||
14094 | doGroup = true; | ||
14095 | if (isAttachment && !m_doAttachmentsInCastRay) | ||
14096 | doGroup = false; | ||
14097 | // Parse object/group if passed filters | ||
14098 | if (doGroup) | ||
14099 | { | ||
14100 | // Iterate over all prims/parts in object/group | ||
14101 | foreach(SceneObjectPart part in group.Parts) | ||
14102 | { | ||
14103 | // Check part filters if configured | ||
14104 | if (m_filterPartsInCastRay) | ||
14105 | { | ||
14106 | isPhysical = (part.PhysActor != null && part.PhysActor.IsPhysical); | ||
14107 | isNonphysical = !isPhysical; | ||
14108 | isPhantom = ((part.Flags & PrimFlags.Phantom) != 0) || (part.VolumeDetectActive); | ||
14109 | bool doPart = true; | ||
14110 | if (isPhysical && rejectPhysical) | ||
14111 | doPart = false; | ||
14112 | if (isNonphysical && rejectNonphysical) | ||
14113 | doPart = false; | ||
14114 | if (isPhantom && detectPhantom) | ||
14115 | doPart = true; | ||
14116 | if (!doPart) | ||
14117 | continue; | ||
14118 | } | ||
14119 | |||
14120 | // Parse prim/part and project ray if passed filters | ||
14121 | Vector3 scalePart = part.Scale; | ||
14122 | Vector3 posPart = part.GetWorldPosition(); | ||
14123 | Quaternion rotPart = part.GetWorldRotation(); | ||
14124 | Quaternion rotPartInv = Quaternion.Inverse(rotPart); | ||
14125 | Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; | ||
14126 | Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; | ||
14127 | |||
14128 | // Filter parts by shape bounding boxes | ||
14129 | Vector3 shapeBoxMax = new Vector3(0.5f, 0.5f, 0.5f); | ||
14130 | if (!part.Shape.SculptEntry) | ||
14131 | shapeBoxMax = shapeBoxMax * (new Vector3(m_primSafetyCoeffX, m_primSafetyCoeffY, m_primSafetyCoeffZ)); | ||
14132 | shapeBoxMax = shapeBoxMax + (new Vector3(tol, tol, tol)); | ||
14133 | if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) | ||
14134 | { | ||
14135 | // Prepare data needed to check for ray hits | ||
14136 | RayTrans rayTrans = new RayTrans(); | ||
14137 | rayTrans.PartId = part.UUID; | ||
14138 | rayTrans.GroupId = part.ParentGroup.UUID; | ||
14139 | rayTrans.Link = group.PrimCount > 1 ? part.LinkNum : 0; | ||
14140 | rayTrans.ScalePart = scalePart; | ||
14141 | rayTrans.PositionPart = posPart; | ||
14142 | rayTrans.RotationPart = rotPart; | ||
14143 | rayTrans.ShapeNeedsEnds = true; | ||
14144 | rayTrans.Position1Ray = pos1Ray; | ||
14145 | rayTrans.Position1RayProj = pos1RayProj; | ||
14146 | rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; | ||
14147 | |||
14148 | // Make an OMV prim to be able to mesh part | ||
14149 | Primitive omvPrim = part.Shape.ToOmvPrimitive(posPart, rotPart); | ||
14150 | byte[] sculptAsset = null; | ||
14151 | if (omvPrim.Sculpt != null) | ||
14152 | sculptAsset = World.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString()); | ||
14153 | FacetedMesh mesh = null; | ||
14154 | |||
14155 | // When part is mesh, get mesh and check for hits | ||
14156 | if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type == SculptType.Mesh && sculptAsset != null) | ||
14157 | { | ||
14158 | AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset); | ||
14159 | FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, m_meshLodInCastRay, out mesh); | ||
14160 | meshAsset = null; | ||
14161 | } | ||
14162 | |||
14163 | // When part is sculpt, create mesh and check for hits | ||
14164 | // Quirk: Generated sculpt mesh is about 2.8% smaller in X and Y than visual sculpt. | ||
14165 | else if (omvPrim.Sculpt != null && omvPrim.Sculpt.Type != SculptType.Mesh && sculptAsset != null) | ||
14166 | { | ||
14167 | IJ2KDecoder imgDecoder = World.RequestModuleInterface<IJ2KDecoder>(); | ||
14168 | if (imgDecoder != null) | ||
14169 | { | ||
14170 | Image sculpt = imgDecoder.DecodeToImage(sculptAsset); | ||
14171 | if (sculpt != null) | ||
14172 | { | ||
14173 | mesh = primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt, m_sculptLodInCastRay); | ||
14174 | sculpt.Dispose(); | ||
14175 | } | ||
14176 | } | ||
14177 | } | ||
14178 | |||
14179 | // When part is prim, create mesh and check for hits | ||
14180 | else if (omvPrim.Sculpt == null) | ||
14181 | { | ||
14182 | if ( | ||
14183 | omvPrim.PrimData.PathBegin == 0.0 && omvPrim.PrimData.PathEnd == 1.0 && | ||
14184 | omvPrim.PrimData.PathTaperX == 0.0 && omvPrim.PrimData.PathTaperY == 0.0 && | ||
14185 | omvPrim.PrimData.PathSkew == 0.0 && | ||
14186 | omvPrim.PrimData.PathTwist - omvPrim.PrimData.PathTwistBegin == 0.0 | ||
14187 | ) | ||
14188 | rayTrans.ShapeNeedsEnds = false; | ||
14189 | mesh = primMesher.GenerateFacetedMesh(omvPrim, m_primLodInCastRay); | ||
14190 | } | ||
14191 | |||
14192 | // Check mesh for ray hits | ||
14193 | AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); | ||
14194 | mesh = null; | ||
14195 | } | ||
14196 | } | ||
14197 | } | ||
14198 | } | ||
14199 | ); | ||
14200 | |||
14201 | // Check avatar filter | ||
14202 | if (!rejectAgents) | ||
14203 | { | ||
14204 | // Iterate over all avatars in region | ||
14205 | World.ForEachRootScenePresence( | ||
14206 | delegate (ScenePresence sp) | ||
14207 | { | ||
14208 | // Get bounding box | ||
14209 | Vector3 lower; | ||
14210 | Vector3 upper; | ||
14211 | BoundingBoxOfScenePresence(sp, out lower, out upper); | ||
14212 | // Parse avatar | ||
14213 | Vector3 scalePart = upper - lower; | ||
14214 | Vector3 posPart = sp.AbsolutePosition; | ||
14215 | Quaternion rotPart = sp.GetWorldRotation(); | ||
14216 | Quaternion rotPartInv = Quaternion.Inverse(rotPart); | ||
14217 | posPart = posPart + (lower + upper) * 0.5f * rotPart; | ||
14218 | // Project ray | ||
14219 | Vector3 pos1RayProj = ((pos1Ray - posPart) * rotPartInv) / scalePart; | ||
14220 | Vector3 pos2RayProj = ((pos2Ray - posPart) * rotPartInv) / scalePart; | ||
14221 | |||
14222 | // Filter avatars by shape bounding boxes | ||
14223 | Vector3 shapeBoxMax = new Vector3(0.5f + tol, 0.5f + tol, 0.5f + tol); | ||
14224 | if (RayIntersectsShapeBox(pos1RayProj, pos2RayProj, shapeBoxMax)) | ||
14225 | { | ||
14226 | // Prepare data needed to check for ray hits | ||
14227 | RayTrans rayTrans = new RayTrans(); | ||
14228 | rayTrans.PartId = sp.UUID; | ||
14229 | rayTrans.GroupId = sp.ParentPart != null ? sp.ParentPart.ParentGroup.UUID : sp.UUID; | ||
14230 | rayTrans.Link = sp.ParentPart != null ? UUID2LinkNumber(sp.ParentPart, sp.UUID) : 0; | ||
14231 | rayTrans.ScalePart = scalePart; | ||
14232 | rayTrans.PositionPart = posPart; | ||
14233 | rayTrans.RotationPart = rotPart; | ||
14234 | rayTrans.ShapeNeedsEnds = false; | ||
14235 | rayTrans.Position1Ray = pos1Ray; | ||
14236 | rayTrans.Position1RayProj = pos1RayProj; | ||
14237 | rayTrans.VectorRayProj = pos2RayProj - pos1RayProj; | ||
14238 | |||
14239 | // Make OMV prim, create and check mesh | ||
14240 | PrimitiveBaseShape prim = PrimitiveBaseShape.CreateSphere(); | ||
14241 | prim.Scale = scalePart; | ||
14242 | Primitive omvPrim = prim.ToOmvPrimitive(posPart, rotPart); | ||
14243 | FacetedMesh mesh = primMesher.GenerateFacetedMesh(omvPrim, m_meshLodInCastRay); | ||
14244 | AddRayInFacetedMesh(mesh, rayTrans, ref rayHits); | ||
14245 | mesh = null; | ||
14246 | } | ||
14247 | } | ||
14248 | ); | ||
14249 | } | ||
14250 | |||
14251 | // Check terrain filter | ||
14252 | if (!rejectLand) | ||
14253 | { | ||
14254 | // Parse terrain | ||
14255 | |||
14256 | // Mesh terrain and check bounding box | ||
14257 | Vector3 lower; | ||
14258 | Vector3 upper; | ||
14259 | List<Tri> triangles = TrisFromHeightmapUnderRay(pos1Ray, pos2Ray, out lower, out upper); | ||
14260 | lower.Z -= tol; | ||
14261 | upper.Z += tol; | ||
14262 | if ((pos1Ray.Z >= lower.Z || pos2Ray.Z >= lower.Z) && (pos1Ray.Z <= upper.Z || pos2Ray.Z <= upper.Z)) | ||
14263 | { | ||
14264 | // Prepare data needed to check for ray hits | ||
14265 | RayTrans rayTrans = new RayTrans(); | ||
14266 | rayTrans.PartId = UUID.Zero; | ||
14267 | rayTrans.GroupId = UUID.Zero; | ||
14268 | rayTrans.Link = 0; | ||
14269 | rayTrans.ScalePart = new Vector3 (1.0f, 1.0f, 1.0f); | ||
14270 | rayTrans.PositionPart = Vector3.Zero; | ||
14271 | rayTrans.RotationPart = Quaternion.Identity; | ||
14272 | rayTrans.ShapeNeedsEnds = true; | ||
14273 | rayTrans.Position1Ray = pos1Ray; | ||
14274 | rayTrans.Position1RayProj = pos1Ray; | ||
14275 | rayTrans.VectorRayProj = vecRay; | ||
14276 | |||
14277 | // Check mesh | ||
14278 | AddRayInTris(triangles, rayTrans, ref rayHits); | ||
14279 | triangles = null; | ||
14280 | } | ||
14281 | } | ||
14282 | |||
14283 | // Sort hits by ascending distance | ||
14284 | rayHits.Sort((s1, s2) => s1.Distance.CompareTo(s2.Distance)); | ||
14285 | |||
14286 | // Check excess hits per part and group | ||
14287 | for (int t = 0; t < 2; t++) | ||
14288 | { | ||
14289 | int maxHitsPerType = 0; | ||
14290 | UUID id = UUID.Zero; | ||
14291 | if (t == 0) | ||
14292 | maxHitsPerType = m_maxHitsPerPrimInCastRay; | ||
14293 | else | ||
14294 | maxHitsPerType = m_maxHitsPerObjectInCastRay; | ||
14295 | |||
14296 | // Handle excess hits only when needed | ||
14297 | if (maxHitsPerType < m_maxHitsInCastRay) | ||
14298 | { | ||
14299 | // Find excess hits | ||
14300 | Hashtable hits = new Hashtable(); | ||
14301 | for (int i = rayHits.Count - 1; i >= 0; i--) | ||
14302 | { | ||
14303 | if (t == 0) | ||
14304 | id = rayHits[i].PartId; | ||
14305 | else | ||
14306 | id = rayHits[i].GroupId; | ||
14307 | if (hits.ContainsKey(id)) | ||
14308 | hits[id] = (int)hits[id] + 1; | ||
14309 | else | ||
14310 | hits[id] = 1; | ||
14311 | } | ||
14312 | |||
14313 | // Remove excess hits | ||
14314 | for (int i = rayHits.Count - 1; i >= 0; i--) | ||
14315 | { | ||
14316 | if (t == 0) | ||
14317 | id = rayHits[i].PartId; | ||
14318 | else | ||
14319 | id = rayHits[i].GroupId; | ||
14320 | int hit = (int)hits[id]; | ||
14321 | if (hit > m_maxHitsPerPrimInCastRay) | ||
14322 | { | ||
14323 | rayHits.RemoveAt(i); | ||
14324 | hit--; | ||
14325 | hits[id] = hit; | ||
14326 | } | ||
14327 | } | ||
14328 | } | ||
14329 | } | ||
14330 | |||
14331 | // Parse hits into result list according to data flags | ||
14332 | int hitCount = rayHits.Count; | ||
14333 | if (hitCount > maxHits) | ||
14334 | hitCount = maxHits; | ||
14335 | for (int i = 0; i < hitCount; i++) | ||
14336 | { | ||
14337 | RayHit rayHit = rayHits[i]; | ||
14338 | if (getRootKey) | ||
14339 | result.Add(new LSL_Key(rayHit.GroupId.ToString())); | ||
14340 | else | ||
14341 | result.Add(new LSL_Key(rayHit.PartId.ToString())); | ||
14342 | result.Add(new LSL_Vector(rayHit.Position)); | ||
14343 | if (getLinkNum) | ||
14344 | result.Add(new LSL_Integer(rayHit.Link)); | ||
14345 | if (getNormal) | ||
14346 | result.Add(new LSL_Vector(rayHit.Normal)); | ||
14347 | } | ||
14348 | result.Add(new LSL_Integer(hitCount)); | ||
14349 | return result; | ||
14350 | } | ||
14351 | |||
14352 | /// <summary> | ||
14353 | /// Struct for transmitting parameters required for finding llCastRay ray hits. | ||
14354 | /// </summary> | ||
14355 | public struct RayTrans | ||
14356 | { | ||
14357 | public UUID PartId; | ||
14358 | public UUID GroupId; | ||
14359 | public int Link; | ||
14360 | public Vector3 ScalePart; | ||
14361 | public Vector3 PositionPart; | ||
14362 | public Quaternion RotationPart; | ||
14363 | public bool ShapeNeedsEnds; | ||
14364 | public Vector3 Position1Ray; | ||
14365 | public Vector3 Position1RayProj; | ||
14366 | public Vector3 VectorRayProj; | ||
14367 | } | ||
14368 | |||
14369 | /// <summary> | ||
14370 | /// Struct for llCastRay ray hits. | ||
14371 | /// </summary> | ||
14372 | public struct RayHit | ||
14373 | { | ||
14374 | public UUID PartId; | ||
14375 | public UUID GroupId; | ||
14376 | public int Link; | ||
14377 | public Vector3 Position; | ||
14378 | public Vector3 Normal; | ||
14379 | public float Distance; | ||
14380 | } | ||
14381 | |||
14382 | /// <summary> | ||
14383 | /// Helper to check if a ray intersects a shape bounding box. | ||
14384 | /// </summary> | ||
14385 | private bool RayIntersectsShapeBox(Vector3 pos1RayProj, Vector3 pos2RayProj, Vector3 shapeBoxMax) | ||
14386 | { | ||
14387 | // Skip if ray can't intersect bounding box; | ||
14388 | Vector3 rayBoxProjMin = Vector3.Min(pos1RayProj, pos2RayProj); | ||
14389 | Vector3 rayBoxProjMax = Vector3.Max(pos1RayProj, pos2RayProj); | ||
14390 | if ( | ||
14391 | rayBoxProjMin.X > shapeBoxMax.X || rayBoxProjMin.Y > shapeBoxMax.Y || rayBoxProjMin.Z > shapeBoxMax.Z || | ||
14392 | rayBoxProjMax.X < -shapeBoxMax.X || rayBoxProjMax.Y < -shapeBoxMax.Y || rayBoxProjMax.Z < -shapeBoxMax.Z | ||
14393 | ) | ||
14394 | return false; | ||
14395 | |||
14396 | // Check if ray intersect any bounding box side | ||
14397 | int sign = 0; | ||
14398 | float dist = 0.0f; | ||
14399 | Vector3 posProj = Vector3.Zero; | ||
14400 | Vector3 vecRayProj = pos2RayProj - pos1RayProj; | ||
14401 | |||
14402 | // Check both X sides unless ray is parallell to them | ||
14403 | if (Math.Abs(vecRayProj.X) > m_floatToleranceInCastRay) | ||
14404 | { | ||
14405 | for (sign = -1; sign <= 1; sign += 2) | ||
14406 | { | ||
14407 | dist = ((float)sign * shapeBoxMax.X - pos1RayProj.X) / vecRayProj.X; | ||
14408 | posProj = pos1RayProj + vecRayProj * dist; | ||
14409 | if (Math.Abs(posProj.Y) <= shapeBoxMax.Y && Math.Abs(posProj.Z) <= shapeBoxMax.Z) | ||
14410 | return true; | ||
14411 | } | ||
14412 | } | ||
14413 | |||
14414 | // Check both Y sides unless ray is parallell to them | ||
14415 | if (Math.Abs(vecRayProj.Y) > m_floatToleranceInCastRay) | ||
14416 | { | ||
14417 | for (sign = -1; sign <= 1; sign += 2) | ||
14418 | { | ||
14419 | dist = ((float)sign * shapeBoxMax.Y - pos1RayProj.Y) / vecRayProj.Y; | ||
14420 | posProj = pos1RayProj + vecRayProj * dist; | ||
14421 | if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Z) <= shapeBoxMax.Z) | ||
14422 | return true; | ||
14423 | } | ||
14424 | } | ||
14425 | |||
14426 | // Check both Z sides unless ray is parallell to them | ||
14427 | if (Math.Abs(vecRayProj.Z) > m_floatToleranceInCastRay) | ||
14428 | { | ||
14429 | for (sign = -1; sign <= 1; sign += 2) | ||
14430 | { | ||
14431 | dist = ((float)sign * shapeBoxMax.Z - pos1RayProj.Z) / vecRayProj.Z; | ||
14432 | posProj = pos1RayProj + vecRayProj * dist; | ||
14433 | if (Math.Abs(posProj.X) <= shapeBoxMax.X && Math.Abs(posProj.Y) <= shapeBoxMax.Y) | ||
14434 | return true; | ||
14435 | } | ||
14436 | } | ||
14437 | |||
14438 | // No hits on bounding box so return false | ||
14439 | return false; | ||
14440 | } | ||
14441 | |||
14442 | /// <summary> | ||
14443 | /// Helper to parse FacetedMesh for ray hits. | ||
14444 | /// </summary> | ||
14445 | private void AddRayInFacetedMesh(FacetedMesh mesh, RayTrans rayTrans, ref List<RayHit> rayHits) | ||
14446 | { | ||
14447 | if (mesh != null) | ||
14448 | { | ||
14449 | foreach (Face face in mesh.Faces) | ||
14450 | { | ||
14451 | for (int i = 0; i < face.Indices.Count; i += 3) | ||
14452 | { | ||
14453 | Tri triangle = new Tri(); | ||
14454 | triangle.p1 = face.Vertices[face.Indices[i]].Position; | ||
14455 | triangle.p2 = face.Vertices[face.Indices[i + 1]].Position; | ||
14456 | triangle.p3 = face.Vertices[face.Indices[i + 2]].Position; | ||
14457 | AddRayInTri(triangle, rayTrans, ref rayHits); | ||
14458 | } | ||
14459 | } | ||
14460 | } | ||
14461 | } | ||
14462 | |||
14463 | /// <summary> | ||
14464 | /// Helper to parse Tri (triangle) List for ray hits. | ||
14465 | /// </summary> | ||
14466 | private void AddRayInTris(List<Tri> triangles, RayTrans rayTrans, ref List<RayHit> rayHits) | ||
14467 | { | ||
14468 | foreach (Tri triangle in triangles) | ||
14469 | { | ||
14470 | AddRayInTri(triangle, rayTrans, ref rayHits); | ||
14471 | } | ||
14472 | } | ||
14473 | |||
14474 | /// <summary> | ||
14475 | /// Helper to add ray hit in a Tri (triangle). | ||
14476 | /// </summary> | ||
14477 | private void AddRayInTri(Tri triProj, RayTrans rayTrans, ref List<RayHit> rayHits) | ||
14478 | { | ||
14479 | // Check for hit in triangle | ||
14480 | Vector3 posHitProj; | ||
14481 | Vector3 normalProj; | ||
14482 | if (HitRayInTri(triProj, rayTrans.Position1RayProj, rayTrans.VectorRayProj, out posHitProj, out normalProj)) | ||
14483 | { | ||
14484 | // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) face plane through shape center | ||
14485 | if (Math.Abs(Vector3.Dot(posHitProj, normalProj)) < m_floatToleranceInCastRay && !rayTrans.ShapeNeedsEnds) | ||
14486 | return; | ||
14487 | |||
14488 | // Transform hit and normal to region coordinate system | ||
14489 | Vector3 posHit = rayTrans.PositionPart + (posHitProj * rayTrans.ScalePart) * rayTrans.RotationPart; | ||
14490 | Vector3 normal = Vector3.Normalize((normalProj * rayTrans.ScalePart) * rayTrans.RotationPart); | ||
14491 | |||
14492 | // Remove duplicate hits at triangle intersections | ||
14493 | float distance = Vector3.Distance(rayTrans.Position1Ray, posHit); | ||
14494 | for (int i = rayHits.Count - 1; i >= 0; i--) | ||
14495 | { | ||
14496 | if (rayHits[i].PartId != rayTrans.PartId) | ||
14497 | break; | ||
14498 | if (Math.Abs(rayHits[i].Distance - distance) < m_floatTolerance2InCastRay) | ||
14499 | return; | ||
14500 | } | ||
14501 | |||
14502 | // Build result data set | ||
14503 | RayHit rayHit = new RayHit(); | ||
14504 | rayHit.PartId = rayTrans.PartId; | ||
14505 | rayHit.GroupId = rayTrans.GroupId; | ||
14506 | rayHit.Link = rayTrans.Link; | ||
14507 | rayHit.Position = posHit; | ||
14508 | rayHit.Normal = normal; | ||
14509 | rayHit.Distance = distance; | ||
14510 | rayHits.Add(rayHit); | ||
14511 | } | ||
14512 | } | ||
14513 | |||
14514 | /// <summary> | ||
14515 | /// Helper to find ray hit in triangle | ||
14516 | /// </summary> | ||
14517 | bool HitRayInTri(Tri triProj, Vector3 pos1RayProj, Vector3 vecRayProj, out Vector3 posHitProj, out Vector3 normalProj) | ||
14518 | { | ||
14519 | float tol = m_floatToleranceInCastRay; | ||
14520 | posHitProj = Vector3.Zero; | ||
14521 | |||
14522 | // Calculate triangle edge vectors | ||
14523 | Vector3 vec1Proj = triProj.p2 - triProj.p1; | ||
14524 | Vector3 vec2Proj = triProj.p3 - triProj.p2; | ||
14525 | Vector3 vec3Proj = triProj.p1 - triProj.p3; | ||
14526 | |||
14527 | // Calculate triangle normal | ||
14528 | normalProj = Vector3.Cross(vec1Proj, vec2Proj); | ||
14529 | |||
14530 | // Skip if degenerate triangle or ray parallell with triangle plane | ||
14531 | float divisor = Vector3.Dot(vecRayProj, normalProj); | ||
14532 | if (Math.Abs(divisor) < tol) | ||
14533 | return false; | ||
14534 | |||
14535 | // Skip if exit and not configured to detect | ||
14536 | if (divisor > tol && !m_detectExitsInCastRay) | ||
14537 | return false; | ||
14538 | |||
14539 | // Skip if outside ray ends | ||
14540 | float distanceProj = Vector3.Dot(triProj.p1 - pos1RayProj, normalProj) / divisor; | ||
14541 | if (distanceProj < -tol || distanceProj > 1 + tol) | ||
14542 | return false; | ||
14543 | |||
14544 | // Calculate hit position in triangle | ||
14545 | posHitProj = pos1RayProj + vecRayProj * distanceProj; | ||
14546 | |||
14547 | // Skip if outside triangle bounding box | ||
14548 | Vector3 triProjMin = Vector3.Min(Vector3.Min(triProj.p1, triProj.p2), triProj.p3); | ||
14549 | Vector3 triProjMax = Vector3.Max(Vector3.Max(triProj.p1, triProj.p2), triProj.p3); | ||
14550 | if ( | ||
14551 | posHitProj.X < triProjMin.X - tol || posHitProj.Y < triProjMin.Y - tol || posHitProj.Z < triProjMin.Z - tol || | ||
14552 | posHitProj.X > triProjMax.X + tol || posHitProj.Y > triProjMax.Y + tol || posHitProj.Z > triProjMax.Z + tol | ||
14553 | ) | ||
14554 | return false; | ||
14555 | |||
14556 | // Skip if outside triangle | ||
14557 | if ( | ||
14558 | Vector3.Dot(Vector3.Cross(vec1Proj, normalProj), posHitProj - triProj.p1) > tol || | ||
14559 | Vector3.Dot(Vector3.Cross(vec2Proj, normalProj), posHitProj - triProj.p2) > tol || | ||
14560 | Vector3.Dot(Vector3.Cross(vec3Proj, normalProj), posHitProj - triProj.p3) > tol | ||
14561 | ) | ||
14562 | return false; | ||
14563 | |||
14564 | // Return hit | ||
14565 | return true; | ||
14566 | } | ||
14567 | |||
14568 | /// <summary> | ||
14569 | /// Helper to parse selected parts of HeightMap into a Tri (triangle) List and calculate bounding box. | ||
14570 | /// </summary> | ||
14571 | private List<Tri> TrisFromHeightmapUnderRay(Vector3 posStart, Vector3 posEnd, out Vector3 lower, out Vector3 upper) | ||
14572 | { | ||
14573 | // Get bounding X-Y rectangle of terrain under ray | ||
14574 | lower = Vector3.Min(posStart, posEnd); | ||
14575 | upper = Vector3.Max(posStart, posEnd); | ||
14576 | lower.X = (float)Math.Floor(lower.X); | ||
14577 | lower.Y = (float)Math.Floor(lower.Y); | ||
14578 | float zLower = float.MaxValue; | ||
14579 | upper.X = (float)Math.Ceiling(upper.X); | ||
14580 | upper.Y = (float)Math.Ceiling(upper.Y); | ||
14581 | float zUpper = float.MinValue; | ||
14582 | |||
14583 | // Initialize Tri (triangle) List | ||
14584 | List<Tri> triangles = new List<Tri>(); | ||
14585 | |||
14586 | // Set parsing lane direction to major ray X-Y axis | ||
14587 | Vector3 vec = posEnd - posStart; | ||
14588 | float xAbs = Math.Abs(vec.X); | ||
14589 | float yAbs = Math.Abs(vec.Y); | ||
14590 | bool bigX = true; | ||
14591 | if (yAbs > xAbs) | ||
14592 | { | ||
14593 | bigX = false; | ||
14594 | vec = vec / yAbs; | ||
14595 | } | ||
14596 | else if (xAbs > yAbs || xAbs > 0.0f) | ||
14597 | vec = vec / xAbs; | ||
14598 | else | ||
14599 | vec = new Vector3(1.0f, 1.0f, 0.0f); | ||
14600 | |||
14601 | // Simplify by start parsing in lower end of lane | ||
14602 | if ((bigX && vec.X < 0.0f) || (!bigX && vec.Y < 0.0f)) | ||
14603 | { | ||
14604 | Vector3 posTemp = posStart; | ||
14605 | posStart = posEnd; | ||
14606 | posEnd = posTemp; | ||
14607 | vec = vec * -1.0f; | ||
14608 | } | ||
14609 | |||
14610 | // First 1x1 rectangle under ray | ||
14611 | float xFloorOld = 0.0f; | ||
14612 | float yFloorOld = 0.0f; | ||
14613 | Vector3 pos = posStart; | ||
14614 | float xFloor = (float)Math.Floor(pos.X); | ||
14615 | float yFloor = (float)Math.Floor(pos.Y); | ||
14616 | AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper); | ||
14617 | |||
14618 | // Parse every remaining 1x1 rectangle under ray | ||
14619 | while (pos != posEnd) | ||
14620 | { | ||
14621 | // Next 1x1 rectangle under ray | ||
14622 | xFloorOld = xFloor; | ||
14623 | yFloorOld = yFloor; | ||
14624 | pos = pos + vec; | ||
14625 | |||
14626 | // Clip position to 1x1 rectangle border | ||
14627 | xFloor = (float)Math.Floor(pos.X); | ||
14628 | yFloor = (float)Math.Floor(pos.Y); | ||
14629 | if (bigX && pos.X > xFloor) | ||
14630 | { | ||
14631 | pos.Y -= vec.Y * (pos.X - xFloor); | ||
14632 | pos.X = xFloor; | ||
14633 | } | ||
14634 | else if (!bigX && pos.Y > yFloor) | ||
14635 | { | ||
14636 | pos.X -= vec.X * (pos.Y - yFloor); | ||
14637 | pos.Y = yFloor; | ||
14638 | } | ||
14639 | |||
14640 | // Last 1x1 rectangle under ray | ||
14641 | if ((bigX && pos.X >= posEnd.X) || (!bigX && pos.Y >= posEnd.Y)) | ||
14642 | { | ||
14643 | pos = posEnd; | ||
14644 | xFloor = (float)Math.Floor(pos.X); | ||
14645 | yFloor = (float)Math.Floor(pos.Y); | ||
14646 | } | ||
14647 | |||
14648 | // Add new 1x1 rectangle in lane | ||
14649 | if ((bigX && xFloor != xFloorOld) || (!bigX && yFloor != yFloorOld)) | ||
14650 | AddTrisFromHeightmap(xFloor, yFloor, ref triangles, ref zLower, ref zUpper); | ||
14651 | // Add last 1x1 rectangle in old lane at lane shift | ||
14652 | if (bigX && yFloor != yFloorOld) | ||
14653 | AddTrisFromHeightmap(xFloor, yFloorOld, ref triangles, ref zLower, ref zUpper); | ||
14654 | if (!bigX && xFloor != xFloorOld) | ||
14655 | AddTrisFromHeightmap(xFloorOld, yFloor, ref triangles, ref zLower, ref zUpper); | ||
14656 | } | ||
14657 | |||
14658 | // Finalize bounding box Z | ||
14659 | lower.Z = zLower; | ||
14660 | upper.Z = zUpper; | ||
14661 | |||
14662 | // Done and returning Tri (triangle)List | ||
14663 | return triangles; | ||
14664 | } | ||
14665 | |||
14666 | /// <summary> | ||
14667 | /// Helper to add HeightMap squares into Tri (triangle) List and adjust bounding box. | ||
14668 | /// </summary> | ||
14669 | private void AddTrisFromHeightmap(float xPos, float yPos, ref List<Tri> triangles, ref float zLower, ref float zUpper) | ||
14670 | { | ||
14671 | int xInt = (int)xPos; | ||
14672 | int yInt = (int)yPos; | ||
14673 | |||
14674 | // Corner 1 of 1x1 rectangle | ||
14675 | int x = Util.Clamp<int>(xInt+1, 0, World.Heightmap.Width - 1); | ||
14676 | int y = Util.Clamp<int>(yInt+1, 0, World.Heightmap.Height - 1); | ||
14677 | Vector3 pos1 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||
14678 | // Adjust bounding box | ||
14679 | zLower = Math.Min(zLower, pos1.Z); | ||
14680 | zUpper = Math.Max(zUpper, pos1.Z); | ||
14681 | |||
14682 | // Corner 2 of 1x1 rectangle | ||
14683 | x = Util.Clamp<int>(xInt, 0, World.Heightmap.Width - 1); | ||
14684 | y = Util.Clamp<int>(yInt+1, 0, World.Heightmap.Height - 1); | ||
14685 | Vector3 pos2 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||
14686 | // Adjust bounding box | ||
14687 | zLower = Math.Min(zLower, pos2.Z); | ||
14688 | zUpper = Math.Max(zUpper, pos2.Z); | ||
14689 | |||
14690 | // Corner 3 of 1x1 rectangle | ||
14691 | x = Util.Clamp<int>(xInt, 0, World.Heightmap.Width - 1); | ||
14692 | y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1); | ||
14693 | Vector3 pos3 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||
14694 | // Adjust bounding box | ||
14695 | zLower = Math.Min(zLower, pos3.Z); | ||
14696 | zUpper = Math.Max(zUpper, pos3.Z); | ||
14697 | |||
14698 | // Corner 4 of 1x1 rectangle | ||
14699 | x = Util.Clamp<int>(xInt+1, 0, World.Heightmap.Width - 1); | ||
14700 | y = Util.Clamp<int>(yInt, 0, World.Heightmap.Height - 1); | ||
14701 | Vector3 pos4 = new Vector3(x, y, (float)World.Heightmap[x, y]); | ||
14702 | // Adjust bounding box | ||
14703 | zLower = Math.Min(zLower, pos4.Z); | ||
14704 | zUpper = Math.Max(zUpper, pos4.Z); | ||
14705 | |||
14706 | // Add triangle 1 | ||
14707 | Tri triangle1 = new Tri(); | ||
14708 | triangle1.p1 = pos1; | ||
14709 | triangle1.p2 = pos2; | ||
14710 | triangle1.p3 = pos3; | ||
14711 | triangles.Add(triangle1); | ||
14712 | |||
14713 | // Add triangle 2 | ||
14714 | Tri triangle2 = new Tri(); | ||
14715 | triangle2.p1 = pos3; | ||
14716 | triangle2.p2 = pos4; | ||
14717 | triangle2.p3 = pos1; | ||
14718 | triangles.Add(triangle2); | ||
14719 | } | ||
14720 | |||
14721 | /// <summary> | ||
14722 | /// Helper to get link number for a UUID. | ||
14723 | /// </summary> | ||
14724 | private int UUID2LinkNumber(SceneObjectPart part, UUID id) | ||
14725 | { | ||
14726 | SceneObjectGroup group = part.ParentGroup; | ||
14727 | if (group != null) | ||
14728 | { | ||
14729 | // Parse every link for UUID | ||
14730 | int linkCount = group.PrimCount + group.GetSittingAvatarsCount(); | ||
14731 | for (int link = linkCount; link > 0; link--) | ||
14732 | { | ||
14733 | ISceneEntity entity = GetLinkEntity(part, link); | ||
14734 | // Return link number if UUID match | ||
14735 | if (entity != null && entity.UUID == id) | ||
14736 | return link; | ||
14737 | } | ||
14738 | } | ||
14739 | // Return link number 0 if no links or UUID matches | ||
14740 | return 0; | ||
14741 | } | ||
14742 | |||
13527 | public LSL_Integer llManageEstateAccess(int action, string avatar) | 14743 | public LSL_Integer llManageEstateAccess(int action, string avatar) |
13528 | { | 14744 | { |
13529 | m_host.AddScriptLPS(1); | 14745 | m_host.AddScriptLPS(1); |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs index d02c91c..4708473 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index a96cd16..e37d3af 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs | |||
@@ -596,6 +596,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
596 | public const int OBJECT_PHYSICS = 21; | 596 | public const int OBJECT_PHYSICS = 21; |
597 | public const int OBJECT_PHANTOM = 22; | 597 | public const int OBJECT_PHANTOM = 22; |
598 | public const int OBJECT_TEMP_ON_REZ = 23; | 598 | public const int OBJECT_TEMP_ON_REZ = 23; |
599 | public const int OBJECT_RENDER_WEIGHT = 24; | ||
600 | public const int OBJECT_HOVER_HEIGHT = 25; | ||
601 | public const int OBJECT_BODY_SHAPE_TYPE = 26; | ||
602 | public const int OBJECT_LAST_OWNER_ID = 27; | ||
599 | 603 | ||
600 | // Pathfinding types | 604 | // Pathfinding types |
601 | public const int OPT_OTHER = -1; | 605 | public const int OPT_OTHER = -1; |
diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs index 31acd44..4df09ef 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs index af7ee26..3eaaed0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs index 03612ef..0094af6 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/Properties/AssemblyInfo.cs | |||
@@ -30,7 +30,7 @@ using Mono.Addins; | |||
30 | // Build Number | 30 | // Build Number |
31 | // Revision | 31 | // Revision |
32 | // | 32 | // |
33 | [assembly: AssemblyVersion("0.8.1.*")] | 33 | [assembly: AssemblyVersion("0.8.2.*")] |
34 | 34 | ||
35 | [assembly: Addin("OpenSim.Region.ScriptEngine.XEngine", OpenSim.VersionInfo.VersionNumber)] | 35 | [assembly: Addin("OpenSim.Region.ScriptEngine.XEngine", OpenSim.VersionInfo.VersionNumber)] |
36 | [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] | 36 | [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] |
diff --git a/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs b/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs index 58fa66f..9fac53e 100644 --- a/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/UserStatistics/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.8.1.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||