Merging Opensim upstream before generating patch
commit
140ea04b9d
|
@ -30,7 +30,7 @@ using Mono.Addins;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
[assembly: Addin("OpenSim.Groups", OpenSim.VersionInfo.VersionNumber)]
|
||||
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
|
||||
|
|
|
@ -30,7 +30,7 @@ using Mono.Addins;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
[assembly: Addin("OpenSim.OfflineIM", OpenSim.VersionInfo.VersionNumber)]
|
||||
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
|
||||
|
|
|
@ -63,7 +63,7 @@ using Mono.Addins;
|
|||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("0.7.6.*")]
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
||||
[assembly: Addin("OpenSim.ApplicationPlugins.LoadRegions", OpenSim.VersionInfo.VersionNumber)]
|
||||
[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)]
|
||||
|
|
|
@ -30,7 +30,7 @@ using Mono.Addins;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
[assembly: Addin("OpenSim.ApplicationPlugins.RegionModulesController", OpenSim.VersionInfo.VersionNumber)]
|
||||
[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)]
|
||||
|
|
|
@ -30,7 +30,7 @@ using Mono.Addins;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
[assembly: Addin("OpenSim.ApplicationPlugins.RemoteController", OpenSim.VersionInfo.VersionNumber)]
|
||||
[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)]
|
||||
|
|
|
@ -0,0 +1,840 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.StructuredData;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Capabilities;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using Caps = OpenSim.Framework.Capabilities.Caps;
|
||||
|
||||
namespace OpenSim.Capabilities.Handlers
|
||||
{
|
||||
public class FetchInvDescHandler
|
||||
{
|
||||
private static readonly ILog m_log =
|
||||
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private IInventoryService m_InventoryService;
|
||||
private ILibraryService m_LibraryService;
|
||||
// private object m_fetchLock = new Object();
|
||||
|
||||
public FetchInvDescHandler(IInventoryService invService, ILibraryService libService)
|
||||
{
|
||||
m_InventoryService = invService;
|
||||
m_LibraryService = libService;
|
||||
}
|
||||
|
||||
|
||||
public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
|
||||
// nasty temporary hack here, the linden client falsely
|
||||
// identifies the uuid 00000000-0000-0000-0000-000000000000
|
||||
// as a string which breaks us
|
||||
//
|
||||
// correctly mark it as a uuid
|
||||
//
|
||||
request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
|
||||
|
||||
// another hack <integer>1</integer> results in a
|
||||
// System.ArgumentException: Object type System.Int32 cannot
|
||||
// be converted to target type: System.Boolean
|
||||
//
|
||||
request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
|
||||
request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
|
||||
|
||||
Hashtable hash = new Hashtable();
|
||||
try
|
||||
{
|
||||
hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
|
||||
}
|
||||
catch (LLSD.LLSDParseException e)
|
||||
{
|
||||
m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace);
|
||||
m_log.Error("Request: " + request);
|
||||
}
|
||||
|
||||
ArrayList foldersrequested = (ArrayList)hash["folders"];
|
||||
|
||||
string response = "";
|
||||
string bad_folders_response = "";
|
||||
|
||||
List<LLSDFetchInventoryDescendents> folders = new List<LLSDFetchInventoryDescendents>();
|
||||
for (int i = 0; i < foldersrequested.Count; i++)
|
||||
{
|
||||
Hashtable inventoryhash = (Hashtable)foldersrequested[i];
|
||||
|
||||
LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
|
||||
|
||||
try
|
||||
{
|
||||
LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter duplicate folder ids that bad viewers may send
|
||||
if (folders.Find(f => f.folder_id == llsdRequest.folder_id) == null)
|
||||
folders.Add(llsdRequest);
|
||||
}
|
||||
|
||||
if (folders.Count > 0)
|
||||
{
|
||||
List<UUID> bad_folders = new List<UUID>();
|
||||
List<InventoryCollectionWithDescendents> invcollSet = Fetch(folders, bad_folders);
|
||||
//m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count);
|
||||
|
||||
if (invcollSet == null)
|
||||
{
|
||||
m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Multiple folder fetch failed. Trying old protocol.");
|
||||
return FetchInventoryDescendentsRequest(foldersrequested, httpRequest, httpResponse);
|
||||
}
|
||||
|
||||
string inventoryitemstr = string.Empty;
|
||||
foreach (InventoryCollectionWithDescendents icoll in invcollSet)
|
||||
{
|
||||
LLSDInventoryDescendents reply = ToLLSD(icoll.Collection, icoll.Descendents);
|
||||
|
||||
inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
|
||||
inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
|
||||
inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
|
||||
|
||||
response += inventoryitemstr;
|
||||
}
|
||||
|
||||
//m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders));
|
||||
foreach (UUID bad in bad_folders)
|
||||
bad_folders_response += "<uuid>" + bad + "</uuid>";
|
||||
}
|
||||
|
||||
if (response.Length == 0)
|
||||
{
|
||||
/* Viewers expect a bad_folders array when not available */
|
||||
if (bad_folders_response.Length != 0)
|
||||
{
|
||||
response = "<llsd><map><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>";
|
||||
}
|
||||
else
|
||||
{
|
||||
response = "<llsd><map><key>folders</key><array /></map></llsd>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bad_folders_response.Length != 0)
|
||||
{
|
||||
response = "<llsd><map><key>folders</key><array>" + response + "</array><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>";
|
||||
}
|
||||
else
|
||||
{
|
||||
response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
|
||||
}
|
||||
}
|
||||
|
||||
//m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request for {0} folders. Item count {1}", folders.Count, item_count);
|
||||
//m_log.Debug("[WEB FETCH INV DESC HANDLER] " + response);
|
||||
|
||||
return response;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct an LLSD reply packet to a CAPS inventory request
|
||||
/// </summary>
|
||||
/// <param name="invFetch"></param>
|
||||
/// <returns></returns>
|
||||
private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch)
|
||||
{
|
||||
LLSDInventoryDescendents reply = new LLSDInventoryDescendents();
|
||||
LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents();
|
||||
contents.agent_id = invFetch.owner_id;
|
||||
contents.owner_id = invFetch.owner_id;
|
||||
contents.folder_id = invFetch.folder_id;
|
||||
|
||||
reply.folders.Array.Add(contents);
|
||||
InventoryCollection inv = new InventoryCollection();
|
||||
inv.Folders = new List<InventoryFolderBase>();
|
||||
inv.Items = new List<InventoryItemBase>();
|
||||
int version = 0;
|
||||
int descendents = 0;
|
||||
|
||||
inv
|
||||
= Fetch(
|
||||
invFetch.owner_id, invFetch.folder_id, invFetch.owner_id,
|
||||
invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version, out descendents);
|
||||
|
||||
if (inv != null && inv.Folders != null)
|
||||
{
|
||||
foreach (InventoryFolderBase invFolder in inv.Folders)
|
||||
{
|
||||
contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
|
||||
}
|
||||
|
||||
descendents += inv.Folders.Count;
|
||||
}
|
||||
|
||||
if (inv != null && inv.Items != null)
|
||||
{
|
||||
foreach (InventoryItemBase invItem in inv.Items)
|
||||
{
|
||||
contents.items.Array.Add(ConvertInventoryItem(invItem));
|
||||
}
|
||||
}
|
||||
|
||||
contents.descendents = descendents;
|
||||
contents.version = version;
|
||||
|
||||
//m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Replying to request for folder {0} (fetch items {1}, fetch folders {2}) with {3} items and {4} folders for agent {5}",
|
||||
// invFetch.folder_id,
|
||||
// invFetch.fetch_items,
|
||||
// invFetch.fetch_folders,
|
||||
// contents.items.Array.Count,
|
||||
// contents.categories.Array.Count,
|
||||
// invFetch.owner_id);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
private LLSDInventoryDescendents ToLLSD(InventoryCollection inv, int descendents)
|
||||
{
|
||||
LLSDInventoryDescendents reply = new LLSDInventoryDescendents();
|
||||
LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents();
|
||||
contents.agent_id = inv.OwnerID;
|
||||
contents.owner_id = inv.OwnerID;
|
||||
contents.folder_id = inv.FolderID;
|
||||
|
||||
reply.folders.Array.Add(contents);
|
||||
|
||||
if (inv.Folders != null)
|
||||
{
|
||||
foreach (InventoryFolderBase invFolder in inv.Folders)
|
||||
{
|
||||
contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
|
||||
}
|
||||
|
||||
descendents += inv.Folders.Count;
|
||||
}
|
||||
|
||||
if (inv.Items != null)
|
||||
{
|
||||
foreach (InventoryItemBase invItem in inv.Items)
|
||||
{
|
||||
contents.items.Array.Add(ConvertInventoryItem(invItem));
|
||||
}
|
||||
}
|
||||
|
||||
contents.descendents = descendents;
|
||||
contents.version = inv.Version;
|
||||
|
||||
return reply;
|
||||
}
|
||||
/// <summary>
|
||||
/// Old style. Soon to be deprecated.
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="httpRequest"></param>
|
||||
/// <param name="httpResponse"></param>
|
||||
/// <returns></returns>
|
||||
[Obsolete]
|
||||
private string FetchInventoryDescendentsRequest(ArrayList foldersrequested, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
//m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request for {0} folders", foldersrequested.Count);
|
||||
|
||||
string response = "";
|
||||
string bad_folders_response = "";
|
||||
|
||||
for (int i = 0; i < foldersrequested.Count; i++)
|
||||
{
|
||||
string inventoryitemstr = "";
|
||||
Hashtable inventoryhash = (Hashtable)foldersrequested[i];
|
||||
|
||||
LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
|
||||
|
||||
try
|
||||
{
|
||||
LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e);
|
||||
}
|
||||
|
||||
LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
|
||||
|
||||
if (null == reply)
|
||||
{
|
||||
bad_folders_response += "<uuid>" + llsdRequest.folder_id.ToString() + "</uuid>";
|
||||
}
|
||||
else
|
||||
{
|
||||
inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
|
||||
inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
|
||||
inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
|
||||
}
|
||||
|
||||
response += inventoryitemstr;
|
||||
}
|
||||
|
||||
if (response.Length == 0)
|
||||
{
|
||||
/* Viewers expect a bad_folders array when not available */
|
||||
if (bad_folders_response.Length != 0)
|
||||
{
|
||||
response = "<llsd><map><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>";
|
||||
}
|
||||
else
|
||||
{
|
||||
response = "<llsd><map><key>folders</key><array /></map></llsd>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bad_folders_response.Length != 0)
|
||||
{
|
||||
response = "<llsd><map><key>folders</key><array>" + response + "</array><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>";
|
||||
}
|
||||
else
|
||||
{
|
||||
response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
|
||||
}
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request");
|
||||
//m_log.Debug("[WEB FETCH INV DESC HANDLER] "+response);
|
||||
|
||||
return response;
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the caps inventory descendents fetch.
|
||||
/// </summary>
|
||||
/// <param name="agentID"></param>
|
||||
/// <param name="folderID"></param>
|
||||
/// <param name="ownerID"></param>
|
||||
/// <param name="fetchFolders"></param>
|
||||
/// <param name="fetchItems"></param>
|
||||
/// <param name="sortOrder"></param>
|
||||
/// <param name="version"></param>
|
||||
/// <returns>An empty InventoryCollection if the inventory look up failed</returns>
|
||||
[Obsolete]
|
||||
private InventoryCollection Fetch(
|
||||
UUID agentID, UUID folderID, UUID ownerID,
|
||||
bool fetchFolders, bool fetchItems, int sortOrder, out int version, out int descendents)
|
||||
{
|
||||
//m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Fetching folders ({0}), items ({1}) from {2} for agent {3}",
|
||||
// fetchFolders, fetchItems, folderID, agentID);
|
||||
|
||||
// FIXME MAYBE: We're not handling sortOrder!
|
||||
|
||||
version = 0;
|
||||
descendents = 0;
|
||||
|
||||
InventoryFolderImpl fold;
|
||||
if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null && agentID == m_LibraryService.LibraryRootFolder.Owner)
|
||||
{
|
||||
if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(folderID)) != null)
|
||||
{
|
||||
InventoryCollection ret = new InventoryCollection();
|
||||
ret.Folders = new List<InventoryFolderBase>();
|
||||
ret.Items = fold.RequestListOfItems();
|
||||
descendents = ret.Folders.Count + ret.Items.Count;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
InventoryCollection contents = new InventoryCollection();
|
||||
|
||||
if (folderID != UUID.Zero)
|
||||
{
|
||||
InventoryCollection fetchedContents = m_InventoryService.GetFolderContent(agentID, folderID);
|
||||
|
||||
if (fetchedContents == null)
|
||||
{
|
||||
m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Could not get contents of folder {0} for user {1}", folderID, agentID);
|
||||
return contents;
|
||||
}
|
||||
contents = fetchedContents;
|
||||
InventoryFolderBase containingFolder = new InventoryFolderBase();
|
||||
containingFolder.ID = folderID;
|
||||
containingFolder.Owner = agentID;
|
||||
containingFolder = m_InventoryService.GetFolder(containingFolder);
|
||||
|
||||
if (containingFolder != null)
|
||||
{
|
||||
//m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Retrieved folder {0} {1} for agent id {2}",
|
||||
// containingFolder.Name, containingFolder.ID, agentID);
|
||||
|
||||
version = containingFolder.Version;
|
||||
|
||||
if (fetchItems)
|
||||
{
|
||||
List<InventoryItemBase> itemsToReturn = contents.Items;
|
||||
List<InventoryItemBase> originalItems = new List<InventoryItemBase>(itemsToReturn);
|
||||
|
||||
// descendents must only include the links, not the linked items we add
|
||||
descendents = originalItems.Count;
|
||||
|
||||
// Add target items for links in this folder before the links themselves.
|
||||
foreach (InventoryItemBase item in originalItems)
|
||||
{
|
||||
if (item.AssetType == (int)AssetType.Link)
|
||||
{
|
||||
InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID));
|
||||
|
||||
// Take care of genuinely broken links where the target doesn't exist
|
||||
// HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
|
||||
// but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
|
||||
// rather than having to keep track of every folder requested in the recursion.
|
||||
if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
|
||||
itemsToReturn.Insert(0, linkedItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Now scan for folder links and insert the items they target and those links at the head of the return data
|
||||
foreach (InventoryItemBase item in originalItems)
|
||||
{
|
||||
if (item.AssetType == (int)AssetType.LinkFolder)
|
||||
{
|
||||
InventoryCollection linkedFolderContents = m_InventoryService.GetFolderContent(ownerID, item.AssetID);
|
||||
List<InventoryItemBase> links = linkedFolderContents.Items;
|
||||
|
||||
itemsToReturn.InsertRange(0, links);
|
||||
|
||||
foreach (InventoryItemBase link in linkedFolderContents.Items)
|
||||
{
|
||||
// Take care of genuinely broken links where the target doesn't exist
|
||||
// HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
|
||||
// but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
|
||||
// rather than having to keep track of every folder requested in the recursion.
|
||||
if (link != null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Adding item {0} {1} from folder {2} linked from {3}",
|
||||
// link.Name, (AssetType)link.AssetType, item.AssetID, containingFolder.Name);
|
||||
|
||||
InventoryItemBase linkedItem
|
||||
= m_InventoryService.GetItem(new InventoryItemBase(link.AssetID));
|
||||
|
||||
if (linkedItem != null)
|
||||
itemsToReturn.Insert(0, linkedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// foreach (InventoryItemBase item in contents.Items)
|
||||
// {
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Returning item {0}, type {1}, parent {2} in {3} {4}",
|
||||
// item.Name, (AssetType)item.AssetType, item.Folder, containingFolder.Name, containingFolder.ID);
|
||||
// }
|
||||
|
||||
// =====
|
||||
|
||||
//
|
||||
// foreach (InventoryItemBase linkedItem in linkedItemsToAdd)
|
||||
// {
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Inserted linked item {0} for link in folder {1} for agent {2}",
|
||||
// linkedItem.Name, folderID, agentID);
|
||||
//
|
||||
// contents.Items.Add(linkedItem);
|
||||
// }
|
||||
//
|
||||
// // If the folder requested contains links, then we need to send those folders first, otherwise the links
|
||||
// // will be broken in the viewer.
|
||||
// HashSet<UUID> linkedItemFolderIdsToSend = new HashSet<UUID>();
|
||||
// foreach (InventoryItemBase item in contents.Items)
|
||||
// {
|
||||
// if (item.AssetType == (int)AssetType.Link)
|
||||
// {
|
||||
// InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID));
|
||||
//
|
||||
// // Take care of genuinely broken links where the target doesn't exist
|
||||
// // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
|
||||
// // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
|
||||
// // rather than having to keep track of every folder requested in the recursion.
|
||||
// if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
|
||||
// {
|
||||
// // We don't need to send the folder if source and destination of the link are in the same
|
||||
// // folder.
|
||||
// if (linkedItem.Folder != containingFolder.ID)
|
||||
// linkedItemFolderIdsToSend.Add(linkedItem.Folder);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend)
|
||||
// {
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Recursively fetching folder {0} linked by item in folder {1} for agent {2}",
|
||||
// linkedItemFolderId, folderID, agentID);
|
||||
//
|
||||
// int dummyVersion;
|
||||
// InventoryCollection linkedCollection
|
||||
// = Fetch(
|
||||
// agentID, linkedItemFolderId, ownerID, fetchFolders, fetchItems, sortOrder, out dummyVersion);
|
||||
//
|
||||
// InventoryFolderBase linkedFolder = new InventoryFolderBase(linkedItemFolderId);
|
||||
// linkedFolder.Owner = agentID;
|
||||
// linkedFolder = m_InventoryService.GetFolder(linkedFolder);
|
||||
//
|
||||
//// contents.Folders.AddRange(linkedCollection.Folders);
|
||||
//
|
||||
// contents.Folders.Add(linkedFolder);
|
||||
// contents.Items.AddRange(linkedCollection.Items);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Lost items don't really need a version
|
||||
version = 1;
|
||||
}
|
||||
|
||||
return contents;
|
||||
|
||||
}
|
||||
|
||||
private void AddLibraryFolders(List<LLSDFetchInventoryDescendents> fetchFolders, List<InventoryCollectionWithDescendents> result)
|
||||
{
|
||||
InventoryFolderImpl fold;
|
||||
if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null)
|
||||
{
|
||||
List<LLSDFetchInventoryDescendents> libfolders = fetchFolders.FindAll(f => f.owner_id == m_LibraryService.LibraryRootFolder.Owner);
|
||||
fetchFolders.RemoveAll(f => libfolders.Contains(f));
|
||||
|
||||
//m_log.DebugFormat("[XXX]: Found {0} library folders in request", libfolders.Count);
|
||||
|
||||
foreach (LLSDFetchInventoryDescendents f in libfolders)
|
||||
{
|
||||
if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(f.folder_id)) != null)
|
||||
{
|
||||
InventoryCollectionWithDescendents ret = new InventoryCollectionWithDescendents();
|
||||
ret.Collection = new InventoryCollection();
|
||||
ret.Collection.Folders = new List<InventoryFolderBase>();
|
||||
ret.Collection.Items = fold.RequestListOfItems();
|
||||
ret.Collection.OwnerID = m_LibraryService.LibraryRootFolder.Owner;
|
||||
ret.Collection.FolderID = f.folder_id;
|
||||
ret.Collection.Version = fold.Version;
|
||||
|
||||
ret.Descendents = ret.Collection.Items.Count;
|
||||
result.Add(ret);
|
||||
|
||||
//m_log.DebugFormat("[XXX]: Added libfolder {0} ({1}) {2}", ret.Collection.FolderID, ret.Collection.OwnerID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<InventoryCollectionWithDescendents> Fetch(List<LLSDFetchInventoryDescendents> fetchFolders, List<UUID> bad_folders)
|
||||
{
|
||||
//m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Fetching {0} folders for owner {1}", fetchFolders.Count, fetchFolders[0].owner_id);
|
||||
|
||||
// FIXME MAYBE: We're not handling sortOrder!
|
||||
|
||||
List<InventoryCollectionWithDescendents> result = new List<InventoryCollectionWithDescendents>();
|
||||
|
||||
AddLibraryFolders(fetchFolders, result);
|
||||
|
||||
if (fetchFolders.Count > 0)
|
||||
{
|
||||
UUID[] fids = new UUID[fetchFolders.Count];
|
||||
int i = 0;
|
||||
foreach (LLSDFetchInventoryDescendents f in fetchFolders)
|
||||
fids[i++] = f.folder_id;
|
||||
|
||||
//m_log.DebugFormat("[XXX]: {0}", string.Join(",", fids));
|
||||
|
||||
InventoryCollection[] fetchedContents = m_InventoryService.GetMultipleFoldersContent(fetchFolders[0].owner_id, fids);
|
||||
|
||||
if (fetchedContents == null || (fetchedContents != null && fetchedContents.Length == 0))
|
||||
{
|
||||
//m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Could not get contents of multiple folders for user {0}", fetchFolders[0].owner_id);
|
||||
return null;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
// Do some post-processing. May need to fetch more from inv server for links
|
||||
foreach (InventoryCollection contents in fetchedContents)
|
||||
{
|
||||
// Find the original request
|
||||
LLSDFetchInventoryDescendents freq = fetchFolders[i++];
|
||||
|
||||
InventoryCollectionWithDescendents coll = new InventoryCollectionWithDescendents();
|
||||
coll.Collection = contents;
|
||||
|
||||
if (BadFolder(freq, contents, bad_folders))
|
||||
continue;
|
||||
|
||||
// Next: link management
|
||||
ProcessLinks(freq, coll);
|
||||
|
||||
result.Add(coll);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List<UUID> bad_folders)
|
||||
{
|
||||
bool bad = false;
|
||||
if (contents == null)
|
||||
{
|
||||
bad_folders.Add(freq.folder_id);
|
||||
bad = true;
|
||||
}
|
||||
|
||||
// The inventory server isn't sending FolderID in the collection...
|
||||
// Must fetch it individually
|
||||
if (contents.FolderID == UUID.Zero)
|
||||
{
|
||||
InventoryFolderBase containingFolder = new InventoryFolderBase();
|
||||
containingFolder.ID = freq.folder_id;
|
||||
containingFolder.Owner = freq.owner_id;
|
||||
containingFolder = m_InventoryService.GetFolder(containingFolder);
|
||||
|
||||
if (containingFolder != null)
|
||||
{
|
||||
contents.FolderID = containingFolder.ID;
|
||||
contents.OwnerID = containingFolder.Owner;
|
||||
contents.Version = containingFolder.Version;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Was it really a request for folder Zero?
|
||||
// This is an overkill, but Firestorm really asks for folder Zero.
|
||||
// I'm leaving the code here for the time being, but commented.
|
||||
if (freq.folder_id == UUID.Zero)
|
||||
{
|
||||
//coll.Collection.OwnerID = freq.owner_id;
|
||||
//coll.Collection.FolderID = contents.FolderID;
|
||||
//containingFolder = m_InventoryService.GetRootFolder(freq.owner_id);
|
||||
//if (containingFolder != null)
|
||||
//{
|
||||
// m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Request for parent of folder {0}", containingFolder.ID);
|
||||
// coll.Collection.Folders.Clear();
|
||||
// coll.Collection.Folders.Add(containingFolder);
|
||||
// if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null)
|
||||
// {
|
||||
// InventoryFolderBase lib = new InventoryFolderBase(m_LibraryService.LibraryRootFolder.ID, m_LibraryService.LibraryRootFolder.Owner);
|
||||
// lib.Name = m_LibraryService.LibraryRootFolder.Name;
|
||||
// lib.Type = m_LibraryService.LibraryRootFolder.Type;
|
||||
// lib.Version = m_LibraryService.LibraryRootFolder.Version;
|
||||
// coll.Collection.Folders.Add(lib);
|
||||
// }
|
||||
// coll.Collection.Items.Clear();
|
||||
//}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Unable to fetch folder {0}", freq.folder_id);
|
||||
bad_folders.Add(freq.folder_id);
|
||||
}
|
||||
bad = true;
|
||||
}
|
||||
}
|
||||
|
||||
return bad;
|
||||
}
|
||||
|
||||
private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollectionWithDescendents coll)
|
||||
{
|
||||
InventoryCollection contents = coll.Collection;
|
||||
|
||||
if (freq.fetch_items && contents.Items != null)
|
||||
{
|
||||
List<InventoryItemBase> itemsToReturn = contents.Items;
|
||||
|
||||
// descendents must only include the links, not the linked items we add
|
||||
coll.Descendents = itemsToReturn.Count;
|
||||
|
||||
// Add target items for links in this folder before the links themselves.
|
||||
List<UUID> itemIDs = new List<UUID>();
|
||||
List<UUID> folderIDs = new List<UUID>();
|
||||
foreach (InventoryItemBase item in itemsToReturn)
|
||||
{
|
||||
//m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType);
|
||||
if (item.AssetType == (int)AssetType.Link)
|
||||
itemIDs.Add(item.AssetID);
|
||||
|
||||
else if (item.AssetType == (int)AssetType.LinkFolder)
|
||||
folderIDs.Add(item.AssetID);
|
||||
}
|
||||
|
||||
//m_log.DebugFormat("[XXX]: folder {0} has {1} links and {2} linkfolders", contents.FolderID, itemIDs.Count, folderIDs.Count);
|
||||
|
||||
// Scan for folder links and insert the items they target and those links at the head of the return data
|
||||
if (folderIDs.Count > 0)
|
||||
{
|
||||
InventoryCollection[] linkedFolders = m_InventoryService.GetMultipleFoldersContent(coll.Collection.OwnerID, folderIDs.ToArray());
|
||||
foreach (InventoryCollection linkedFolderContents in linkedFolders)
|
||||
{
|
||||
List<InventoryItemBase> links = linkedFolderContents.Items;
|
||||
|
||||
itemsToReturn.InsertRange(0, links);
|
||||
|
||||
foreach (InventoryItemBase link in linkedFolderContents.Items)
|
||||
{
|
||||
// Take care of genuinely broken links where the target doesn't exist
|
||||
// HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
|
||||
// but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
|
||||
// rather than having to keep track of every folder requested in the recursion.
|
||||
if (link != null)
|
||||
{
|
||||
//m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Adding item {0} {1} from folder {2} linked from {3} ({4} {5})",
|
||||
// link.Name, (AssetType)link.AssetType, linkedFolderContents.FolderID, contents.FolderID, link.ID, link.AssetID);
|
||||
itemIDs.Add(link.ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (itemIDs.Count > 0)
|
||||
{
|
||||
InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray());
|
||||
if (linked == null)
|
||||
{
|
||||
// OMG!!! One by one!!! This is fallback code, in case the backend isn't updated
|
||||
m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: GetMultipleItems failed. Falling back to fetching inventory items one by one.");
|
||||
linked = new InventoryItemBase[itemIDs.Count];
|
||||
int i = 0;
|
||||
InventoryItemBase item = new InventoryItemBase();
|
||||
item.Owner = freq.owner_id;
|
||||
foreach (UUID id in itemIDs)
|
||||
{
|
||||
item.ID = id;
|
||||
linked[i++] = m_InventoryService.GetItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
//m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Processing folder {0}. Existing items:", freq.folder_id);
|
||||
//foreach (InventoryItemBase item in itemsToReturn)
|
||||
// m_log.DebugFormat("[XXX]: {0} {1} {2}", item.Name, item.AssetType, item.Folder);
|
||||
|
||||
if (linked != null)
|
||||
{
|
||||
foreach (InventoryItemBase linkedItem in linked)
|
||||
{
|
||||
// Take care of genuinely broken links where the target doesn't exist
|
||||
// HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
|
||||
// but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
|
||||
// rather than having to keep track of every folder requested in the recursion.
|
||||
if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
|
||||
{
|
||||
itemsToReturn.Insert(0, linkedItem);
|
||||
//m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert an internal inventory folder object into an LLSD object.
|
||||
/// </summary>
|
||||
/// <param name="invFolder"></param>
|
||||
/// <returns></returns>
|
||||
private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder)
|
||||
{
|
||||
LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder();
|
||||
llsdFolder.folder_id = invFolder.ID;
|
||||
llsdFolder.parent_id = invFolder.ParentID;
|
||||
llsdFolder.name = invFolder.Name;
|
||||
llsdFolder.type = invFolder.Type;
|
||||
llsdFolder.preferred_type = -1;
|
||||
|
||||
return llsdFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert an internal inventory item object into an LLSD object.
|
||||
/// </summary>
|
||||
/// <param name="invItem"></param>
|
||||
/// <returns></returns>
|
||||
private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem)
|
||||
{
|
||||
LLSDInventoryItem llsdItem = new LLSDInventoryItem();
|
||||
llsdItem.asset_id = invItem.AssetID;
|
||||
llsdItem.created_at = invItem.CreationDate;
|
||||
llsdItem.desc = invItem.Description;
|
||||
llsdItem.flags = (int)invItem.Flags;
|
||||
llsdItem.item_id = invItem.ID;
|
||||
llsdItem.name = invItem.Name;
|
||||
llsdItem.parent_id = invItem.Folder;
|
||||
llsdItem.type = invItem.AssetType;
|
||||
llsdItem.inv_type = invItem.InvType;
|
||||
|
||||
llsdItem.permissions = new LLSDPermissions();
|
||||
llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid;
|
||||
llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions;
|
||||
llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions;
|
||||
llsdItem.permissions.group_id = invItem.GroupID;
|
||||
llsdItem.permissions.group_mask = (int)invItem.GroupPermissions;
|
||||
llsdItem.permissions.is_owner_group = invItem.GroupOwned;
|
||||
llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions;
|
||||
llsdItem.permissions.owner_id = invItem.Owner;
|
||||
llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions;
|
||||
llsdItem.sale_info = new LLSDSaleInfo();
|
||||
llsdItem.sale_info.sale_price = invItem.SalePrice;
|
||||
llsdItem.sale_info.sale_type = invItem.SaleType;
|
||||
|
||||
return llsdItem;
|
||||
}
|
||||
}
|
||||
|
||||
class InventoryCollectionWithDescendents
|
||||
{
|
||||
public InventoryCollection Collection;
|
||||
public int Descendents;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using log4net;
|
||||
using log4net.Config;
|
||||
using NUnit.Framework;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Capabilities.Handlers;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using OpenSim.Tests.Common;
|
||||
|
||||
namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class FetchInventoryDescendents2HandlerTests : OpenSimTestCase
|
||||
{
|
||||
private UUID m_userID = UUID.Zero;
|
||||
private Scene m_scene;
|
||||
private UUID m_rootFolderID;
|
||||
private int m_rootDescendents;
|
||||
private UUID m_notecardsFolder;
|
||||
private UUID m_objectsFolder;
|
||||
|
||||
private void Init()
|
||||
{
|
||||
// Create an inventory that looks like this:
|
||||
//
|
||||
// /My Inventory
|
||||
// <other system folders>
|
||||
// /Objects
|
||||
// Some Object
|
||||
// /Notecards
|
||||
// Notecard 1
|
||||
// Notecard 2
|
||||
// /Test Folder
|
||||
// Link to notecard -> /Notecards/Notecard 2
|
||||
// Link to Objects folder -> /Objects
|
||||
|
||||
m_scene = new SceneHelpers().SetupScene();
|
||||
|
||||
m_scene.InventoryService.CreateUserInventory(m_userID);
|
||||
|
||||
m_rootFolderID = m_scene.InventoryService.GetRootFolder(m_userID).ID;
|
||||
|
||||
InventoryFolderBase of = m_scene.InventoryService.GetFolderForType(m_userID, AssetType.Object);
|
||||
m_objectsFolder = of.ID;
|
||||
|
||||
// Add an object
|
||||
InventoryItemBase item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-00000000000b"), m_userID);
|
||||
item.AssetID = UUID.Random();
|
||||
item.AssetType = (int)AssetType.Object;
|
||||
item.Folder = m_objectsFolder;
|
||||
item.Name = "Some Object";
|
||||
m_scene.InventoryService.AddItem(item);
|
||||
|
||||
InventoryFolderBase ncf = m_scene.InventoryService.GetFolderForType(m_userID, AssetType.Notecard);
|
||||
m_notecardsFolder = ncf.ID;
|
||||
|
||||
// Add a notecard
|
||||
item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-000000000001"), m_userID);
|
||||
item.AssetID = UUID.Random();
|
||||
item.AssetType = (int)AssetType.Notecard;
|
||||
item.Folder = m_notecardsFolder;
|
||||
item.Name = "Test Notecard 1";
|
||||
m_scene.InventoryService.AddItem(item);
|
||||
// Add another notecard
|
||||
item.ID = new UUID("20000000-0000-0000-0000-000000000002");
|
||||
item.AssetID = new UUID("a0000000-0000-0000-0000-00000000000a");
|
||||
item.Name = "Test Notecard 2";
|
||||
m_scene.InventoryService.AddItem(item);
|
||||
|
||||
// Add a folder
|
||||
InventoryFolderBase folder = new InventoryFolderBase(new UUID("f0000000-0000-0000-0000-00000000000f"), "Test Folder", m_userID, m_rootFolderID);
|
||||
m_scene.InventoryService.AddFolder(folder);
|
||||
|
||||
// Add a link to notecard 2 in Test Folder
|
||||
item.AssetID = item.ID; // use item ID of notecard 2
|
||||
item.ID = new UUID("40000000-0000-0000-0000-000000000004");
|
||||
item.AssetType = (int)AssetType.Link;
|
||||
item.Folder = folder.ID;
|
||||
item.Name = "Link to notecard";
|
||||
m_scene.InventoryService.AddItem(item);
|
||||
|
||||
// Add a link to the Objects folder in Test Folder
|
||||
item.AssetID = m_scene.InventoryService.GetFolderForType(m_userID, AssetType.Object).ID; // use item ID of Objects folder
|
||||
item.ID = new UUID("50000000-0000-0000-0000-000000000005");
|
||||
item.AssetType = (int)AssetType.LinkFolder;
|
||||
item.Folder = folder.ID;
|
||||
item.Name = "Link to Objects folder";
|
||||
m_scene.InventoryService.AddItem(item);
|
||||
|
||||
InventoryCollection coll = m_scene.InventoryService.GetFolderContent(m_userID, m_rootFolderID);
|
||||
m_rootDescendents = coll.Items.Count + coll.Folders.Count;
|
||||
Console.WriteLine("Number of descendents: " + m_rootDescendents);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_001_SimpleFolder()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
|
||||
Init();
|
||||
|
||||
FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null);
|
||||
TestOSHttpRequest req = new TestOSHttpRequest();
|
||||
TestOSHttpResponse resp = new TestOSHttpResponse();
|
||||
|
||||
string request = "<llsd><map><key>folders</key><array><map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
|
||||
request += m_rootFolderID;
|
||||
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map></array></map></llsd>";
|
||||
|
||||
string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp);
|
||||
|
||||
Assert.That(llsdresponse != null, Is.True, "Incorrect null response");
|
||||
Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response");
|
||||
Assert.That(llsdresponse.Contains("00000000-0000-0000-0000-000000000000"), Is.True, "Response should contain userID");
|
||||
|
||||
string descendents = "descendents</key><integer>" + m_rootDescendents + "</integer>";
|
||||
Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents");
|
||||
Console.WriteLine(llsdresponse);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_002_MultipleFolders()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
|
||||
FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null);
|
||||
TestOSHttpRequest req = new TestOSHttpRequest();
|
||||
TestOSHttpResponse resp = new TestOSHttpResponse();
|
||||
|
||||
string request = "<llsd><map><key>folders</key><array>";
|
||||
request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
|
||||
request += m_rootFolderID;
|
||||
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map>";
|
||||
request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
|
||||
request += m_notecardsFolder;
|
||||
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map>";
|
||||
request += "</array></map></llsd>";
|
||||
|
||||
string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp);
|
||||
Console.WriteLine(llsdresponse);
|
||||
|
||||
string descendents = "descendents</key><integer>" + m_rootDescendents + "</integer>";
|
||||
Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for root folder");
|
||||
descendents = "descendents</key><integer>2</integer>";
|
||||
Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Notecard folder");
|
||||
|
||||
Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Notecard 1 is missing from response");
|
||||
Assert.That(llsdresponse.Contains("20000000-0000-0000-0000-000000000002"), Is.True, "Notecard 2 is missing from response");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Test_003_Links()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
|
||||
FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null);
|
||||
TestOSHttpRequest req = new TestOSHttpRequest();
|
||||
TestOSHttpResponse resp = new TestOSHttpResponse();
|
||||
|
||||
string request = "<llsd><map><key>folders</key><array><map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
|
||||
request += "f0000000-0000-0000-0000-00000000000f";
|
||||
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map></array></map></llsd>";
|
||||
|
||||
string llsdresponse = handler.FetchInventoryDescendentsRequest(request, "/FETCH", string.Empty, req, resp);
|
||||
Console.WriteLine(llsdresponse);
|
||||
|
||||
string descendents = "descendents</key><integer>2</integer>";
|
||||
Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Test Folder");
|
||||
|
||||
// Make sure that the note card link is included
|
||||
Assert.That(llsdresponse.Contains("Link to notecard"), Is.True, "Link to notecard is missing");
|
||||
|
||||
//Make sure the notecard item itself is included
|
||||
Assert.That(llsdresponse.Contains("Test Notecard 2"), Is.True, "Notecard 2 item (the source) is missing");
|
||||
|
||||
// Make sure that the source item is before the link item
|
||||
int pos1 = llsdresponse.IndexOf("Test Notecard 2");
|
||||
int pos2 = llsdresponse.IndexOf("Link to notecard");
|
||||
Assert.Less(pos1, pos2, "Source of link is after link");
|
||||
|
||||
// Make sure the folder link is included
|
||||
Assert.That(llsdresponse.Contains("Link to Objects folder"), Is.True, "Link to Objects folder is missing");
|
||||
|
||||
// Make sure the objects inside the Objects folder are included
|
||||
// Note: I'm not entirely sure this is needed, but that's what I found in the implementation
|
||||
Assert.That(llsdresponse.Contains("Some Object"), Is.True, "Some Object item (contents of the source) is missing");
|
||||
|
||||
// Make sure that the source item is before the link item
|
||||
pos1 = llsdresponse.IndexOf("Some Object");
|
||||
pos2 = llsdresponse.IndexOf("Link to Objects folder");
|
||||
Assert.Less(pos1, pos2, "Contents of source of folder link is after folder link");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,465 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.StructuredData;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Capabilities;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using Caps = OpenSim.Framework.Capabilities.Caps;
|
||||
|
||||
namespace OpenSim.Capabilities.Handlers
|
||||
{
|
||||
public class FetchInvDescHandler
|
||||
{
|
||||
private static readonly ILog m_log =
|
||||
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private IInventoryService m_InventoryService;
|
||||
private ILibraryService m_LibraryService;
|
||||
// private object m_fetchLock = new Object();
|
||||
|
||||
public FetchInvDescHandler(IInventoryService invService, ILibraryService libService)
|
||||
{
|
||||
m_InventoryService = invService;
|
||||
m_LibraryService = libService;
|
||||
}
|
||||
|
||||
public string FetchInventoryDescendentsRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
// lock (m_fetchLock)
|
||||
// {
|
||||
// m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Received request {0}", request);
|
||||
|
||||
// nasty temporary hack here, the linden client falsely
|
||||
// identifies the uuid 00000000-0000-0000-0000-000000000000
|
||||
// as a string which breaks us
|
||||
//
|
||||
// correctly mark it as a uuid
|
||||
//
|
||||
request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
|
||||
|
||||
// another hack <integer>1</integer> results in a
|
||||
// System.ArgumentException: Object type System.Int32 cannot
|
||||
// be converted to target type: System.Boolean
|
||||
//
|
||||
request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
|
||||
request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
|
||||
|
||||
Hashtable hash = new Hashtable();
|
||||
try
|
||||
{
|
||||
hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
|
||||
}
|
||||
catch (LLSD.LLSDParseException e)
|
||||
{
|
||||
m_log.ErrorFormat("[WEB FETCH INV DESC HANDLER]: Fetch error: {0}{1}" + e.Message, e.StackTrace);
|
||||
m_log.Error("Request: " + request);
|
||||
}
|
||||
|
||||
ArrayList foldersrequested = (ArrayList)hash["folders"];
|
||||
|
||||
string response = "";
|
||||
string bad_folders_response = "";
|
||||
|
||||
for (int i = 0; i < foldersrequested.Count; i++)
|
||||
{
|
||||
string inventoryitemstr = "";
|
||||
Hashtable inventoryhash = (Hashtable)foldersrequested[i];
|
||||
|
||||
LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
|
||||
|
||||
try
|
||||
{
|
||||
LLSDHelpers.DeserialiseOSDMap(inventoryhash, llsdRequest);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e);
|
||||
}
|
||||
LLSDInventoryDescendents reply = FetchInventoryReply(llsdRequest);
|
||||
|
||||
if (null == reply)
|
||||
{
|
||||
bad_folders_response += "<uuid>" + llsdRequest.folder_id.ToString() + "</uuid>";
|
||||
}
|
||||
else
|
||||
{
|
||||
inventoryitemstr = LLSDHelpers.SerialiseLLSDReply(reply);
|
||||
inventoryitemstr = inventoryitemstr.Replace("<llsd><map><key>folders</key><array>", "");
|
||||
inventoryitemstr = inventoryitemstr.Replace("</array></map></llsd>", "");
|
||||
}
|
||||
|
||||
response += inventoryitemstr;
|
||||
}
|
||||
|
||||
if (response.Length == 0)
|
||||
{
|
||||
/* Viewers expect a bad_folders array when not available */
|
||||
if (bad_folders_response.Length != 0)
|
||||
{
|
||||
response = "<llsd><map><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>";
|
||||
}
|
||||
else
|
||||
{
|
||||
response = "<llsd><map><key>folders</key><array /></map></llsd>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bad_folders_response.Length != 0)
|
||||
{
|
||||
response = "<llsd><map><key>folders</key><array>" + response + "</array><key>bad_folders</key><array>" + bad_folders_response + "</array></map></llsd>";
|
||||
}
|
||||
else
|
||||
{
|
||||
response = "<llsd><map><key>folders</key><array>" + response + "</array></map></llsd>";
|
||||
}
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Replying to CAPS fetch inventory request");
|
||||
//m_log.Debug("[WEB FETCH INV DESC HANDLER] "+response);
|
||||
|
||||
return response;
|
||||
|
||||
// }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct an LLSD reply packet to a CAPS inventory request
|
||||
/// </summary>
|
||||
/// <param name="invFetch"></param>
|
||||
/// <returns></returns>
|
||||
private LLSDInventoryDescendents FetchInventoryReply(LLSDFetchInventoryDescendents invFetch)
|
||||
{
|
||||
LLSDInventoryDescendents reply = new LLSDInventoryDescendents();
|
||||
LLSDInventoryFolderContents contents = new LLSDInventoryFolderContents();
|
||||
contents.agent_id = invFetch.owner_id;
|
||||
contents.owner_id = invFetch.owner_id;
|
||||
contents.folder_id = invFetch.folder_id;
|
||||
|
||||
reply.folders.Array.Add(contents);
|
||||
InventoryCollection inv = new InventoryCollection();
|
||||
inv.Folders = new List<InventoryFolderBase>();
|
||||
inv.Items = new List<InventoryItemBase>();
|
||||
int version = 0;
|
||||
int descendents = 0;
|
||||
|
||||
inv
|
||||
= Fetch(
|
||||
invFetch.owner_id, invFetch.folder_id, invFetch.owner_id,
|
||||
invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version, out descendents);
|
||||
|
||||
if (inv != null && inv.Folders != null)
|
||||
{
|
||||
foreach (InventoryFolderBase invFolder in inv.Folders)
|
||||
{
|
||||
contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
|
||||
}
|
||||
|
||||
descendents += inv.Folders.Count;
|
||||
}
|
||||
|
||||
if (inv != null && inv.Items != null)
|
||||
{
|
||||
foreach (InventoryItemBase invItem in inv.Items)
|
||||
{
|
||||
contents.items.Array.Add(ConvertInventoryItem(invItem));
|
||||
}
|
||||
}
|
||||
|
||||
contents.descendents = descendents;
|
||||
contents.version = version;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Replying to request for folder {0} (fetch items {1}, fetch folders {2}) with {3} items and {4} folders for agent {5}",
|
||||
// invFetch.folder_id,
|
||||
// invFetch.fetch_items,
|
||||
// invFetch.fetch_folders,
|
||||
// contents.items.Array.Count,
|
||||
// contents.categories.Array.Count,
|
||||
// invFetch.owner_id);
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle the caps inventory descendents fetch.
|
||||
/// </summary>
|
||||
/// <param name="agentID"></param>
|
||||
/// <param name="folderID"></param>
|
||||
/// <param name="ownerID"></param>
|
||||
/// <param name="fetchFolders"></param>
|
||||
/// <param name="fetchItems"></param>
|
||||
/// <param name="sortOrder"></param>
|
||||
/// <param name="version"></param>
|
||||
/// <returns>An empty InventoryCollection if the inventory look up failed</returns>
|
||||
private InventoryCollection Fetch(
|
||||
UUID agentID, UUID folderID, UUID ownerID,
|
||||
bool fetchFolders, bool fetchItems, int sortOrder, out int version, out int descendents)
|
||||
{
|
||||
//m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Fetching folders ({0}), items ({1}) from {2} for agent {3}",
|
||||
// fetchFolders, fetchItems, folderID, agentID);
|
||||
|
||||
// FIXME MAYBE: We're not handling sortOrder!
|
||||
|
||||
version = 0;
|
||||
descendents = 0;
|
||||
|
||||
InventoryFolderImpl fold;
|
||||
if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null && agentID == m_LibraryService.LibraryRootFolder.Owner)
|
||||
{
|
||||
if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(folderID)) != null)
|
||||
{
|
||||
InventoryCollection ret = new InventoryCollection();
|
||||
ret.Folders = new List<InventoryFolderBase>();
|
||||
ret.Items = fold.RequestListOfItems();
|
||||
descendents = ret.Folders.Count + ret.Items.Count;
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
InventoryCollection contents = new InventoryCollection();
|
||||
|
||||
if (folderID != UUID.Zero)
|
||||
{
|
||||
InventoryCollection fetchedContents = m_InventoryService.GetFolderContent(agentID, folderID);
|
||||
|
||||
if (fetchedContents == null)
|
||||
{
|
||||
m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Could not get contents of folder {0} for user {1}", folderID, agentID);
|
||||
return contents;
|
||||
}
|
||||
|
||||
contents = fetchedContents;
|
||||
InventoryFolderBase containingFolder = new InventoryFolderBase();
|
||||
containingFolder.ID = folderID;
|
||||
containingFolder.Owner = agentID;
|
||||
containingFolder = m_InventoryService.GetFolder(containingFolder);
|
||||
|
||||
if (containingFolder != null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Retrieved folder {0} {1} for agent id {2}",
|
||||
// containingFolder.Name, containingFolder.ID, agentID);
|
||||
|
||||
version = containingFolder.Version;
|
||||
|
||||
if (fetchItems)
|
||||
{
|
||||
List<InventoryItemBase> itemsToReturn = contents.Items;
|
||||
List<InventoryItemBase> originalItems = new List<InventoryItemBase>(itemsToReturn);
|
||||
|
||||
// descendents must only include the links, not the linked items we add
|
||||
descendents = originalItems.Count;
|
||||
|
||||
// Add target items for links in this folder before the links themselves.
|
||||
foreach (InventoryItemBase item in originalItems)
|
||||
{
|
||||
if (item.AssetType == (int)AssetType.Link)
|
||||
{
|
||||
InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID));
|
||||
|
||||
// Take care of genuinely broken links where the target doesn't exist
|
||||
// HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
|
||||
// but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
|
||||
// rather than having to keep track of every folder requested in the recursion.
|
||||
if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
|
||||
itemsToReturn.Insert(0, linkedItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Now scan for folder links and insert the items they target and those links at the head of the return data
|
||||
foreach (InventoryItemBase item in originalItems)
|
||||
{
|
||||
if (item.AssetType == (int)AssetType.LinkFolder)
|
||||
{
|
||||
InventoryCollection linkedFolderContents = m_InventoryService.GetFolderContent(ownerID, item.AssetID);
|
||||
List<InventoryItemBase> links = linkedFolderContents.Items;
|
||||
|
||||
itemsToReturn.InsertRange(0, links);
|
||||
|
||||
foreach (InventoryItemBase link in linkedFolderContents.Items)
|
||||
{
|
||||
// Take care of genuinely broken links where the target doesn't exist
|
||||
// HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
|
||||
// but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
|
||||
// rather than having to keep track of every folder requested in the recursion.
|
||||
if (link != null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Adding item {0} {1} from folder {2} linked from {3}",
|
||||
// link.Name, (AssetType)link.AssetType, item.AssetID, containingFolder.Name);
|
||||
|
||||
InventoryItemBase linkedItem
|
||||
= m_InventoryService.GetItem(new InventoryItemBase(link.AssetID));
|
||||
|
||||
if (linkedItem != null)
|
||||
itemsToReturn.Insert(0, linkedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// foreach (InventoryItemBase item in contents.Items)
|
||||
// {
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Returning item {0}, type {1}, parent {2} in {3} {4}",
|
||||
// item.Name, (AssetType)item.AssetType, item.Folder, containingFolder.Name, containingFolder.ID);
|
||||
// }
|
||||
|
||||
// =====
|
||||
|
||||
//
|
||||
// foreach (InventoryItemBase linkedItem in linkedItemsToAdd)
|
||||
// {
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Inserted linked item {0} for link in folder {1} for agent {2}",
|
||||
// linkedItem.Name, folderID, agentID);
|
||||
//
|
||||
// contents.Items.Add(linkedItem);
|
||||
// }
|
||||
//
|
||||
// // If the folder requested contains links, then we need to send those folders first, otherwise the links
|
||||
// // will be broken in the viewer.
|
||||
// HashSet<UUID> linkedItemFolderIdsToSend = new HashSet<UUID>();
|
||||
// foreach (InventoryItemBase item in contents.Items)
|
||||
// {
|
||||
// if (item.AssetType == (int)AssetType.Link)
|
||||
// {
|
||||
// InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID));
|
||||
//
|
||||
// // Take care of genuinely broken links where the target doesn't exist
|
||||
// // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
|
||||
// // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
|
||||
// // rather than having to keep track of every folder requested in the recursion.
|
||||
// if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
|
||||
// {
|
||||
// // We don't need to send the folder if source and destination of the link are in the same
|
||||
// // folder.
|
||||
// if (linkedItem.Folder != containingFolder.ID)
|
||||
// linkedItemFolderIdsToSend.Add(linkedItem.Folder);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// foreach (UUID linkedItemFolderId in linkedItemFolderIdsToSend)
|
||||
// {
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Recursively fetching folder {0} linked by item in folder {1} for agent {2}",
|
||||
// linkedItemFolderId, folderID, agentID);
|
||||
//
|
||||
// int dummyVersion;
|
||||
// InventoryCollection linkedCollection
|
||||
// = Fetch(
|
||||
// agentID, linkedItemFolderId, ownerID, fetchFolders, fetchItems, sortOrder, out dummyVersion);
|
||||
//
|
||||
// InventoryFolderBase linkedFolder = new InventoryFolderBase(linkedItemFolderId);
|
||||
// linkedFolder.Owner = agentID;
|
||||
// linkedFolder = m_InventoryService.GetFolder(linkedFolder);
|
||||
//
|
||||
//// contents.Folders.AddRange(linkedCollection.Folders);
|
||||
//
|
||||
// contents.Folders.Add(linkedFolder);
|
||||
// contents.Items.AddRange(linkedCollection.Items);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Lost items don't really need a version
|
||||
version = 1;
|
||||
}
|
||||
|
||||
return contents;
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Convert an internal inventory folder object into an LLSD object.
|
||||
/// </summary>
|
||||
/// <param name="invFolder"></param>
|
||||
/// <returns></returns>
|
||||
private LLSDInventoryFolder ConvertInventoryFolder(InventoryFolderBase invFolder)
|
||||
{
|
||||
LLSDInventoryFolder llsdFolder = new LLSDInventoryFolder();
|
||||
llsdFolder.folder_id = invFolder.ID;
|
||||
llsdFolder.parent_id = invFolder.ParentID;
|
||||
llsdFolder.name = invFolder.Name;
|
||||
llsdFolder.type = invFolder.Type;
|
||||
llsdFolder.preferred_type = -1;
|
||||
|
||||
return llsdFolder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert an internal inventory item object into an LLSD object.
|
||||
/// </summary>
|
||||
/// <param name="invItem"></param>
|
||||
/// <returns></returns>
|
||||
private LLSDInventoryItem ConvertInventoryItem(InventoryItemBase invItem)
|
||||
{
|
||||
LLSDInventoryItem llsdItem = new LLSDInventoryItem();
|
||||
llsdItem.asset_id = invItem.AssetID;
|
||||
llsdItem.created_at = invItem.CreationDate;
|
||||
llsdItem.desc = invItem.Description;
|
||||
llsdItem.flags = (int)invItem.Flags;
|
||||
llsdItem.item_id = invItem.ID;
|
||||
llsdItem.name = invItem.Name;
|
||||
llsdItem.parent_id = invItem.Folder;
|
||||
llsdItem.type = invItem.AssetType;
|
||||
llsdItem.inv_type = invItem.InvType;
|
||||
|
||||
llsdItem.permissions = new LLSDPermissions();
|
||||
llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid;
|
||||
llsdItem.permissions.base_mask = (int)invItem.CurrentPermissions;
|
||||
llsdItem.permissions.everyone_mask = (int)invItem.EveryOnePermissions;
|
||||
llsdItem.permissions.group_id = invItem.GroupID;
|
||||
llsdItem.permissions.group_mask = (int)invItem.GroupPermissions;
|
||||
llsdItem.permissions.is_owner_group = invItem.GroupOwned;
|
||||
llsdItem.permissions.next_owner_mask = (int)invItem.NextPermissions;
|
||||
llsdItem.permissions.owner_id = invItem.Owner;
|
||||
llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions;
|
||||
llsdItem.sale_info = new LLSDSaleInfo();
|
||||
llsdItem.sale_info.sale_price = invItem.SalePrice;
|
||||
llsdItem.sale_info.sale_type = invItem.SaleType;
|
||||
|
||||
return llsdItem;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -59,4 +59,4 @@ using System.Runtime.InteropServices;
|
|||
// Revision
|
||||
//
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all values by your own or you can build default build and revision
|
||||
// numbers with the '*' character (the default):
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
|
|
@ -37,6 +37,8 @@ namespace OpenSim.Framework
|
|||
{
|
||||
public List<InventoryFolderBase> Folders;
|
||||
public List<InventoryItemBase> Items;
|
||||
public UUID UserID;
|
||||
public UUID OwnerID;
|
||||
public UUID FolderID;
|
||||
public int Version;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -125,7 +125,8 @@ namespace OpenSim.Framework.Serialization.External
|
|||
/// <param name="userService">The service for retrieving user account information</param>
|
||||
/// <param name="scopeID">The scope of the user account information (Grid ID)</param>
|
||||
/// <returns>The SceneObjectPart represented in XML2</returns>
|
||||
public static string RewriteSOP(string xml, string homeURL, IUserAccountService userService, UUID scopeID)
|
||||
[Obsolete("This method is deprecated. Use RewriteSOP instead.")]
|
||||
public static string RewriteSOP_Old(string xml, string homeURL, IUserAccountService userService, UUID scopeID)
|
||||
{
|
||||
if (xml == string.Empty || homeURL == string.Empty || userService == null)
|
||||
return xml;
|
||||
|
@ -173,6 +174,187 @@ namespace OpenSim.Framework.Serialization.External
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Takes a XML representation of a SceneObjectPart and returns another XML representation
|
||||
/// with creator data added to it.
|
||||
/// </summary>
|
||||
/// <param name="xml">The SceneObjectPart represented in XML2</param>
|
||||
/// <param name="sceneName">An identifier for the component that's calling this function</param>
|
||||
/// <param name="homeURL">The URL of the user agents service (home) for the creator</param>
|
||||
/// <param name="userService">The service for retrieving user account information</param>
|
||||
/// <param name="scopeID">The scope of the user account information (Grid ID)</param>
|
||||
/// <returns>The SceneObjectPart represented in XML2</returns>
|
||||
public static string RewriteSOP(string xmlData, string sceneName, string homeURL, IUserAccountService userService, UUID scopeID)
|
||||
{
|
||||
// Console.WriteLine("Input XML [{0}]", xmlData);
|
||||
if (xmlData == string.Empty || homeURL == string.Empty || userService == null)
|
||||
return xmlData;
|
||||
|
||||
using (StringWriter sw = new StringWriter())
|
||||
using (XmlTextWriter writer = new XmlTextWriter(sw))
|
||||
using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null))
|
||||
using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment }))
|
||||
{
|
||||
TransformXml(reader, writer, sceneName, homeURL, userService, scopeID);
|
||||
|
||||
// Console.WriteLine("Output: [{0}]", sw.ToString());
|
||||
|
||||
return sw.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
protected static void TransformXml(XmlReader reader, XmlWriter writer, string sceneName, string homeURI, IUserAccountService userAccountService, UUID scopeID)
|
||||
{
|
||||
// m_log.DebugFormat("[HG ASSET MAPPER]: Transforming XML");
|
||||
|
||||
int sopDepth = -1;
|
||||
UserAccount creator = null;
|
||||
bool hasCreatorData = false;
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
// Console.WriteLine("Depth: {0}, name {1}", reader.Depth, reader.Name);
|
||||
|
||||
switch (reader.NodeType)
|
||||
{
|
||||
case XmlNodeType.Attribute:
|
||||
// Console.WriteLine("FOUND ATTRIBUTE {0}", reader.Name);
|
||||
writer.WriteAttributeString(reader.Name, reader.Value);
|
||||
break;
|
||||
|
||||
case XmlNodeType.CDATA:
|
||||
writer.WriteCData(reader.Value);
|
||||
break;
|
||||
|
||||
case XmlNodeType.Comment:
|
||||
writer.WriteComment(reader.Value);
|
||||
break;
|
||||
|
||||
case XmlNodeType.DocumentType:
|
||||
writer.WriteDocType(reader.Name, reader.Value, null, null);
|
||||
break;
|
||||
|
||||
case XmlNodeType.Element:
|
||||
// m_log.DebugFormat("Depth {0} at element {1}", reader.Depth, reader.Name);
|
||||
|
||||
writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
|
||||
|
||||
if (reader.HasAttributes)
|
||||
{
|
||||
while (reader.MoveToNextAttribute())
|
||||
writer.WriteAttributeString(reader.Name, reader.Value);
|
||||
|
||||
reader.MoveToElement();
|
||||
}
|
||||
|
||||
if (reader.LocalName == "SceneObjectPart")
|
||||
{
|
||||
if (sopDepth < 0)
|
||||
{
|
||||
sopDepth = reader.Depth;
|
||||
// m_log.DebugFormat("[HG ASSET MAPPER]: Set sopDepth to {0}", sopDepth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sopDepth >= 0 && reader.Depth == sopDepth + 1)
|
||||
{
|
||||
if (reader.Name == "CreatorID")
|
||||
{
|
||||
reader.Read();
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Guid" || reader.Name == "UUID")
|
||||
{
|
||||
reader.Read();
|
||||
|
||||
if (reader.NodeType == XmlNodeType.Text)
|
||||
{
|
||||
UUID uuid = UUID.Zero;
|
||||
UUID.TryParse(reader.Value, out uuid);
|
||||
creator = userAccountService.GetUserAccount(scopeID, uuid);
|
||||
writer.WriteElementString("UUID", reader.Value);
|
||||
reader.Read();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we unexpected run across mixed content in this node, still carry on
|
||||
// transforming the subtree (this replicates earlier behaviour).
|
||||
TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we unexpected run across mixed content in this node, still carry on
|
||||
// transforming the subtree (this replicates earlier behaviour).
|
||||
TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
|
||||
}
|
||||
}
|
||||
else if (reader.Name == "CreatorData")
|
||||
{
|
||||
reader.Read();
|
||||
if (reader.NodeType == XmlNodeType.Text)
|
||||
{
|
||||
hasCreatorData = true;
|
||||
writer.WriteString(reader.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we unexpected run across mixed content in this node, still carry on
|
||||
// transforming the subtree (this replicates earlier behaviour).
|
||||
TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
// m_log.DebugFormat("[HG ASSET MAPPER]: Writing end for empty element {0}", reader.Name);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case XmlNodeType.EndElement:
|
||||
// m_log.DebugFormat("Depth {0} at EndElement", reader.Depth);
|
||||
if (sopDepth == reader.Depth)
|
||||
{
|
||||
if (!hasCreatorData && creator != null)
|
||||
writer.WriteElementString(reader.Prefix, "CreatorData", reader.NamespaceURI, string.Format("{0};{1} {2}", homeURI, creator.FirstName, creator.LastName));
|
||||
|
||||
// m_log.DebugFormat("[HG ASSET MAPPER]: Reset sopDepth");
|
||||
sopDepth = -1;
|
||||
creator = null;
|
||||
hasCreatorData = false;
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
|
||||
case XmlNodeType.EntityReference:
|
||||
writer.WriteEntityRef(reader.Name);
|
||||
break;
|
||||
|
||||
case XmlNodeType.ProcessingInstruction:
|
||||
writer.WriteProcessingInstruction(reader.Name, reader.Value);
|
||||
break;
|
||||
|
||||
case XmlNodeType.Text:
|
||||
writer.WriteString(reader.Value);
|
||||
break;
|
||||
|
||||
case XmlNodeType.XmlDeclaration:
|
||||
// For various reasons, not all serializations have xml declarations (or consistent ones)
|
||||
// and as it's embedded inside a byte stream we don't need it anyway, so ignore.
|
||||
break;
|
||||
|
||||
default:
|
||||
m_log.WarnFormat(
|
||||
"[HG ASSET MAPPER]: Unrecognized node {0} in asset XML transform in {1}",
|
||||
reader.NodeType, sceneName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string CalcCreatorData(string homeURL, string name)
|
||||
{
|
||||
return homeURL + ";" + name;
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -292,11 +292,11 @@ namespace OpenSim.Framework.Servers
|
|||
+ " 3 = full stack trace, including common threads\n",
|
||||
HandleDebugThreadpoolLevel);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug", false, "show threadpool calls active",
|
||||
"show threadpool calls active",
|
||||
"Show details about threadpool calls that are still active (currently waiting or in progress)",
|
||||
HandleShowThreadpoolCallsActive);
|
||||
// m_console.Commands.AddCommand(
|
||||
// "Debug", false, "show threadpool calls active",
|
||||
// "show threadpool calls active",
|
||||
// "Show details about threadpool calls that are still active (currently waiting or in progress)",
|
||||
// HandleShowThreadpoolCallsActive);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Debug", false, "show threadpool calls complete",
|
||||
|
|
|
@ -30,7 +30,7 @@ using Mono.Addins;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
[assembly: AddinRoot("OpenSim", OpenSim.VersionInfo.VersionNumber)]
|
||||
[assembly: ImportAddinAssembly("OpenSim.Framework.dll")]
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -201,11 +201,12 @@ namespace OpenSim.Region.ClientStack.Linden
|
|||
|
||||
Scene.EventManager.OnRegisterCaps += RegisterCaps;
|
||||
|
||||
int nworkers = 2; // was 2
|
||||
if (ProcessQueuedRequestsAsync && m_workerThreads == null)
|
||||
{
|
||||
m_workerThreads = new Thread[2];
|
||||
m_workerThreads = new Thread[nworkers];
|
||||
|
||||
for (uint i = 0; i < 2; i++)
|
||||
for (uint i = 0; i < nworkers; i++)
|
||||
{
|
||||
m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests,
|
||||
String.Format("InventoryWorkerThread{0}", i),
|
||||
|
@ -364,7 +365,11 @@ namespace OpenSim.Region.ClientStack.Linden
|
|||
requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
|
||||
|
||||
lock (responses)
|
||||
{
|
||||
if (responses.ContainsKey(requestID))
|
||||
m_log.WarnFormat("[FETCH INVENTORY DESCENDENTS2 MODULE]: Caught in the act of loosing responses! Please report this on mantis #7054");
|
||||
responses[requestID] = response;
|
||||
}
|
||||
|
||||
WebFetchInvDescModule.ProcessedRequestsCount++;
|
||||
}
|
||||
|
|
|
@ -3747,6 +3747,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
avp.Sender.IsTrial = false;
|
||||
avp.Sender.ID = agentID;
|
||||
avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0];
|
||||
avp.AppearanceHover = new AvatarAppearancePacket.AppearanceHoverBlock[0];
|
||||
//m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
|
||||
OutPacket(avp, ThrottleOutPacketType.Task);
|
||||
}
|
||||
|
@ -4465,7 +4466,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
{
|
||||
uint priority = 0; // time based ordering only
|
||||
lock (m_entityProps.SyncRoot)
|
||||
m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false));
|
||||
m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,true));
|
||||
}
|
||||
|
||||
private void ResendPropertyUpdate(ObjectPropertyUpdate update)
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ using System.Xml;
|
|||
using log4net;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Serialization.External;
|
||||
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Region.Framework.Scenes.Serialization;
|
||||
|
@ -189,217 +190,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
|||
return Utils.StringToBytes(RewriteSOP(xml));
|
||||
}
|
||||
|
||||
protected void TransformXml(XmlReader reader, XmlWriter writer)
|
||||
{
|
||||
// m_log.DebugFormat("[HG ASSET MAPPER]: Transforming XML");
|
||||
|
||||
int sopDepth = -1;
|
||||
UserAccount creator = null;
|
||||
bool hasCreatorData = false;
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
// Console.WriteLine("Depth: {0}, name {1}", reader.Depth, reader.Name);
|
||||
|
||||
switch (reader.NodeType)
|
||||
{
|
||||
case XmlNodeType.Attribute:
|
||||
// Console.WriteLine("FOUND ATTRIBUTE {0}", reader.Name);
|
||||
writer.WriteAttributeString(reader.Prefix, reader.Name, reader.NamespaceURI, reader.Value);
|
||||
break;
|
||||
|
||||
case XmlNodeType.CDATA:
|
||||
writer.WriteCData(reader.Value);
|
||||
break;
|
||||
|
||||
case XmlNodeType.Comment:
|
||||
writer.WriteComment(reader.Value);
|
||||
break;
|
||||
|
||||
case XmlNodeType.DocumentType:
|
||||
writer.WriteDocType(reader.Name, reader.Value, null, null);
|
||||
break;
|
||||
|
||||
case XmlNodeType.Element:
|
||||
// m_log.DebugFormat("Depth {0} at element {1}", reader.Depth, reader.Name);
|
||||
|
||||
writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
|
||||
|
||||
if (reader.HasAttributes)
|
||||
{
|
||||
while (reader.MoveToNextAttribute())
|
||||
writer.WriteAttributeString(reader.Prefix, reader.Name, reader.NamespaceURI, reader.Value);
|
||||
|
||||
reader.MoveToElement();
|
||||
}
|
||||
|
||||
if (reader.LocalName == "SceneObjectPart")
|
||||
{
|
||||
if (sopDepth < 0)
|
||||
{
|
||||
sopDepth = reader.Depth;
|
||||
// m_log.DebugFormat("[HG ASSET MAPPER]: Set sopDepth to {0}", sopDepth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sopDepth >= 0 && reader.Depth == sopDepth + 1)
|
||||
{
|
||||
if (reader.Name == "CreatorID")
|
||||
{
|
||||
reader.Read();
|
||||
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Guid" || reader.Name == "UUID")
|
||||
{
|
||||
reader.Read();
|
||||
|
||||
if (reader.NodeType == XmlNodeType.Text)
|
||||
{
|
||||
UUID uuid = UUID.Zero;
|
||||
UUID.TryParse(reader.Value, out uuid);
|
||||
creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid);
|
||||
writer.WriteElementString("UUID", reader.Value);
|
||||
reader.Read();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we unexpected run across mixed content in this node, still carry on
|
||||
// transforming the subtree (this replicates earlier behaviour).
|
||||
TransformXml(reader, writer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we unexpected run across mixed content in this node, still carry on
|
||||
// transforming the subtree (this replicates earlier behaviour).
|
||||
TransformXml(reader, writer);
|
||||
}
|
||||
}
|
||||
else if (reader.Name == "CreatorData")
|
||||
{
|
||||
reader.Read();
|
||||
if (reader.NodeType == XmlNodeType.Text)
|
||||
{
|
||||
hasCreatorData = true;
|
||||
writer.WriteString(reader.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we unexpected run across mixed content in this node, still carry on
|
||||
// transforming the subtree (this replicates earlier behaviour).
|
||||
TransformXml(reader, writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
// m_log.DebugFormat("[HG ASSET MAPPER]: Writing end for empty element {0}", reader.Name);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case XmlNodeType.EndElement:
|
||||
// m_log.DebugFormat("Depth {0} at EndElement", reader.Depth);
|
||||
if (sopDepth == reader.Depth)
|
||||
{
|
||||
if (!hasCreatorData && creator != null)
|
||||
writer.WriteElementString(reader.Prefix, "CreatorData", reader.NamespaceURI, string.Format("{0};{1} {2}", m_HomeURI, creator.FirstName, creator.LastName));
|
||||
|
||||
// m_log.DebugFormat("[HG ASSET MAPPER]: Reset sopDepth");
|
||||
sopDepth = -1;
|
||||
creator = null;
|
||||
hasCreatorData = false;
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
break;
|
||||
|
||||
case XmlNodeType.EntityReference:
|
||||
writer.WriteEntityRef(reader.Name);
|
||||
break;
|
||||
|
||||
case XmlNodeType.ProcessingInstruction:
|
||||
writer.WriteProcessingInstruction(reader.Name, reader.Value);
|
||||
break;
|
||||
|
||||
case XmlNodeType.Text:
|
||||
writer.WriteString(reader.Value);
|
||||
break;
|
||||
|
||||
case XmlNodeType.XmlDeclaration:
|
||||
// For various reasons, not all serializations have xml declarations (or consistent ones)
|
||||
// and as it's embedded inside a byte stream we don't need it anyway, so ignore.
|
||||
break;
|
||||
|
||||
default:
|
||||
m_log.WarnFormat(
|
||||
"[HG ASSET MAPPER]: Unrecognized node {0} in asset XML transform in {1}",
|
||||
reader.NodeType, m_scene.Name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected string RewriteSOP(string xmlData)
|
||||
{
|
||||
// Console.WriteLine("Input XML [{0}]", xmlData);
|
||||
return ExternalRepresentationUtils.RewriteSOP(xmlData, m_scene.Name, m_HomeURI, m_scene.UserAccountService, m_scene.RegionInfo.ScopeID);
|
||||
|
||||
using (StringWriter sw = new StringWriter())
|
||||
using (XmlTextWriter writer = new XmlTextWriter(sw))
|
||||
using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null))
|
||||
using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment }))
|
||||
{
|
||||
TransformXml(reader, writer);
|
||||
|
||||
// Console.WriteLine("Output: [{0}]", sw.ToString());
|
||||
|
||||
return sw.ToString();
|
||||
}
|
||||
|
||||
// We are now taking the more complex streaming approach above because some assets can be very large
|
||||
// and can trigger higher CPU use or possibly memory problems.
|
||||
// XmlDocument doc = new XmlDocument();
|
||||
// doc.LoadXml(xml);
|
||||
// XmlNodeList sops = doc.GetElementsByTagName("SceneObjectPart");
|
||||
//
|
||||
// foreach (XmlNode sop in sops)
|
||||
// {
|
||||
// UserAccount creator = null;
|
||||
// bool hasCreatorData = false;
|
||||
// XmlNodeList nodes = sop.ChildNodes;
|
||||
// foreach (XmlNode node in nodes)
|
||||
// {
|
||||
// if (node.Name == "CreatorID")
|
||||
// {
|
||||
// UUID uuid = UUID.Zero;
|
||||
// UUID.TryParse(node.InnerText, out uuid);
|
||||
// creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid);
|
||||
// }
|
||||
// if (node.Name == "CreatorData" && node.InnerText != null && node.InnerText != string.Empty)
|
||||
// hasCreatorData = true;
|
||||
//
|
||||
// //if (node.Name == "OwnerID")
|
||||
// //{
|
||||
// // UserAccount owner = GetUser(node.InnerText);
|
||||
// // if (owner != null)
|
||||
// // node.InnerText = m_ProfileServiceURL + "/" + node.InnerText + "/" + owner.FirstName + " " + owner.LastName;
|
||||
// //}
|
||||
// }
|
||||
//
|
||||
// if (!hasCreatorData && creator != null)
|
||||
// {
|
||||
// XmlElement creatorData = doc.CreateElement("CreatorData");
|
||||
// creatorData.InnerText = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName;
|
||||
// sop.AppendChild(creatorData);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// using (StringWriter wr = new StringWriter())
|
||||
// {
|
||||
// doc.Save(wr);
|
||||
// return wr.ToString();
|
||||
// }
|
||||
}
|
||||
|
||||
// TODO: unused
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library
|
|||
{
|
||||
InventoryFolderImpl folder = null;
|
||||
InventoryCollection inv = new InventoryCollection();
|
||||
inv.UserID = m_Library.Owner;
|
||||
inv.OwnerID = m_Library.Owner;
|
||||
|
||||
if (folderID != m_Library.ID)
|
||||
{
|
||||
|
@ -87,6 +87,34 @@ namespace OpenSim.Region.CoreModules.Framework.Library
|
|||
return inv;
|
||||
}
|
||||
|
||||
public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
|
||||
{
|
||||
InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length];
|
||||
int i = 0;
|
||||
foreach (UUID fid in folderIDs)
|
||||
{
|
||||
invColl[i++] = GetFolderContent(principalID, fid);
|
||||
}
|
||||
|
||||
return invColl;
|
||||
}
|
||||
|
||||
public virtual InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs)
|
||||
{
|
||||
InventoryItemBase[] itemColl = new InventoryItemBase[itemIDs.Length];
|
||||
int i = 0;
|
||||
InventoryItemBase item = new InventoryItemBase();
|
||||
item.Owner = principalID;
|
||||
foreach (UUID fid in itemIDs)
|
||||
{
|
||||
item.ID = fid;
|
||||
itemColl[i++] = GetItem(item);
|
||||
}
|
||||
|
||||
return itemColl;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Add a new folder to the user's inventory
|
||||
/// </summary>
|
||||
|
|
|
@ -154,7 +154,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
|||
|
||||
#endregion ISharedRegionModule
|
||||
|
||||
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
void EventManager_OnPrimsLoaded(Scene s)
|
||||
|
@ -180,7 +180,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
|||
void HandleUUIDNameRequest(UUID uuid, IClientAPI client)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}",
|
||||
// "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}",
|
||||
// uuid, remote_client.Name);
|
||||
|
||||
if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid))
|
||||
|
@ -212,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
|||
// appear to clear this when the user asks it to clear the cache, but others may not.
|
||||
//
|
||||
// So to avoid clients
|
||||
// (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will
|
||||
// (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will
|
||||
// instead drop the request entirely.
|
||||
if (GetUser(uuid, out user))
|
||||
{
|
||||
|
@ -220,7 +220,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
|||
}
|
||||
// else
|
||||
// m_log.DebugFormat(
|
||||
// "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}",
|
||||
// "[USER MANAGEMENT MODULE]: No bound name for {0} found, ignoring request from {1}",
|
||||
// uuid, client.Name);
|
||||
});
|
||||
}
|
||||
|
@ -416,7 +416,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
|||
m_log.Debug("[USER MANAGEMENT MODULE]: GetServerURLs call failed ", e);
|
||||
userdata.ServerURLs = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
|
||||
if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
|
||||
return userdata.ServerURLs[serverType].ToString();
|
||||
}
|
||||
|
@ -620,7 +620,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
|||
AddUser(id, string.Empty, string.Empty, string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
string homeURL;
|
||||
string firstname = string.Empty;
|
||||
string lastname = string.Empty;
|
||||
|
@ -676,7 +676,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
|||
else
|
||||
{
|
||||
lock(m_UserCache)
|
||||
{
|
||||
{
|
||||
if(!m_UserCache.ContainsKey(id))
|
||||
{
|
||||
UserData newUser = new UserData();
|
||||
|
@ -726,6 +726,21 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
|||
"Show the bindings between user UUIDs and user names",
|
||||
String.Empty,
|
||||
HandleShowUsers);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand("Users", true,
|
||||
"reset user cache",
|
||||
"reset user cache",
|
||||
"reset user cache to allow changed settings to be applied",
|
||||
String.Empty,
|
||||
HandleResetUserCache);
|
||||
}
|
||||
|
||||
private void HandleResetUserCache(string module, string[] cmd)
|
||||
{
|
||||
lock(m_UserCache)
|
||||
{
|
||||
m_UserCache.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleShowUser(string module, string[] cmd)
|
||||
|
|
|
@ -30,7 +30,7 @@ using Mono.Addins;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
||||
[assembly: Addin("OpenSim.Region.CoreModules", OpenSim.VersionInfo.VersionNumber)]
|
||||
|
|
|
@ -389,6 +389,25 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
|
|||
return connector.GetFolderContent(userID, folderID);
|
||||
}
|
||||
|
||||
public InventoryCollection[] GetMultipleFoldersContent(UUID userID, UUID[] folderIDs)
|
||||
{
|
||||
string invURL = GetInventoryServiceURL(userID);
|
||||
|
||||
if (invURL == null) // not there, forward to local inventory connector to resolve
|
||||
lock (m_Lock)
|
||||
return m_LocalGridInventoryService.GetMultipleFoldersContent(userID, folderIDs);
|
||||
|
||||
else
|
||||
{
|
||||
InventoryCollection[] coll = new InventoryCollection[folderIDs.Length];
|
||||
int i = 0;
|
||||
foreach (UUID fid in folderIDs)
|
||||
coll[i++] = GetFolderContent(userID, fid);
|
||||
|
||||
return coll;
|
||||
}
|
||||
}
|
||||
|
||||
public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
|
||||
{
|
||||
//m_log.Debug("[HG INVENTORY CONNECTOR]: GetFolderItems " + folderID);
|
||||
|
@ -596,6 +615,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
|
|||
return connector.GetItem(item);
|
||||
}
|
||||
|
||||
public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs)
|
||||
{
|
||||
if (itemIDs == null)
|
||||
return new InventoryItemBase[0];
|
||||
//m_log.Debug("[HG INVENTORY CONNECTOR]: GetItem " + item.ID);
|
||||
|
||||
string invURL = GetInventoryServiceURL(userID);
|
||||
|
||||
if (invURL == null) // not there, forward to local inventory connector to resolve
|
||||
lock (m_Lock)
|
||||
return m_LocalGridInventoryService.GetMultipleItems(userID, itemIDs);
|
||||
|
||||
IInventoryService connector = GetConnector(invURL);
|
||||
|
||||
return connector.GetMultipleItems(userID, itemIDs);
|
||||
}
|
||||
|
||||
public InventoryFolderBase GetFolder(InventoryFolderBase folder)
|
||||
{
|
||||
if (folder == null)
|
||||
|
|
|
@ -106,7 +106,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
|
|||
if (m_Inventories.TryGetValue(userID, out inv))
|
||||
{
|
||||
c = new InventoryCollection();
|
||||
c.UserID = userID;
|
||||
c.OwnerID = userID;
|
||||
|
||||
c.Folders = inv.Folders.FindAll(delegate(InventoryFolderBase f)
|
||||
{
|
||||
|
|
|
@ -195,6 +195,19 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
|
|||
return invCol;
|
||||
}
|
||||
|
||||
public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
|
||||
{
|
||||
InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length];
|
||||
int i = 0;
|
||||
foreach (UUID fid in folderIDs)
|
||||
{
|
||||
invColl[i++] = GetFolderContent(principalID, fid);
|
||||
}
|
||||
|
||||
return invColl;
|
||||
|
||||
}
|
||||
|
||||
public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
|
||||
{
|
||||
return m_InventoryService.GetFolderItems(userID, folderID);
|
||||
|
@ -294,6 +307,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
|
|||
return item;
|
||||
}
|
||||
|
||||
public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs)
|
||||
{
|
||||
return m_InventoryService.GetMultipleItems(userID, itemIDs);
|
||||
}
|
||||
|
||||
public InventoryFolderBase GetFolder(InventoryFolderBase folder)
|
||||
{
|
||||
return m_InventoryService.GetFolder(folder);
|
||||
|
|
|
@ -204,6 +204,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
|
|||
return invCol;
|
||||
}
|
||||
|
||||
public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
|
||||
{
|
||||
return m_RemoteConnector.GetMultipleFoldersContent(principalID, folderIDs);
|
||||
}
|
||||
|
||||
public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
|
||||
{
|
||||
return m_RemoteConnector.GetFolderItems(userID, folderID);
|
||||
|
@ -298,6 +303,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
|
|||
return m_RemoteConnector.GetItem(item);
|
||||
}
|
||||
|
||||
public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs)
|
||||
{
|
||||
if (itemIDs == null)
|
||||
return new InventoryItemBase[0];
|
||||
|
||||
return m_RemoteConnector.GetMultipleItems(userID, itemIDs);
|
||||
}
|
||||
|
||||
public InventoryFolderBase GetFolder(InventoryFolderBase folder)
|
||||
{
|
||||
//m_log.DebugFormat("[XINVENTORY CONNECTOR]: GetFolder {0}", folder.ID);
|
||||
|
|
|
@ -335,7 +335,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
|||
if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home"))
|
||||
{
|
||||
//m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID);
|
||||
string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), m_options["home"].ToString(), m_userAccountService, m_scopeID);
|
||||
string xml = ExternalRepresentationUtils.RewriteSOP(Utils.BytesToString(asset.Data), string.Empty, m_options["home"].ToString(), m_userAccountService, m_scopeID);
|
||||
asset.Data = Utils.StringToBytes(xml);
|
||||
}
|
||||
return asset;
|
||||
|
|
|
@ -98,11 +98,17 @@ namespace OpenSim.Region.CoreModules.World.Land
|
|||
// caches ExtendedLandData
|
||||
private Cache parcelInfoCache;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions.
|
||||
/// </summary>
|
||||
private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>();
|
||||
|
||||
// Enables limiting parcel layer info transmission when doing simple updates
|
||||
private bool shouldLimitParcelLayerInfoToViewDistance { get; set; }
|
||||
// "View distance" for sending parcel layer info if asked for from a view point in the region
|
||||
private int parcelLayerViewDistance { get; set; }
|
||||
|
||||
#region INonSharedRegionModule Members
|
||||
|
||||
public Type ReplaceableInterface
|
||||
|
@ -112,6 +118,14 @@ namespace OpenSim.Region.CoreModules.World.Land
|
|||
|
||||
public void Initialise(IConfigSource source)
|
||||
{
|
||||
shouldLimitParcelLayerInfoToViewDistance = true;
|
||||
parcelLayerViewDistance = 128;
|
||||
IConfig landManagementConfig = source.Configs["LandManagement"];
|
||||
if (landManagementConfig != null)
|
||||
{
|
||||
shouldLimitParcelLayerInfoToViewDistance = landManagementConfig.GetBoolean("LimitParcelLayerUpdateDistance", shouldLimitParcelLayerInfoToViewDistance);
|
||||
parcelLayerViewDistance = landManagementConfig.GetInt("ParcelLayerViewDistance", parcelLayerViewDistance);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddRegion(Scene scene)
|
||||
|
@ -1129,11 +1143,26 @@ namespace OpenSim.Region.CoreModules.World.Land
|
|||
|
||||
#region Parcel Updating
|
||||
|
||||
// Send parcel layer info for the whole region
|
||||
public void SendParcelOverlay(IClientAPI remote_client)
|
||||
{
|
||||
SendParcelOverlay(remote_client, 0, 0, (int)Constants.MaximumRegionSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Where we send the ParcelOverlay packet to the client
|
||||
/// Send the parcel overlay blocks to the client. We send the overlay packets
|
||||
/// around a location and limited by the 'parcelLayerViewDistance'. This number
|
||||
/// is usually 128 and the code is arranged so it sends all the parcel overlay
|
||||
/// information for a whole region if the region is legacy sized (256x256). If
|
||||
/// the region is larger, only the parcel layer information is sent around
|
||||
/// the point specified. This reduces the problem of parcel layer information
|
||||
/// blocks increasing exponentially as region size increases.
|
||||
/// </summary>
|
||||
/// <param name="remote_client">The object representing the client</param>
|
||||
public void SendParcelOverlay(IClientAPI remote_client)
|
||||
/// <param name="xPlace">X position in the region to send surrounding parcel layer info</param>
|
||||
/// <param name="yPlace">y position in the region to send surrounding parcel layer info</param>
|
||||
/// <param name="layerViewDistance">Distance from x,y position to send parcel layer info</param>
|
||||
private void SendParcelOverlay(IClientAPI remote_client, int xPlace, int yPlace, int layerViewDistance)
|
||||
{
|
||||
const int LAND_BLOCKS_PER_PACKET = 1024;
|
||||
|
||||
|
@ -1141,15 +1170,58 @@ namespace OpenSim.Region.CoreModules.World.Land
|
|||
int byteArrayCount = 0;
|
||||
int sequenceID = 0;
|
||||
|
||||
// Layer data is in landUnit (4m) chunks
|
||||
for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++)
|
||||
int xLow = 0;
|
||||
int xHigh = (int)m_scene.RegionInfo.RegionSizeX;
|
||||
int yLow = 0;
|
||||
int yHigh = (int)m_scene.RegionInfo.RegionSizeY;
|
||||
|
||||
if (shouldLimitParcelLayerInfoToViewDistance)
|
||||
{
|
||||
for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++)
|
||||
// Compute view distance around the given point
|
||||
int txLow = xPlace - layerViewDistance;
|
||||
int txHigh = xPlace + layerViewDistance;
|
||||
// If the distance is outside the region area, move the view distance to ba all in the region
|
||||
if (txLow < xLow)
|
||||
{
|
||||
txLow = xLow;
|
||||
txHigh = Math.Min(yLow + (layerViewDistance * 2), xHigh);
|
||||
}
|
||||
if (txHigh > xHigh)
|
||||
{
|
||||
txLow = Math.Max(xLow, xHigh - (layerViewDistance * 2));
|
||||
txHigh = xHigh;
|
||||
}
|
||||
xLow = txLow;
|
||||
xHigh = txHigh;
|
||||
|
||||
int tyLow = yPlace - layerViewDistance;
|
||||
int tyHigh = yPlace + layerViewDistance;
|
||||
if (tyLow < yLow)
|
||||
{
|
||||
tyLow = yLow;
|
||||
tyHigh = Math.Min(yLow + (layerViewDistance * 2), yHigh);
|
||||
}
|
||||
if (tyHigh > yHigh)
|
||||
{
|
||||
tyLow = Math.Max(yLow, yHigh - (layerViewDistance * 2));
|
||||
tyHigh = yHigh;
|
||||
}
|
||||
yLow = tyLow;
|
||||
yHigh = tyHigh;
|
||||
}
|
||||
// m_log.DebugFormat("{0} SendParcelOverlay: place=<{1},{2}>, vDist={3}, xLH=<{4},{5}, yLH=<{6},{7}>",
|
||||
// LogHeader, xPlace, yPlace, layerViewDistance, xLow, xHigh, yLow, yHigh);
|
||||
|
||||
// Layer data is in landUnit (4m) chunks
|
||||
for (int y = yLow; y < yHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++)
|
||||
{
|
||||
for (int x = xLow; x < xHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++)
|
||||
{
|
||||
byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * LandUnit, y * LandUnit), x, y, remote_client);
|
||||
byteArrayCount++;
|
||||
if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
|
||||
{
|
||||
// m_log.DebugFormat("{0} SendParcelOverlay, sending packet, bytes={1}", LogHeader, byteArray.Length);
|
||||
remote_client.SendLandParcelOverlay(byteArray, sequenceID);
|
||||
byteArrayCount = 0;
|
||||
sequenceID++;
|
||||
|
@ -1162,6 +1234,7 @@ namespace OpenSim.Region.CoreModules.World.Land
|
|||
if (byteArrayCount != 0)
|
||||
{
|
||||
remote_client.SendLandParcelOverlay(byteArray, sequenceID);
|
||||
// m_log.DebugFormat("{0} SendParcelOverlay, complete sending packet, bytes={1}", LogHeader, byteArray.Length);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1265,7 +1338,8 @@ namespace OpenSim.Region.CoreModules.World.Land
|
|||
temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
|
||||
}
|
||||
|
||||
SendParcelOverlay(remote_client);
|
||||
// Also send the layer data around the point of interest
|
||||
SendParcelOverlay(remote_client, (start_x + end_x) / 2, (start_y + end_y) / 2, parcelLayerViewDistance);
|
||||
}
|
||||
|
||||
public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client)
|
||||
|
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using OpenSim.Region.CoreModules.World.Terrain;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Terrain.Features
|
||||
{
|
||||
public class RectangleFeature : TerrainFeature
|
||||
{
|
||||
public RectangleFeature(ITerrainModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
public override string CreateFeature(ITerrainChannel map, string[] args)
|
||||
{
|
||||
string val;
|
||||
string result;
|
||||
if (args.Length < 7)
|
||||
{
|
||||
result = "Usage: " + GetUsage();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = String.Empty;
|
||||
|
||||
float targetElevation;
|
||||
val = base.parseFloat(args[3], out targetElevation);
|
||||
if (val != String.Empty)
|
||||
{
|
||||
result = val;
|
||||
}
|
||||
|
||||
int xOrigin;
|
||||
val = base.parseInt(args[4], out xOrigin);
|
||||
if (val != String.Empty)
|
||||
{
|
||||
result = val;
|
||||
}
|
||||
else if (xOrigin < 0 || xOrigin >= map.Width)
|
||||
{
|
||||
result = "x-origin must be within the region";
|
||||
}
|
||||
|
||||
int yOrigin;
|
||||
val = base.parseInt(args[5], out yOrigin);
|
||||
if (val != String.Empty)
|
||||
{
|
||||
result = val;
|
||||
}
|
||||
else if (yOrigin < 0 || yOrigin >= map.Height)
|
||||
{
|
||||
result = "y-origin must be within the region";
|
||||
}
|
||||
|
||||
int xDelta;
|
||||
val = base.parseInt(args[6], out xDelta);
|
||||
if (val != String.Empty)
|
||||
{
|
||||
result = val;
|
||||
}
|
||||
else if (xDelta <= 0)
|
||||
{
|
||||
result = "x-size must be greater than zero";
|
||||
}
|
||||
|
||||
int yDelta;
|
||||
if (args.Length > 7)
|
||||
{
|
||||
val = base.parseInt(args[7], out yDelta);
|
||||
if (val != String.Empty)
|
||||
{
|
||||
result = val;
|
||||
}
|
||||
else if (yDelta <= 0)
|
||||
{
|
||||
result = "y-size must be greater than zero";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no y-size.. make it square
|
||||
yDelta = xDelta;
|
||||
}
|
||||
|
||||
// slightly more complex validation, if required.
|
||||
if (result == String.Empty)
|
||||
{
|
||||
if (xOrigin + xDelta > map.Width)
|
||||
{
|
||||
result = "(x-origin + x-size) must be within the region size";
|
||||
}
|
||||
else if (yOrigin + yDelta > map.Height)
|
||||
{
|
||||
result = "(y-origin + y-size) must be within the region size";
|
||||
}
|
||||
}
|
||||
|
||||
// if it's all good, then do the work
|
||||
if (result == String.Empty)
|
||||
{
|
||||
int yPos = yOrigin + yDelta;
|
||||
while(--yPos >= yOrigin)
|
||||
{
|
||||
int xPos = xOrigin + xDelta;
|
||||
while(--xPos >= xOrigin)
|
||||
{
|
||||
map[xPos, yPos] = (double)targetElevation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string GetUsage()
|
||||
{
|
||||
return "rectangle <height> <x-origin> <y-origin> <x-size> [<y-size>]";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -24,65 +24,53 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
using System;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
{
|
||||
public abstract class TerrainFeature : ITerrainFeature
|
||||
public interface ITerrainModifier
|
||||
{
|
||||
protected ITerrainModule m_module;
|
||||
/// <summary>
|
||||
/// Creates the feature.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Empty string if successful, otherwise error message.
|
||||
/// </returns>
|
||||
/// <param name='map'>
|
||||
/// ITerrainChannel holding terrain data.
|
||||
/// </param>
|
||||
/// <param name='args'>
|
||||
/// command-line arguments from console.
|
||||
/// </param>
|
||||
string ModifyTerrain(ITerrainChannel map, string[] args);
|
||||
|
||||
protected TerrainFeature(ITerrainModule module)
|
||||
{
|
||||
m_module = module;
|
||||
}
|
||||
|
||||
public abstract string CreateFeature(ITerrainChannel map, string[] args);
|
||||
|
||||
public abstract string GetUsage();
|
||||
|
||||
protected string parseFloat(String s, out float f)
|
||||
{
|
||||
string result;
|
||||
double d;
|
||||
if (Double.TryParse(s, out d))
|
||||
{
|
||||
try
|
||||
{
|
||||
f = (float)d;
|
||||
result = String.Empty;
|
||||
}
|
||||
catch(InvalidCastException)
|
||||
{
|
||||
result = String.Format("{0} is invalid", s);
|
||||
f = -1.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
f = -1.0f;
|
||||
result = String.Format("{0} is invalid", s);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected string parseInt(String s, out int i)
|
||||
{
|
||||
string result;
|
||||
if (Int32.TryParse(s, out i))
|
||||
{
|
||||
result = String.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = String.Format("{0} is invalid", s);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a string describing the usage.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A string describing parameters for creating the feature.
|
||||
/// Format is "feature-name <arg1> <arg2> ..."
|
||||
/// </returns>
|
||||
string GetUsage();
|
||||
|
||||
/// <summary>
|
||||
/// Apply the appropriate operation on the specified map, at (x, y).
|
||||
/// </summary>
|
||||
/// <param name='map'>
|
||||
/// Map.
|
||||
/// </param>
|
||||
/// <param name='data'>
|
||||
/// Data.
|
||||
/// </param>
|
||||
/// <param name='x'>
|
||||
/// X.
|
||||
/// </param>
|
||||
/// <param name='y'>
|
||||
/// Y.
|
||||
/// </param>
|
||||
double operate(double[,] map, TerrainModifierData data, int x, int y);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
using System;
|
||||
|
||||
using OpenSim.Region.CoreModules.World.Terrain;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
|
||||
{
|
||||
public class FillModifier : TerrainModifier
|
||||
{
|
||||
|
||||
public FillModifier(ITerrainModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ModifyTerrain(ITerrainChannel map, string[] args)
|
||||
{
|
||||
string result;
|
||||
if (args.Length < 3)
|
||||
{
|
||||
result = "Usage: " + GetUsage();
|
||||
}
|
||||
else
|
||||
{
|
||||
TerrainModifierData data;
|
||||
result = this.parseParameters(args, out data);
|
||||
|
||||
// Context-specific validation
|
||||
if (result == String.Empty)
|
||||
{
|
||||
if (data.shape == String.Empty)
|
||||
{
|
||||
data.shape = "rectangle";
|
||||
data.x0 = 0;
|
||||
data.y0 = 0;
|
||||
data.dx = map.Width;
|
||||
data.dy = map.Height;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's all good, then do the work
|
||||
if (result == String.Empty)
|
||||
{
|
||||
this.applyModification(map, data);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string GetUsage()
|
||||
{
|
||||
string val = "fill <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]"
|
||||
+ "\nSets all points within the specified range to the specified value.";
|
||||
return val;
|
||||
}
|
||||
|
||||
public override double operate(double[,] map, TerrainModifierData data, int x, int y)
|
||||
{
|
||||
double factor = this.computeBevel(data, x, y);
|
||||
double result = data.elevation - (data.elevation - data.bevelevation) * factor;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
using System;
|
||||
using OpenSim.Region.CoreModules.World.Terrain;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
|
||||
{
|
||||
public class LowerModifier : TerrainModifier
|
||||
{
|
||||
public LowerModifier(ITerrainModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ModifyTerrain(ITerrainChannel map, string[] args)
|
||||
{
|
||||
string result;
|
||||
if (args.Length < 3)
|
||||
{
|
||||
result = "Usage: " + GetUsage();
|
||||
}
|
||||
else
|
||||
{
|
||||
TerrainModifierData data;
|
||||
result = this.parseParameters(args, out data);
|
||||
|
||||
// Context-specific validation
|
||||
if (result == String.Empty)
|
||||
{
|
||||
if (data.shape == String.Empty)
|
||||
{
|
||||
data.shape = "rectangle";
|
||||
data.x0 = 0;
|
||||
data.y0 = 0;
|
||||
data.dx = map.Width;
|
||||
data.dy = map.Height;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's all good, then do the work
|
||||
if (result == String.Empty)
|
||||
{
|
||||
this.applyModification(map, data);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string GetUsage()
|
||||
{
|
||||
string val = "lower <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]"
|
||||
+ "\nLowers all points within the specified range by the specified amount.";
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
public override double operate(double[,] map, TerrainModifierData data, int x, int y)
|
||||
{
|
||||
double factor = this.computeBevel(data, x, y);
|
||||
double result = map[x, y] - (data.elevation - (data.elevation - data.bevelevation) * factor);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
using System;
|
||||
using OpenSim.Region.CoreModules.World.Terrain;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
|
||||
{
|
||||
public class MaxModifier : TerrainModifier
|
||||
{
|
||||
public MaxModifier(ITerrainModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ModifyTerrain(ITerrainChannel map, string[] args)
|
||||
{
|
||||
string result;
|
||||
if (args.Length < 3)
|
||||
{
|
||||
result = "Usage: " + GetUsage();
|
||||
}
|
||||
else
|
||||
{
|
||||
TerrainModifierData data;
|
||||
result = this.parseParameters(args, out data);
|
||||
|
||||
// Context-specific validation
|
||||
if (result == String.Empty)
|
||||
{
|
||||
if (data.shape == String.Empty)
|
||||
{
|
||||
data.shape = "rectangle";
|
||||
data.x0 = 0;
|
||||
data.y0 = 0;
|
||||
data.dx = map.Width;
|
||||
data.dy = map.Height;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's all good, then do the work
|
||||
if (result == String.Empty)
|
||||
{
|
||||
this.applyModification(map, data);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string GetUsage()
|
||||
{
|
||||
string val = "max <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]"
|
||||
+ "\nEnsures that all points within the specified range are no higher than the specified value.";
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
public override double operate(double[,] map, TerrainModifierData data, int x, int y)
|
||||
{
|
||||
double factor = this.computeBevel(data, x, y);
|
||||
double result = Math.Min(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
using System;
|
||||
using OpenSim.Region.CoreModules.World.Terrain;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
|
||||
{
|
||||
public class MinModifier : TerrainModifier
|
||||
{
|
||||
public MinModifier(ITerrainModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ModifyTerrain(ITerrainChannel map, string[] args)
|
||||
{
|
||||
string result;
|
||||
if (args.Length < 3)
|
||||
{
|
||||
result = "Usage: " + GetUsage();
|
||||
}
|
||||
else
|
||||
{
|
||||
TerrainModifierData data;
|
||||
result = this.parseParameters(args, out data);
|
||||
|
||||
// Context-specific validation
|
||||
if (result == String.Empty)
|
||||
{
|
||||
if (data.shape == String.Empty)
|
||||
{
|
||||
data.shape = "rectangle";
|
||||
data.x0 = 0;
|
||||
data.y0 = 0;
|
||||
data.dx = map.Width;
|
||||
data.dy = map.Height;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's all good, then do the work
|
||||
if (result == String.Empty)
|
||||
{
|
||||
this.applyModification(map, data);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string GetUsage()
|
||||
{
|
||||
string val = "min <height> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<height2>]"
|
||||
+ "\nEnsures that all points within the specified range are no lower than the specified value.";
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
public override double operate(double[,] map, TerrainModifierData data, int x, int y)
|
||||
{
|
||||
double factor = this.computeBevel(data, x, y);
|
||||
double result = Math.Max(data.elevation - (data.elevation - data.bevelevation) * factor, map[x, y]);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
using System;
|
||||
using OpenSim.Region.CoreModules.World.Terrain;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
|
||||
{
|
||||
public class NoiseModifier : TerrainModifier
|
||||
{
|
||||
public NoiseModifier(ITerrainModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ModifyTerrain(ITerrainChannel map, string[] args)
|
||||
{
|
||||
string result;
|
||||
if (args.Length < 3)
|
||||
{
|
||||
result = "Usage: " + GetUsage();
|
||||
}
|
||||
else
|
||||
{
|
||||
TerrainModifierData data;
|
||||
result = this.parseParameters(args, out data);
|
||||
|
||||
// Context-specific validation
|
||||
if (result == String.Empty)
|
||||
{
|
||||
if (data.bevel == "taper")
|
||||
{
|
||||
if (data.bevelevation < 0.0 || data.bevelevation > 1.0)
|
||||
{
|
||||
result = String.Format("Taper must be 0.0 to 1.0: {0}", data.bevelevation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data.bevelevation = 1.0f;
|
||||
}
|
||||
|
||||
if (data.elevation < 0.0 || data.elevation > 1.0)
|
||||
{
|
||||
result = String.Format("Noise strength must be 0.0 to 1.0: {0}", data.elevation);
|
||||
}
|
||||
|
||||
if (data.shape == String.Empty)
|
||||
{
|
||||
data.shape = "rectangle";
|
||||
data.x0 = 0;
|
||||
data.y0 = 0;
|
||||
data.dx = map.Width;
|
||||
data.dy = map.Height;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's all good, then do the work
|
||||
if (result == String.Empty)
|
||||
{
|
||||
this.applyModification(map, data);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string GetUsage()
|
||||
{
|
||||
string val = "noise <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]"
|
||||
+ "\nAdds noise to all points within the specified range.";
|
||||
return val;
|
||||
}
|
||||
|
||||
public override double operate(double[,] map, TerrainModifierData data, int x, int y)
|
||||
{
|
||||
double factor = this.computeBevel(data, x, y);
|
||||
double noise = TerrainUtil.PerlinNoise2D((double)x / map.GetLength(0), (double)y / map.GetLength(1), 8, 1.0);
|
||||
return map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor) * (noise - .5);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
using System;
|
||||
using OpenSim.Region.CoreModules.World.Terrain;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
|
||||
{
|
||||
public class RaiseModifier : TerrainModifier
|
||||
{
|
||||
public RaiseModifier(ITerrainModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ModifyTerrain(ITerrainChannel map, string[] args)
|
||||
{
|
||||
string result;
|
||||
if (args.Length < 3)
|
||||
{
|
||||
result = "Usage: " + GetUsage();
|
||||
}
|
||||
else
|
||||
{
|
||||
TerrainModifierData data;
|
||||
result = this.parseParameters(args, out data);
|
||||
|
||||
// Context-specific validation
|
||||
if (result == String.Empty)
|
||||
{
|
||||
if (data.shape == String.Empty)
|
||||
{
|
||||
data.shape = "rectangle";
|
||||
data.x0 = 0;
|
||||
data.y0 = 0;
|
||||
data.dx = map.Width;
|
||||
data.dy = map.Height;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's all good, then do the work
|
||||
if (result == String.Empty)
|
||||
{
|
||||
this.applyModification(map, data);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string GetUsage()
|
||||
{
|
||||
string val = "raise <delta> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<delta2>]"
|
||||
+ "\nRaises all points within the specified range by the specified amount.";
|
||||
return val;
|
||||
|
||||
}
|
||||
|
||||
public override double operate(double[,] map, TerrainModifierData data, int x, int y)
|
||||
{
|
||||
double factor = this.computeBevel(data, x, y);
|
||||
double result = map[x, y] + (data.elevation - (data.elevation - data.bevelevation) * factor);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
using System;
|
||||
using OpenSim.Region.CoreModules.World.Terrain;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Terrain.Modifiers
|
||||
{
|
||||
public class SmoothModifier : TerrainModifier
|
||||
{
|
||||
public SmoothModifier(ITerrainModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ModifyTerrain(ITerrainChannel map, string[] args)
|
||||
{
|
||||
string result;
|
||||
if (args.Length < 3)
|
||||
{
|
||||
result = "Usage: " + GetUsage();
|
||||
}
|
||||
else
|
||||
{
|
||||
TerrainModifierData data;
|
||||
result = this.parseParameters(args, out data);
|
||||
|
||||
// Context-specific validation
|
||||
if (result == String.Empty)
|
||||
{
|
||||
if (data.bevel == "taper")
|
||||
{
|
||||
if (data.bevelevation < 0.01 || data.bevelevation > 0.99)
|
||||
{
|
||||
result = String.Format("Taper must be 0.01 to 0.99: {0}", data.bevelevation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data.bevelevation = 2.0f / 3.0f;
|
||||
}
|
||||
|
||||
if (data.elevation < 0.0 || data.elevation > 1.0)
|
||||
{
|
||||
result = String.Format("Smoothing strength must be 0.0 to 1.0: {0}", data.elevation);
|
||||
}
|
||||
|
||||
if (data.shape == String.Empty)
|
||||
{
|
||||
data.shape = "rectangle";
|
||||
data.x0 = 0;
|
||||
data.y0 = 0;
|
||||
data.dx = map.Width;
|
||||
data.dy = map.Height;
|
||||
}
|
||||
}
|
||||
|
||||
// if it's all good, then do the work
|
||||
if (result == String.Empty)
|
||||
{
|
||||
this.applyModification(map, data);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string GetUsage()
|
||||
{
|
||||
string val = "smooth <strength> [ -rec=x1,y1,dx[,dy] | -ell=x0,y0,rx[,ry] ] [-taper=<fraction>]"
|
||||
+ "\nSmooths all points within the specified range using a simple averaging algorithm.";
|
||||
return val;
|
||||
}
|
||||
|
||||
public override double operate(double[,] map, TerrainModifierData data, int x, int y)
|
||||
{
|
||||
double[] scale = new double[3];
|
||||
scale[0] = data.elevation;
|
||||
scale[1] = ((1.0 - scale[0]) * data.bevelevation) / 8.0;
|
||||
scale[2] = ((1.0 - scale[0]) * (1.0 - data.bevelevation)) / 16.0;
|
||||
int xMax = map.GetLength(0);
|
||||
int yMax = map.GetLength(1);
|
||||
double result;
|
||||
if ((x == 0) || (y == 0) || (x == (xMax - 1)) || (y == (yMax - 1)))
|
||||
{
|
||||
result = map[x, y];
|
||||
}
|
||||
else
|
||||
{
|
||||
result = 0.0;
|
||||
for(int yPos = (y - 2); yPos < (y + 3); yPos++)
|
||||
{
|
||||
int yVal = (yPos <= 0) ? 0 : ((yPos < yMax) ? yPos : yMax - 1);
|
||||
for(int xPos = (x - 2); xPos < (x + 3); xPos++)
|
||||
{
|
||||
int xVal = (xPos <= 0) ? 0 : ((xPos < xMax) ? xPos : xMax - 1);
|
||||
int dist = Math.Max(Math.Abs(x - xVal), Math.Abs(y - yVal));
|
||||
result += map[xVal, yVal] * scale[dist];
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
{
|
||||
public abstract class TerrainModifier : ITerrainModifier
|
||||
{
|
||||
protected ITerrainModule m_module;
|
||||
protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
protected TerrainModifier(ITerrainModule module)
|
||||
{
|
||||
m_module = module;
|
||||
}
|
||||
|
||||
public abstract string ModifyTerrain(ITerrainChannel map, string[] args);
|
||||
|
||||
public abstract string GetUsage();
|
||||
|
||||
public abstract double operate(double[,] map, TerrainModifierData data, int x, int y);
|
||||
|
||||
protected String parseParameters(string[] args, out TerrainModifierData data)
|
||||
{
|
||||
string val;
|
||||
string arg;
|
||||
string result;
|
||||
data = new TerrainModifierData();
|
||||
data.shape = String.Empty;
|
||||
data.bevel = String.Empty;
|
||||
data.dx = 0;
|
||||
data.dy = 0;
|
||||
if (args.Length < 4)
|
||||
{
|
||||
result = "Usage: " + GetUsage();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = this.parseFloat(args[3], out data.elevation);
|
||||
}
|
||||
if (result == String.Empty)
|
||||
{
|
||||
int index = 3;
|
||||
while(++index < args.Length && result == String.Empty)
|
||||
{
|
||||
arg = args[index];
|
||||
// check for shape
|
||||
if (arg.StartsWith("-rec=") || arg.StartsWith("-ell="))
|
||||
{
|
||||
if (data.shape != String.Empty)
|
||||
{
|
||||
result = "Only 1 '-rec' or '-ell' parameter is permitted.";
|
||||
}
|
||||
else
|
||||
{
|
||||
data.shape = arg.StartsWith("-ell=") ? "ellipse" : "rectangle";
|
||||
val = arg.Substring(arg.IndexOf("=") + 1);
|
||||
string[] coords = val.Split(new char[] {','});
|
||||
if ((coords.Length < 3) || (coords.Length > 4))
|
||||
{
|
||||
result = String.Format("Bad format for shape parameter {0}", arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = this.parseInt(coords[0], out data.x0);
|
||||
if (result == String.Empty)
|
||||
{
|
||||
result = this.parseInt(coords[1], out data.y0);
|
||||
}
|
||||
if (result == String.Empty)
|
||||
{
|
||||
result = this.parseInt(coords[2], out data.dx);
|
||||
}
|
||||
if (result == String.Empty)
|
||||
{
|
||||
if (coords.Length == 4)
|
||||
{
|
||||
result = this.parseInt(coords[3], out data.dy);
|
||||
}
|
||||
else
|
||||
{
|
||||
data.dy = data.dx;
|
||||
}
|
||||
}
|
||||
if (result == String.Empty)
|
||||
{
|
||||
if ((data.dx <= 0) || (data.dy <= 0))
|
||||
{
|
||||
result = "Shape sizes must be positive integers";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = String.Format("Bad value in shape parameters {0}", arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (arg.StartsWith("-taper="))
|
||||
{
|
||||
if (data.bevel != String.Empty)
|
||||
{
|
||||
result = "Only 1 '-taper' parameter is permitted.";
|
||||
}
|
||||
else
|
||||
{
|
||||
data.bevel = "taper";
|
||||
val = arg.Substring(arg.IndexOf("=") + 1);
|
||||
result = this.parseFloat(val, out data.bevelevation);
|
||||
if (result != String.Empty)
|
||||
{
|
||||
result = String.Format("Bad format for taper parameter {0}", arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = String.Format("Unrecognized parameter {0}", arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected string parseFloat(String s, out float f)
|
||||
{
|
||||
string result;
|
||||
double d;
|
||||
if (Double.TryParse(s, out d))
|
||||
{
|
||||
try
|
||||
{
|
||||
f = (float)d;
|
||||
result = String.Empty;
|
||||
}
|
||||
catch(InvalidCastException)
|
||||
{
|
||||
result = String.Format("{0} is invalid", s);
|
||||
f = -1.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
f = -1.0f;
|
||||
result = String.Format("{0} is invalid", s);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected string parseInt(String s, out int i)
|
||||
{
|
||||
string result;
|
||||
if (Int32.TryParse(s, out i))
|
||||
{
|
||||
result = String.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = String.Format("{0} is invalid", s);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void applyModification(ITerrainChannel map, TerrainModifierData data)
|
||||
{
|
||||
bool[,] mask;
|
||||
int xMax;
|
||||
int yMax;
|
||||
int xMid;
|
||||
int yMid;
|
||||
if (data.shape == "ellipse")
|
||||
{
|
||||
mask = this.ellipticalMask(data.dx, data.dy);
|
||||
xMax = mask.GetLength(0);
|
||||
yMax = mask.GetLength(1);
|
||||
xMid = xMax / 2 + xMax % 2;
|
||||
yMid = yMax / 2 + yMax % 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = this.rectangularMask(data.dx, data.dy);
|
||||
xMax = mask.GetLength(0);
|
||||
yMax = mask.GetLength(1);
|
||||
xMid = 0;
|
||||
yMid = 0;
|
||||
}
|
||||
// m_log.DebugFormat("Apply {0} mask {1}x{2} @ {3},{4}", data.shape, xMax, yMax, xMid, yMid);
|
||||
double[,] buffer = map.GetDoubles();
|
||||
int yDim = yMax;
|
||||
while(--yDim >= 0)
|
||||
{
|
||||
int yPos = data.y0 + yDim - yMid;
|
||||
if ((yPos >= 0) && (yPos < map.Height))
|
||||
{
|
||||
int xDim = xMax;
|
||||
while(--xDim >= 0)
|
||||
{
|
||||
int xPos = data.x0 + xDim - xMid;
|
||||
if ((xPos >= 0) && (xPos < map.Width) && (mask[xDim, yDim]))
|
||||
{
|
||||
double endElevation = this.operate(buffer, data, xPos, yPos);
|
||||
map[xPos, yPos] = endElevation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected double computeBevel(TerrainModifierData data, int x, int y)
|
||||
{
|
||||
int deltaX;
|
||||
int deltaY;
|
||||
int xMax;
|
||||
int yMax;
|
||||
double factor;
|
||||
if (data.bevel == "taper")
|
||||
{
|
||||
if (data.shape == "ellipse")
|
||||
{
|
||||
deltaX = x - data.x0;
|
||||
deltaY = y - data.y0;
|
||||
xMax = data.dx;
|
||||
yMax = data.dy;
|
||||
factor = (double)((deltaX * deltaX) + (deltaY * deltaY));
|
||||
factor /= ((xMax * xMax) + (yMax * yMax));
|
||||
}
|
||||
else
|
||||
{
|
||||
// pyramid
|
||||
xMax = data.dx / 2 + data.dx % 2;
|
||||
yMax = data.dy / 2 + data.dy % 2;
|
||||
deltaX = Math.Abs(data.x0 + xMax - x);
|
||||
deltaY = Math.Abs(data.y0 + yMax - y);
|
||||
factor = Math.Max(((double)(deltaY) / yMax), ((double)(deltaX) / xMax));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
factor = 0.0;
|
||||
}
|
||||
return factor;
|
||||
}
|
||||
|
||||
private bool[,] rectangularMask(int xSize, int ySize)
|
||||
{
|
||||
bool[,] mask = new bool[xSize, ySize];
|
||||
int yPos = ySize;
|
||||
while(--yPos >= 0)
|
||||
{
|
||||
int xPos = xSize;
|
||||
while(--xPos >= 0)
|
||||
{
|
||||
mask[xPos, yPos] = true;
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fast ellipse-based derivative of Bresenham algorithm.
|
||||
* https://web.archive.org/web/20120225095359/http://homepage.smc.edu/kennedy_john/belipse.pdf
|
||||
*/
|
||||
private bool[,] ellipticalMask(int xRadius, int yRadius)
|
||||
{
|
||||
long twoASquared = 2L * xRadius * xRadius;
|
||||
long twoBSquared = 2L * yRadius * yRadius;
|
||||
|
||||
bool[,] mask = new bool[2 * xRadius + 1, 2 * yRadius + 1];
|
||||
|
||||
long ellipseError = 0L;
|
||||
long stoppingX = twoBSquared * xRadius;
|
||||
long stoppingY = 0L;
|
||||
long xChange = yRadius * yRadius * (1L - 2L * xRadius);
|
||||
long yChange = xRadius * xRadius;
|
||||
|
||||
int xPos = xRadius;
|
||||
int yPos = 0;
|
||||
|
||||
// first set of points
|
||||
while(stoppingX >= stoppingY)
|
||||
{
|
||||
int yUpper = yRadius + yPos;
|
||||
int yLower = yRadius - yPos;
|
||||
// fill in the mask
|
||||
int xNow = xPos;
|
||||
while(xNow >= 0)
|
||||
{
|
||||
mask[xRadius + xNow, yUpper] = true;
|
||||
mask[xRadius - xNow, yUpper] = true;
|
||||
mask[xRadius + xNow, yLower] = true;
|
||||
mask[xRadius - xNow, yLower] = true;
|
||||
--xNow;
|
||||
}
|
||||
yPos++;
|
||||
stoppingY += twoASquared;
|
||||
ellipseError += yChange;
|
||||
yChange += twoASquared;
|
||||
if ((2L * ellipseError + xChange) > 0L)
|
||||
{
|
||||
xPos--;
|
||||
stoppingX -= twoBSquared;
|
||||
ellipseError += xChange;
|
||||
xChange += twoBSquared;
|
||||
}
|
||||
}
|
||||
|
||||
// second set of points
|
||||
xPos = 0;
|
||||
yPos = yRadius;
|
||||
xChange = yRadius * yRadius;
|
||||
yChange = xRadius * xRadius * (1L - 2L * yRadius);
|
||||
|
||||
ellipseError = 0L;
|
||||
stoppingX = 0L;
|
||||
stoppingY = twoASquared * yRadius;
|
||||
|
||||
while(stoppingX <= stoppingY)
|
||||
{
|
||||
int xUpper = xRadius + xPos;
|
||||
int xLower = xRadius - xPos;
|
||||
// fill in the mask
|
||||
int yNow = yPos;
|
||||
while(yNow >= 0)
|
||||
{
|
||||
mask[xUpper, yRadius + yNow] = true;
|
||||
mask[xUpper, yRadius - yNow] = true;
|
||||
mask[xLower, yRadius + yNow] = true;
|
||||
mask[xLower, yRadius - yNow] = true;
|
||||
--yNow;
|
||||
}
|
||||
xPos++;
|
||||
stoppingX += twoBSquared;
|
||||
ellipseError += xChange;
|
||||
xChange += twoBSquared;
|
||||
if ((2L * ellipseError + yChange) > 0L)
|
||||
{
|
||||
yPos--;
|
||||
stoppingY -= twoASquared;
|
||||
ellipseError += yChange;
|
||||
yChange += twoASquared;
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
{
|
||||
public struct TerrainModifierData
|
||||
{
|
||||
public float elevation;
|
||||
public string shape;
|
||||
public int x0;
|
||||
public int y0;
|
||||
public int dx;
|
||||
public int dy;
|
||||
public string bevel;
|
||||
public float bevelevation;
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,6 @@
|
|||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -42,7 +41,7 @@ using OpenSim.Framework;
|
|||
using OpenSim.Framework.Console;
|
||||
using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
|
||||
using OpenSim.Region.CoreModules.World.Terrain.FileLoaders;
|
||||
using OpenSim.Region.CoreModules.World.Terrain.Features;
|
||||
using OpenSim.Region.CoreModules.World.Terrain.Modifiers;
|
||||
using OpenSim.Region.CoreModules.World.Terrain.FloodBrushes;
|
||||
using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
@ -75,14 +74,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Terrain Features
|
||||
/// </summary>
|
||||
public enum TerrainFeatures: byte
|
||||
{
|
||||
Rectangle = 1,
|
||||
}
|
||||
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
#pragma warning disable 414
|
||||
|
@ -90,26 +81,19 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
#pragma warning restore 414
|
||||
|
||||
private readonly Commander m_commander = new Commander("terrain");
|
||||
|
||||
private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects =
|
||||
new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>();
|
||||
|
||||
private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>();
|
||||
|
||||
private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects =
|
||||
new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>();
|
||||
|
||||
private Dictionary<string, ITerrainEffect> m_plugineffects;
|
||||
|
||||
private Dictionary<string, ITerrainFeature> m_featureEffects =
|
||||
new Dictionary<string, ITerrainFeature>();
|
||||
|
||||
private Dictionary<string, ITerrainModifier> m_modifyOperations =
|
||||
new Dictionary<string, ITerrainModifier>();
|
||||
private ITerrainChannel m_channel;
|
||||
private ITerrainChannel m_revert;
|
||||
private Scene m_scene;
|
||||
private volatile bool m_tainted;
|
||||
private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5);
|
||||
|
||||
private String m_InitialTerrain = "pinhead-island";
|
||||
|
||||
// If true, send terrain patch updates to clients based on their view distance
|
||||
|
@ -136,14 +120,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
{
|
||||
return (updateCount > 0);
|
||||
}
|
||||
|
||||
public void SetByXY(int x, int y, bool state)
|
||||
{
|
||||
this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state);
|
||||
}
|
||||
|
||||
public bool GetByPatch(int patchX, int patchY)
|
||||
{
|
||||
return updated[patchX, patchY];
|
||||
}
|
||||
|
||||
public void SetByPatch(int patchX, int patchY, bool state)
|
||||
{
|
||||
bool prevState = updated[patchX, patchY];
|
||||
|
@ -153,11 +140,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
updateCount--;
|
||||
updated[patchX, patchY] = state;
|
||||
}
|
||||
|
||||
public void SetAll(bool state)
|
||||
{
|
||||
updateCount = 0;
|
||||
for (int xx = 0; xx < updated.GetLength(0); xx++)
|
||||
for (int yy = 0; yy < updated.GetLength(1); yy++)
|
||||
for(int xx = 0; xx < updated.GetLength(0); xx++)
|
||||
for(int yy = 0; yy < updated.GetLength(1); yy++)
|
||||
updated[xx, yy] = state;
|
||||
if (state)
|
||||
updateCount = updated.GetLength(0) * updated.GetLength(1);
|
||||
|
@ -174,9 +162,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize)
|
||||
);
|
||||
}
|
||||
for (int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize)
|
||||
for(int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize)
|
||||
{
|
||||
for (int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize)
|
||||
for(int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize)
|
||||
{
|
||||
// Only set tainted. The patch bit may be set if the patch was to be sent later.
|
||||
if (terrData.IsTaintedAt(xx, yy, false))
|
||||
|
@ -201,8 +189,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
#region ICommandableModule Members
|
||||
|
||||
public ICommander CommandInterface
|
||||
{
|
||||
public ICommander CommandInterface {
|
||||
get { return m_commander; }
|
||||
}
|
||||
|
||||
|
@ -230,7 +217,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
m_scene = scene;
|
||||
|
||||
// Install terrain module in the simulator
|
||||
lock (m_scene)
|
||||
lock(m_scene)
|
||||
{
|
||||
if (m_scene.Heightmap == null)
|
||||
{
|
||||
|
@ -262,7 +249,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
string supportedFilesSeparatorForTileSave = "";
|
||||
|
||||
m_supportFileExtensionsForTileSave = "";
|
||||
foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
{
|
||||
m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")";
|
||||
supportedFilesSeparator = ", ";
|
||||
|
@ -285,7 +272,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
public void RemoveRegion(Scene scene)
|
||||
{
|
||||
lock (m_scene)
|
||||
lock(m_scene)
|
||||
{
|
||||
// remove the commands
|
||||
m_scene.UnregisterModuleCommander(m_commander.Name);
|
||||
|
@ -304,13 +291,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
{
|
||||
}
|
||||
|
||||
public Type ReplaceableInterface
|
||||
{
|
||||
public Type ReplaceableInterface {
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
public string Name {
|
||||
get { return "TerrainModule"; }
|
||||
}
|
||||
|
||||
|
@ -329,11 +314,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
/// <param name="filename">Filename to terrain file. Type is determined by extension.</param>
|
||||
public void LoadFromFile(string filename)
|
||||
{
|
||||
foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
{
|
||||
if (filename.EndsWith(loader.Key))
|
||||
{
|
||||
lock (m_scene)
|
||||
lock(m_scene)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -349,20 +334,20 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
m_channel = channel;
|
||||
UpdateRevertMap();
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
catch(NotImplementedException)
|
||||
{
|
||||
m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value +
|
||||
" parser does not support file loading. (May be save only)");
|
||||
throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value));
|
||||
}
|
||||
catch (FileNotFoundException)
|
||||
catch(FileNotFoundException)
|
||||
{
|
||||
m_log.Error(
|
||||
"[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)");
|
||||
throw new TerrainException(
|
||||
String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename));
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
catch(ArgumentException e)
|
||||
{
|
||||
m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message);
|
||||
throw new TerrainException(
|
||||
|
@ -386,7 +371,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
{
|
||||
try
|
||||
{
|
||||
foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
{
|
||||
if (filename.EndsWith(loader.Key))
|
||||
{
|
||||
|
@ -396,7 +381,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ioe)
|
||||
catch(IOException ioe)
|
||||
{
|
||||
m_log.Error(String.Format("[TERRAIN]: Unable to save to {0}, {1}", filename, ioe.Message));
|
||||
}
|
||||
|
@ -429,11 +414,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
public void LoadFromStream(string filename, Vector3 displacement,
|
||||
float radianRotation, Vector2 rotationDisplacement, Stream stream)
|
||||
{
|
||||
foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
{
|
||||
if (filename.EndsWith(loader.Key))
|
||||
{
|
||||
lock (m_scene)
|
||||
lock(m_scene)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -441,7 +426,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement);
|
||||
UpdateRevertMap();
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
catch(NotImplementedException)
|
||||
{
|
||||
m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value +
|
||||
" parser does not support file loading. (May be save only)");
|
||||
|
@ -501,7 +486,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
{
|
||||
try
|
||||
{
|
||||
foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
{
|
||||
if (filename.EndsWith(loader.Key))
|
||||
{
|
||||
|
@ -510,7 +495,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
catch(NotImplementedException)
|
||||
{
|
||||
m_log.Error("Unable to save to " + filename + ", saving of this file format has not been implemented.");
|
||||
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
|
|||
|
||||
// Someone diddled terrain outside the normal code paths. Set the taintedness for all clients.
|
||||
// ITerrainModule.TaintTerrain()
|
||||
public void TaintTerrain ()
|
||||
public void TaintTerrain()
|
||||
{
|
||||
lock (m_perClientPatchUpdates)
|
||||
lock(m_perClientPatchUpdates)
|
||||
{
|
||||
// Set the flags for all clients so the tainted patches will be sent out
|
||||
foreach (PatchUpdates pups in m_perClientPatchUpdates.Values)
|
||||
foreach(PatchUpdates pups in m_perClientPatchUpdates.Values)
|
||||
{
|
||||
pups.SetAll(m_scene.Heightmap.GetTerrainData());
|
||||
}
|
||||
|
@ -539,7 +524,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId);
|
||||
if (presence != null)
|
||||
{
|
||||
lock (m_perClientPatchUpdates)
|
||||
lock(m_perClientPatchUpdates)
|
||||
{
|
||||
PatchUpdates pups;
|
||||
if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups))
|
||||
|
@ -566,13 +551,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
m_plugineffects = new Dictionary<string, ITerrainEffect>();
|
||||
LoadPlugins(Assembly.GetCallingAssembly());
|
||||
string plugineffectsPath = "Terrain";
|
||||
|
||||
|
||||
// Load the files in the Terrain/ dir
|
||||
if (!Directory.Exists(plugineffectsPath))
|
||||
return;
|
||||
|
||||
|
||||
string[] files = Directory.GetFiles(plugineffectsPath);
|
||||
foreach (string file in files)
|
||||
foreach(string file in files)
|
||||
{
|
||||
m_log.Info("Loading effects in " + file);
|
||||
try
|
||||
|
@ -580,7 +565,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
Assembly library = Assembly.LoadFrom(file);
|
||||
LoadPlugins(library);
|
||||
}
|
||||
catch (BadImageFormatException)
|
||||
catch(BadImageFormatException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -588,7 +573,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
private void LoadPlugins(Assembly library)
|
||||
{
|
||||
foreach (Type pluginType in library.GetTypes())
|
||||
foreach(Type pluginType in library.GetTypes())
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -610,7 +595,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
m_log.Info("L ... " + typeName);
|
||||
}
|
||||
}
|
||||
catch (AmbiguousMatchException)
|
||||
catch(AmbiguousMatchException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -618,7 +603,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
public void InstallPlugin(string pluginName, ITerrainEffect effect)
|
||||
{
|
||||
lock (m_plugineffects)
|
||||
lock(m_plugineffects)
|
||||
{
|
||||
if (!m_plugineffects.ContainsKey(pluginName))
|
||||
{
|
||||
|
@ -661,8 +646,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea();
|
||||
m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert);
|
||||
|
||||
// Terrain Feature effects
|
||||
m_featureEffects["rectangle"] = new RectangleFeature(this);
|
||||
// Terrain Modifier operations
|
||||
m_modifyOperations["min"] = new MinModifier(this);
|
||||
m_modifyOperations["max"] = new MaxModifier(this);
|
||||
m_modifyOperations["raise"] = new RaiseModifier(this);
|
||||
m_modifyOperations["lower"] = new LowerModifier(this);
|
||||
m_modifyOperations["fill"] = new FillModifier(this);
|
||||
m_modifyOperations["smooth"] = new SmoothModifier(this);
|
||||
m_modifyOperations["noise"] = new NoiseModifier(this);
|
||||
|
||||
// Filesystem load/save loaders
|
||||
m_loaders[".r32"] = new RAW32();
|
||||
|
@ -707,22 +698,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
/// <param name="fileStartY">Where to begin our slice</param>
|
||||
public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY)
|
||||
{
|
||||
int offsetX = (int) m_scene.RegionInfo.RegionLocX - fileStartX;
|
||||
int offsetY = (int) m_scene.RegionInfo.RegionLocY - fileStartY;
|
||||
int offsetX = (int)m_scene.RegionInfo.RegionLocX - fileStartX;
|
||||
int offsetY = (int)m_scene.RegionInfo.RegionLocY - fileStartY;
|
||||
|
||||
if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight)
|
||||
{
|
||||
// this region is included in the tile request
|
||||
foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
{
|
||||
if (filename.EndsWith(loader.Key))
|
||||
{
|
||||
lock (m_scene)
|
||||
lock(m_scene)
|
||||
{
|
||||
ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY,
|
||||
fileWidth, fileHeight,
|
||||
(int) m_scene.RegionInfo.RegionSizeX,
|
||||
(int) m_scene.RegionInfo.RegionSizeY);
|
||||
(int)m_scene.RegionInfo.RegionSizeX,
|
||||
(int)m_scene.RegionInfo.RegionSizeY);
|
||||
m_scene.Heightmap = channel;
|
||||
m_channel = channel;
|
||||
UpdateRevertMap();
|
||||
|
@ -761,11 +752,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
}
|
||||
|
||||
// this region is included in the tile request
|
||||
foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
|
||||
{
|
||||
if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave())
|
||||
{
|
||||
lock (m_scene)
|
||||
lock(m_scene)
|
||||
{
|
||||
loader.Value.SaveFile(m_channel, filename, offsetX, offsetY,
|
||||
fileWidth, fileHeight,
|
||||
|
@ -777,7 +768,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1,
|
||||
m_scene.RegionInfo.RegionName, filename);
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -799,9 +790,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
TerrainData terrData = m_channel.GetTerrainData();
|
||||
|
||||
bool shouldTaint = false;
|
||||
for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
|
||||
for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
|
||||
{
|
||||
for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
|
||||
for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
|
||||
{
|
||||
if (terrData.IsTaintedAt(x, y))
|
||||
{
|
||||
|
@ -856,7 +847,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
string[] tmpArgs = new string[args.Length - 2];
|
||||
int i;
|
||||
for (i = 2; i < args.Length; i++)
|
||||
for(i = 2; i < args.Length; i++)
|
||||
tmpArgs[i - 2] = args[i];
|
||||
|
||||
m_commander.ProcessConsoleCommand(args[1], tmpArgs);
|
||||
|
@ -874,7 +865,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
client.OnLandUndo += client_OnLandUndo;
|
||||
client.OnUnackedTerrain += client_OnUnackedTerrain;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Installs terrain brush hook to IClientAPI
|
||||
/// </summary>
|
||||
|
@ -890,10 +881,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain;
|
||||
}
|
||||
|
||||
lock (m_perClientPatchUpdates)
|
||||
lock(m_perClientPatchUpdates)
|
||||
m_perClientPatchUpdates.Remove(client);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Scan over changes in the terrain and limit height changes. This enforces the
|
||||
/// non-estate owner limits on rate of terrain editting.
|
||||
|
@ -904,12 +895,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
TerrainData terrData = m_channel.GetTerrainData();
|
||||
|
||||
bool wasLimited = false;
|
||||
for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
|
||||
for(int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
|
||||
{
|
||||
for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
|
||||
for(int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
|
||||
{
|
||||
if (terrData.IsTaintedAt(x, y, false /* clearOnTest */))
|
||||
{
|
||||
{
|
||||
// If we should respect the estate settings then
|
||||
// fixup and height deltas that don't respect them.
|
||||
// Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values.
|
||||
|
@ -933,9 +924,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
// loop through the height map for this patch and compare it against
|
||||
// the revert map
|
||||
for (int x = xStart; x < xStart + Constants.TerrainPatchSize; x++)
|
||||
for(int x = xStart; x < xStart + Constants.TerrainPatchSize; x++)
|
||||
{
|
||||
for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++)
|
||||
for(int y = yStart; y < yStart + Constants.TerrainPatchSize; y++)
|
||||
{
|
||||
float requestedHeight = terrData[x, y];
|
||||
float bakedHeight = (float)m_revert[x, y];
|
||||
|
@ -959,7 +950,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
private void client_OnLandUndo(IClientAPI client)
|
||||
{
|
||||
lock (m_undo)
|
||||
lock(m_undo)
|
||||
{
|
||||
if (m_undo.Count > 0)
|
||||
{
|
||||
|
@ -981,19 +972,19 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
if (m_sendTerrainUpdatesByViewDistance)
|
||||
{
|
||||
// Add that this patch needs to be sent to the accounting for each client.
|
||||
lock (m_perClientPatchUpdates)
|
||||
lock(m_perClientPatchUpdates)
|
||||
{
|
||||
m_scene.ForEachScenePresence(presence =>
|
||||
{
|
||||
PatchUpdates thisClientUpdates;
|
||||
if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates))
|
||||
{
|
||||
PatchUpdates thisClientUpdates;
|
||||
if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates))
|
||||
{
|
||||
// There is a ScenePresence without a send patch map. Create one.
|
||||
thisClientUpdates = new PatchUpdates(terrData, presence);
|
||||
m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates);
|
||||
}
|
||||
thisClientUpdates.SetByXY(x, y, true);
|
||||
// There is a ScenePresence without a send patch map. Create one.
|
||||
thisClientUpdates = new PatchUpdates(terrData, presence);
|
||||
m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates);
|
||||
}
|
||||
thisClientUpdates.SetByXY(x, y, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1005,11 +996,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
float[] heightMap = new float[10];
|
||||
m_scene.ForEachClient(
|
||||
delegate(IClientAPI controller)
|
||||
{
|
||||
controller.SendLayerData(x / Constants.TerrainPatchSize,
|
||||
{
|
||||
controller.SendLayerData(x / Constants.TerrainPatchSize,
|
||||
y / Constants.TerrainPatchSize,
|
||||
heightMap);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1019,12 +1010,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
public int PatchX;
|
||||
public int PatchY;
|
||||
public float Dist;
|
||||
|
||||
public PatchesToSend(int pX, int pY, float pDist)
|
||||
{
|
||||
PatchX = pX;
|
||||
PatchY = pY;
|
||||
Dist = pDist;
|
||||
}
|
||||
|
||||
public int CompareTo(PatchesToSend other)
|
||||
{
|
||||
return Dist.CompareTo(other.Dist);
|
||||
|
@ -1036,9 +1029,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
// Loop through all the per-client info and send any patches necessary.
|
||||
private void CheckSendingPatchesToClients()
|
||||
{
|
||||
lock (m_perClientPatchUpdates)
|
||||
lock(m_perClientPatchUpdates)
|
||||
{
|
||||
foreach (PatchUpdates pups in m_perClientPatchUpdates.Values)
|
||||
foreach(PatchUpdates pups in m_perClientPatchUpdates.Values)
|
||||
{
|
||||
if (pups.HasUpdates())
|
||||
{
|
||||
|
@ -1062,7 +1055,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
int[] yPieces = new int[toSend.Count];
|
||||
float[] patchPieces = new float[toSend.Count * 2];
|
||||
int pieceIndex = 0;
|
||||
foreach (PatchesToSend pts in toSend)
|
||||
foreach(PatchesToSend pts in toSend)
|
||||
{
|
||||
patchPieces[pieceIndex++] = pts.PatchX;
|
||||
patchPieces[pieceIndex++] = pts.PatchY;
|
||||
|
@ -1083,25 +1076,25 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
return ret;
|
||||
|
||||
// Compute the area of patches within our draw distance
|
||||
int startX = (((int) (presence.AbsolutePosition.X - presence.DrawDistance))/Constants.TerrainPatchSize) - 2;
|
||||
int startX = (((int)(presence.AbsolutePosition.X - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2;
|
||||
startX = Math.Max(startX, 0);
|
||||
startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize);
|
||||
int startY = (((int) (presence.AbsolutePosition.Y - presence.DrawDistance))/Constants.TerrainPatchSize) - 2;
|
||||
startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize);
|
||||
int startY = (((int)(presence.AbsolutePosition.Y - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2;
|
||||
startY = Math.Max(startY, 0);
|
||||
startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize);
|
||||
int endX = (((int) (presence.AbsolutePosition.X + presence.DrawDistance))/Constants.TerrainPatchSize) + 2;
|
||||
startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize);
|
||||
int endX = (((int)(presence.AbsolutePosition.X + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2;
|
||||
endX = Math.Max(endX, 0);
|
||||
endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize);
|
||||
int endY = (((int) (presence.AbsolutePosition.Y + presence.DrawDistance))/Constants.TerrainPatchSize) + 2;
|
||||
endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize);
|
||||
int endY = (((int)(presence.AbsolutePosition.Y + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2;
|
||||
endY = Math.Max(endY, 0);
|
||||
endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize);
|
||||
endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize);
|
||||
// m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, start=<{4},{5}>, end=<{6},{7}>",
|
||||
// LogHeader, m_scene.RegionInfo.RegionName,
|
||||
// presence.DrawDistance, presence.AbsolutePosition,
|
||||
// startX, startY, endX, endY);
|
||||
for (int x = startX; x < endX; x++)
|
||||
for(int x = startX; x < endX; x++)
|
||||
{
|
||||
for (int y = startY; y < endY; y++)
|
||||
for(int y = startY; y < endY; y++)
|
||||
{
|
||||
//Need to make sure we don't send the same ones over and over
|
||||
Vector3 presencePos = presence.AbsolutePosition;
|
||||
|
@ -1133,28 +1126,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
bool allowed = false;
|
||||
if (north == south && east == west)
|
||||
{
|
||||
if (m_painteffects.ContainsKey((StandardTerrainEffects) action))
|
||||
if (m_painteffects.ContainsKey((StandardTerrainEffects)action))
|
||||
{
|
||||
bool[,] allowMask = new bool[m_channel.Width,m_channel.Height];
|
||||
bool[,] allowMask = new bool[m_channel.Width, m_channel.Height];
|
||||
allowMask.Initialize();
|
||||
int n = size + 1;
|
||||
if (n > 2)
|
||||
n = 4;
|
||||
|
||||
int zx = (int) (west + 0.5);
|
||||
int zy = (int) (north + 0.5);
|
||||
int zx = (int)(west + 0.5);
|
||||
int zy = (int)(north + 0.5);
|
||||
|
||||
int dx;
|
||||
for (dx=-n; dx<=n; dx++)
|
||||
for(dx=-n; dx<=n; dx++)
|
||||
{
|
||||
int dy;
|
||||
for (dy=-n; dy<=n; dy++)
|
||||
for(dy=-n; dy<=n; dy++)
|
||||
{
|
||||
int x = zx + dx;
|
||||
int y = zy + dy;
|
||||
if (x>=0 && y>=0 && x<m_channel.Width && y<m_channel.Height)
|
||||
if (x >= 0 && y >= 0 && x < m_channel.Width && y < m_channel.Height)
|
||||
{
|
||||
if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0)))
|
||||
if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0)))
|
||||
{
|
||||
allowMask[x, y] = true;
|
||||
allowed = true;
|
||||
|
@ -1165,7 +1158,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
if (allowed)
|
||||
{
|
||||
StoreUndoState();
|
||||
m_painteffects[(StandardTerrainEffects) action].PaintEffect(
|
||||
m_painteffects[(StandardTerrainEffects)action].PaintEffect(
|
||||
m_channel, allowMask, west, south, height, size, seconds);
|
||||
|
||||
//revert changes outside estate limits
|
||||
|
@ -1180,22 +1173,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
}
|
||||
else
|
||||
{
|
||||
if (m_floodeffects.ContainsKey((StandardTerrainEffects) action))
|
||||
if (m_floodeffects.ContainsKey((StandardTerrainEffects)action))
|
||||
{
|
||||
bool[,] fillArea = new bool[m_channel.Width,m_channel.Height];
|
||||
bool[,] fillArea = new bool[m_channel.Width, m_channel.Height];
|
||||
fillArea.Initialize();
|
||||
|
||||
int x;
|
||||
for (x = 0; x < m_channel.Width; x++)
|
||||
for(x = 0; x < m_channel.Width; x++)
|
||||
{
|
||||
int y;
|
||||
for (y = 0; y < m_channel.Height; y++)
|
||||
for(y = 0; y < m_channel.Height; y++)
|
||||
{
|
||||
if (x < east && x > west)
|
||||
{
|
||||
if (y < north && y > south)
|
||||
{
|
||||
if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x,y,0)))
|
||||
if (m_scene.Permissions.CanTerraformLand(agentId, new Vector3(x, y, 0)))
|
||||
{
|
||||
fillArea[x, y] = true;
|
||||
allowed = true;
|
||||
|
@ -1208,7 +1201,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
if (allowed)
|
||||
{
|
||||
StoreUndoState();
|
||||
m_floodeffects[(StandardTerrainEffects) action].FloodEffect(m_channel, fillArea, size);
|
||||
m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size);
|
||||
|
||||
//revert changes outside estate limits
|
||||
if (!god)
|
||||
|
@ -1232,7 +1225,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY)
|
||||
{
|
||||
//m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY);
|
||||
|
@ -1243,7 +1236,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
private void StoreUndoState()
|
||||
{
|
||||
lock (m_undo)
|
||||
lock(m_undo)
|
||||
{
|
||||
if (m_undo.Count > 0)
|
||||
{
|
||||
|
@ -1264,21 +1257,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
private void InterfaceLoadFile(Object[] args)
|
||||
{
|
||||
LoadFromFile((string) args[0]);
|
||||
LoadFromFile((string)args[0]);
|
||||
}
|
||||
|
||||
private void InterfaceLoadTileFile(Object[] args)
|
||||
{
|
||||
LoadFromFile((string) args[0],
|
||||
(int) args[1],
|
||||
(int) args[2],
|
||||
(int) args[3],
|
||||
(int) args[4]);
|
||||
LoadFromFile((string)args[0],
|
||||
(int)args[1],
|
||||
(int)args[2],
|
||||
(int)args[3],
|
||||
(int)args[4]);
|
||||
}
|
||||
|
||||
private void InterfaceSaveFile(Object[] args)
|
||||
{
|
||||
SaveToFile((string) args[0]);
|
||||
SaveToFile((string)args[0]);
|
||||
}
|
||||
|
||||
private void InterfaceSaveTileFile(Object[] args)
|
||||
|
@ -1298,8 +1291,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
private void InterfaceRevertTerrain(Object[] args)
|
||||
{
|
||||
int x, y;
|
||||
for (x = 0; x < m_channel.Width; x++)
|
||||
for (y = 0; y < m_channel.Height; y++)
|
||||
for(x = 0; x < m_channel.Width; x++)
|
||||
for(y = 0; y < m_channel.Height; y++)
|
||||
m_channel[x, y] = m_revert[x, y];
|
||||
|
||||
}
|
||||
|
@ -1310,9 +1303,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
if (direction.ToLower().StartsWith("y"))
|
||||
{
|
||||
for (int x = 0; x < m_channel.Width; x++)
|
||||
for(int x = 0; x < m_channel.Width; x++)
|
||||
{
|
||||
for (int y = 0; y < m_channel.Height / 2; y++)
|
||||
for(int y = 0; y < m_channel.Height / 2; y++)
|
||||
{
|
||||
double height = m_channel[x, y];
|
||||
double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y];
|
||||
|
@ -1324,9 +1317,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
}
|
||||
else if (direction.ToLower().StartsWith("x"))
|
||||
{
|
||||
for (int y = 0; y < m_channel.Height; y++)
|
||||
for(int y = 0; y < m_channel.Height; y++)
|
||||
{
|
||||
for (int x = 0; x < m_channel.Width / 2; x++)
|
||||
for(int x = 0; x < m_channel.Width / 2; x++)
|
||||
{
|
||||
double height = m_channel[x, y];
|
||||
double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y];
|
||||
|
@ -1365,9 +1358,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
int width = m_channel.Width;
|
||||
int height = m_channel.Height;
|
||||
|
||||
for (int x = 0; x < width; x++)
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
for(int y = 0; y < height; y++)
|
||||
{
|
||||
double currHeight = m_channel[x, y];
|
||||
if (currHeight < currMin)
|
||||
|
@ -1388,12 +1381,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
//m_log.InfoFormat("Scale = {0}", scale);
|
||||
|
||||
// scale the heightmap accordingly
|
||||
for (int x = 0; x < width; x++)
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
for(int y = 0; y < height; y++)
|
||||
{
|
||||
double currHeight = m_channel[x, y] - currMin;
|
||||
m_channel[x, y] = desiredMin + (currHeight * scale);
|
||||
double currHeight = m_channel[x, y] - currMin;
|
||||
m_channel[x, y] = desiredMin + (currHeight * scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1404,42 +1397,42 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
private void InterfaceElevateTerrain(Object[] args)
|
||||
{
|
||||
int x, y;
|
||||
for (x = 0; x < m_channel.Width; x++)
|
||||
for (y = 0; y < m_channel.Height; y++)
|
||||
m_channel[x, y] += (double) args[0];
|
||||
for(x = 0; x < m_channel.Width; x++)
|
||||
for(y = 0; y < m_channel.Height; y++)
|
||||
m_channel[x, y] += (double)args[0];
|
||||
}
|
||||
|
||||
private void InterfaceMultiplyTerrain(Object[] args)
|
||||
{
|
||||
int x, y;
|
||||
for (x = 0; x < m_channel.Width; x++)
|
||||
for (y = 0; y < m_channel.Height; y++)
|
||||
m_channel[x, y] *= (double) args[0];
|
||||
for(x = 0; x < m_channel.Width; x++)
|
||||
for(y = 0; y < m_channel.Height; y++)
|
||||
m_channel[x, y] *= (double)args[0];
|
||||
}
|
||||
|
||||
private void InterfaceLowerTerrain(Object[] args)
|
||||
{
|
||||
int x, y;
|
||||
for (x = 0; x < m_channel.Width; x++)
|
||||
for (y = 0; y < m_channel.Height; y++)
|
||||
m_channel[x, y] -= (double) args[0];
|
||||
for(x = 0; x < m_channel.Width; x++)
|
||||
for(y = 0; y < m_channel.Height; y++)
|
||||
m_channel[x, y] -= (double)args[0];
|
||||
}
|
||||
|
||||
public void InterfaceFillTerrain(Object[] args)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
for (x = 0; x < m_channel.Width; x++)
|
||||
for (y = 0; y < m_channel.Height; y++)
|
||||
m_channel[x, y] = (double) args[0];
|
||||
for(x = 0; x < m_channel.Width; x++)
|
||||
for(y = 0; y < m_channel.Height; y++)
|
||||
m_channel[x, y] = (double)args[0];
|
||||
}
|
||||
|
||||
private void InterfaceMinTerrain(Object[] args)
|
||||
{
|
||||
int x, y;
|
||||
for (x = 0; x < m_channel.Width; x++)
|
||||
for(x = 0; x < m_channel.Width; x++)
|
||||
{
|
||||
for (y = 0; y < m_channel.Height; y++)
|
||||
for(y = 0; y < m_channel.Height; y++)
|
||||
{
|
||||
m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]);
|
||||
}
|
||||
|
@ -1449,9 +1442,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
private void InterfaceMaxTerrain(Object[] args)
|
||||
{
|
||||
int x, y;
|
||||
for (x = 0; x < m_channel.Width; x++)
|
||||
for(x = 0; x < m_channel.Width; x++)
|
||||
{
|
||||
for (y = 0; y < m_channel.Height; y++)
|
||||
for(y = 0; y < m_channel.Height; y++)
|
||||
{
|
||||
m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]);
|
||||
}
|
||||
|
@ -1480,10 +1473,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
double sum = 0;
|
||||
|
||||
int x;
|
||||
for (x = 0; x < m_channel.Width; x++)
|
||||
for(x = 0; x < m_channel.Width; x++)
|
||||
{
|
||||
int y;
|
||||
for (y = 0; y < m_channel.Height; y++)
|
||||
for(y = 0; y < m_channel.Height; y++)
|
||||
{
|
||||
sum += m_channel[x, y];
|
||||
if (max < m_channel[x, y])
|
||||
|
@ -1501,7 +1494,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
|
||||
private void InterfaceEnableExperimentalBrushes(Object[] args)
|
||||
{
|
||||
if ((bool) args[0])
|
||||
if ((bool)args[0])
|
||||
{
|
||||
m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere();
|
||||
m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere();
|
||||
|
@ -1520,7 +1513,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
if (firstArg == "list")
|
||||
{
|
||||
MainConsole.Instance.Output("List of loaded plugins");
|
||||
foreach (KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects)
|
||||
foreach(KeyValuePair<string, ITerrainEffect> kvp in m_plugineffects)
|
||||
{
|
||||
MainConsole.Instance.Output(kvp.Key);
|
||||
}
|
||||
|
@ -1665,46 +1658,65 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
|||
// Add this to our scene so scripts can call these functions
|
||||
m_scene.RegisterModuleCommander(m_commander);
|
||||
|
||||
// Add Feature command to Scene, since Command object requires fixed-length arglists
|
||||
m_scene.AddCommand("Terrain", this, "terrain feature",
|
||||
"terrain feature <type> <parameters...>", "Constructs a feature of the requested type.", FeatureCommand);
|
||||
// Add Modify command to Scene, since Command object requires fixed-length arglists
|
||||
m_scene.AddCommand("Terrain", this, "terrain modify",
|
||||
"terrain modify <operation> <value> [<area>] [<taper>]",
|
||||
"Modifies the terrain as instructed." +
|
||||
"\nEach operation can be limited to an area of effect:" +
|
||||
"\n * -ell=x,y,rx[,ry] constrains the operation to an ellipse centred at x,y" +
|
||||
"\n * -rec=x,y,dx[,dy] constrains the operation to a rectangle based at x,y" +
|
||||
"\nEach operation can have its effect tapered based on distance from centre:" +
|
||||
"\n * elliptical operations taper as cones" +
|
||||
"\n * rectangular operations taper as pyramids"
|
||||
,
|
||||
ModifyCommand);
|
||||
|
||||
}
|
||||
|
||||
public void FeatureCommand(string module, string[] cmd)
|
||||
public void ModifyCommand(string module, string[] cmd)
|
||||
{
|
||||
string result;
|
||||
if (cmd.Length > 2)
|
||||
Scene scene = SceneManager.Instance.CurrentScene;
|
||||
if ((scene != null) && (scene != m_scene))
|
||||
{
|
||||
string featureType = cmd[2];
|
||||
result = String.Empty;
|
||||
}
|
||||
else if (cmd.Length > 2)
|
||||
{
|
||||
string operationType = cmd[2];
|
||||
|
||||
ITerrainFeature feature;
|
||||
if (!m_featureEffects.TryGetValue(featureType, out feature))
|
||||
|
||||
ITerrainModifier operation;
|
||||
if (!m_modifyOperations.TryGetValue(operationType, out operation))
|
||||
{
|
||||
result = String.Format("Terrain Feature \"{0}\" not found.", featureType);
|
||||
result = String.Format("Terrain Modify \"{0}\" not found.", operationType);
|
||||
}
|
||||
else if ((cmd.Length > 3) && (cmd[3] == "usage"))
|
||||
else if ((cmd.Length > 3) && (cmd[3] == "usage"))
|
||||
{
|
||||
result = "Usage: " + feature.GetUsage();
|
||||
result = "Usage: " + operation.GetUsage();
|
||||
}
|
||||
else
|
||||
{
|
||||
result = feature.CreateFeature(m_channel, cmd);
|
||||
result = operation.ModifyTerrain(m_channel, cmd);
|
||||
}
|
||||
|
||||
if(result == String.Empty)
|
||||
if (result == String.Empty)
|
||||
{
|
||||
result = "Created Feature";
|
||||
m_log.DebugFormat("Created terrain feature {0}", featureType);
|
||||
result = "Modified terrain";
|
||||
m_log.DebugFormat("Performed terrain operation {0}", operationType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = "Usage: <feature-name> <arg1> <arg2>...";
|
||||
result = "Usage: <operation-name> <arg1> <arg2>...";
|
||||
}
|
||||
if (result != String.Empty)
|
||||
{
|
||||
MainConsole.Instance.Output(result);
|
||||
}
|
||||
MainConsole.Instance.Output(result);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -31,6 +31,6 @@ using Mono.Addins;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
[assembly: AddinRoot("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
|
||||
|
||||
|
|
|
@ -1653,7 +1653,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
// These variables will be used to save the precise frame time using the
|
||||
// Stopwatch class of Microsoft SDK; the times are recorded at the start
|
||||
// and end of a parcticular section of code, and then used to calculate
|
||||
// and end of a particular section of code, and then used to calculate
|
||||
// the frame times, which are the sums of the sections for each given name
|
||||
double preciseTotalFrameTime = 0.0;
|
||||
double preciseSimFrameTime = 0.0;
|
||||
|
@ -1698,7 +1698,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
// input took
|
||||
simFrameStopwatch.Stop();
|
||||
preciseSimFrameTime =
|
||||
simFrameStopwatch.Elapsed.TotalMilliseconds;
|
||||
simFrameStopwatch.Elapsed.TotalMilliseconds;
|
||||
terrainMS = Util.EnvironmentTickCountSubtract(tmpMS);
|
||||
}
|
||||
|
||||
|
@ -1717,7 +1717,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
// Begin the stopwatch to track the time to prepare physics
|
||||
physicsFrameStopwatch.Start();
|
||||
if (PhysicsEnabled && Frame % m_update_physics == 0)
|
||||
m_sceneGraph.UpdatePreparePhysics();
|
||||
m_sceneGraph.UpdatePreparePhysics();
|
||||
|
||||
// Get the time it took to prepare the physics, this
|
||||
// would report the most precise time that physics was
|
||||
|
@ -1738,7 +1738,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
// took
|
||||
simFrameStopwatch.Stop();
|
||||
preciseSimFrameTime +=
|
||||
simFrameStopwatch.Elapsed.TotalMilliseconds;
|
||||
simFrameStopwatch.Elapsed.TotalMilliseconds;
|
||||
agentMS = Util.EnvironmentTickCountSubtract(tmpMS);
|
||||
|
||||
// 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
|
|||
// Get the elapsed time for the simulation frame
|
||||
simFrameStopwatch.Stop();
|
||||
preciseSimFrameTime +=
|
||||
simFrameStopwatch.Elapsed.TotalMilliseconds;
|
||||
simFrameStopwatch.Elapsed.TotalMilliseconds;
|
||||
|
||||
if (!UpdateOnTimer)
|
||||
{
|
||||
|
@ -1872,7 +1872,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
// Get the total frame time
|
||||
totalFrameStopwatch.Stop();
|
||||
preciseTotalFrameTime =
|
||||
totalFrameStopwatch.Elapsed.TotalMilliseconds;
|
||||
totalFrameStopwatch.Elapsed.TotalMilliseconds;
|
||||
|
||||
// Restart the stopwatch for the total time of the next frame
|
||||
totalFrameStopwatch.Restart();
|
||||
|
@ -1897,7 +1897,7 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
// Send the correct time values to the stats reporter for the
|
||||
// frame times
|
||||
StatsReporter.addFrameTimeMilliseconds(preciseTotalFrameTime,
|
||||
preciseSimFrameTime, precisePhysicsFrameTime, 0.0);
|
||||
preciseSimFrameTime, precisePhysicsFrameTime, 0.0);
|
||||
|
||||
// Send the correct number of frames that the physics library
|
||||
// has processed to the stats reporter
|
||||
|
|
|
@ -2672,20 +2672,27 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
}
|
||||
else
|
||||
{
|
||||
//NonPhysicalGrabMovement(pos);
|
||||
NonPhysicalGrabMovement(pos);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//NonPhysicalGrabMovement(pos);
|
||||
NonPhysicalGrabMovement(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply possition for grabbing non-physical linksets (Ctrl+Drag)
|
||||
/// This MUST be blocked for linksets that contain touch scripts because the viewer triggers grab on the touch
|
||||
/// event (Viewer Bug?) This would allow anyone to drag a linkset with a touch script. SL behaviour is also to
|
||||
/// block grab on prims with touch events.
|
||||
/// </summary>
|
||||
/// <param name="pos">New Position</param>
|
||||
public void NonPhysicalGrabMovement(Vector3 pos)
|
||||
{
|
||||
AbsolutePosition = pos;
|
||||
m_rootPart.SendTerseUpdateToAllClients();
|
||||
if(!IsAttachment && ScriptCount() == 0)
|
||||
UpdateGroupPosition(pos);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -2781,16 +2788,27 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
}
|
||||
else
|
||||
{
|
||||
//NonPhysicalSpinMovement(pos);
|
||||
NonPhysicalSpinMovement(newOrientation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//NonPhysicalSpinMovement(pos);
|
||||
NonPhysicalSpinMovement(newOrientation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Apply rotation for spinning non-physical linksets (Ctrl+Shift+Drag)
|
||||
/// As with dragging, scripted objects must be blocked from spinning
|
||||
/// </summary>
|
||||
/// <param name="newOrientation">New Rotation</param>
|
||||
private void NonPhysicalSpinMovement(Quaternion newOrientation)
|
||||
{
|
||||
if(!IsAttachment && ScriptCount() == 0)
|
||||
UpdateGroupRotationR(newOrientation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the name of a prim
|
||||
/// </summary>
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using System.Linq;
|
||||
using Nini.Config;
|
||||
using NUnit.Framework;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Serialization.External;
|
||||
using OpenSim.Framework.Communications;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Region.Framework.Scenes.Serialization;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using OpenSim.Tests.Common;
|
||||
|
||||
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Basic scene object serialization tests.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class SceneObjectSerializationTests : OpenSimTestCase
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Serialize and deserialize.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestSerialDeserial()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
int partsToTestCount = 3;
|
||||
|
||||
SceneObjectGroup so
|
||||
= SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10);
|
||||
SceneObjectPart[] parts = so.Parts;
|
||||
so.Name = "obj1";
|
||||
so.Description = "xpto";
|
||||
|
||||
string xml = SceneObjectSerializer.ToXml2Format(so);
|
||||
Assert.That(!string.IsNullOrEmpty(xml), "SOG serialization resulted in empty or null string");
|
||||
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.LoadXml(xml);
|
||||
XmlNodeList nodes = doc.GetElementsByTagName("SceneObjectPart");
|
||||
Assert.That(nodes.Count, Is.EqualTo(3), "SOG serialization resulted in wrong number of SOPs");
|
||||
|
||||
SceneObjectGroup so2 = SceneObjectSerializer.FromXml2Format(xml);
|
||||
Assert.IsNotNull(so2, "SOG deserialization resulted in null object");
|
||||
Assert.That(so2.Name == so.Name, "Name of deserialized object does not match original name");
|
||||
Assert.That(so2.Description == so.Description, "Description of deserialized object does not match original name");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This checks for a bug reported in mantis #7514
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestNamespaceAttribute()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
UserAccount account = new UserAccount(UUID.Zero, UUID.Random(), "Test", "User", string.Empty);
|
||||
scene.UserAccountService.StoreUserAccount(account);
|
||||
int partsToTestCount = 1;
|
||||
|
||||
SceneObjectGroup so
|
||||
= SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10);
|
||||
SceneObjectPart[] parts = so.Parts;
|
||||
so.Name = "obj1";
|
||||
so.Description = "xpto";
|
||||
so.OwnerID = account.PrincipalID;
|
||||
so.RootPart.CreatorID = so.OwnerID;
|
||||
|
||||
string xml = SceneObjectSerializer.ToXml2Format(so);
|
||||
Assert.That(!string.IsNullOrEmpty(xml), "SOG serialization resulted in empty or null string");
|
||||
|
||||
xml = ExternalRepresentationUtils.RewriteSOP(xml, "Test Scene", "http://localhost", scene.UserAccountService, UUID.Zero);
|
||||
//Console.WriteLine(xml);
|
||||
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.LoadXml(xml);
|
||||
|
||||
XmlNodeList nodes = doc.GetElementsByTagName("SceneObjectPart");
|
||||
Assert.That(nodes.Count, Is.GreaterThan(0), "SOG serialization resulted in no SOPs");
|
||||
foreach (XmlAttribute a in nodes[0].Attributes)
|
||||
{
|
||||
int count = a.Name.Count(c => c == ':');
|
||||
Assert.That(count, Is.EqualTo(1), "Cannot have multiple ':' in attribute name in SOP");
|
||||
}
|
||||
nodes = doc.GetElementsByTagName("CreatorData");
|
||||
Assert.That(nodes.Count, Is.GreaterThan(0), "SOG serialization resulted in no CreatorData");
|
||||
foreach (XmlAttribute a in nodes[0].Attributes)
|
||||
{
|
||||
int count = a.Name.Count(c => c == ':');
|
||||
Assert.That(count, Is.EqualTo(1), "Cannot have multiple ':' in attribute name in CreatorData");
|
||||
}
|
||||
|
||||
SceneObjectGroup so2 = SceneObjectSerializer.FromXml2Format(xml);
|
||||
Assert.IsNotNull(so2, "SOG deserialization resulted in null object");
|
||||
Assert.AreNotEqual(so.RootPart.CreatorIdentification, so2.RootPart.CreatorIdentification, "RewriteSOP failed to transform CreatorData.");
|
||||
Assert.That(so2.RootPart.CreatorIdentification.Contains("http://"), "RewriteSOP failed to add the homeURL to CreatorData");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ using Mono.Addins;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
||||
[assembly: Addin("OpenSim.Region.OptionalModules", OpenSim.VersionInfo.VersionNumber)]
|
||||
|
|
|
@ -115,6 +115,9 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
|
|||
|
||||
private delegate T DefaultGetter<T>(string settingName, T defaultValue);
|
||||
private bool m_enabled;
|
||||
private ICommandConsole m_console;
|
||||
private List<Scene> m_Scenes = new List<Scene> ();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
|||
/// Currently a no-op for AutoBackup because we have to wait for region to be fully loaded.
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
void IRegionModuleBase.AddRegion(Scene scene)
|
||||
void IRegionModuleBase.AddRegion (Scene scene)
|
||||
{
|
||||
if (!this.m_enabled) {
|
||||
return;
|
||||
}
|
||||
lock (m_Scenes) {
|
||||
m_Scenes.Add (scene);
|
||||
}
|
||||
m_console = MainConsole.Instance;
|
||||
|
||||
m_console.Commands.AddCommand (
|
||||
"AutoBackup", false, "dobackup",
|
||||
"dobackup",
|
||||
"do backup.", DoBackup);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -220,7 +235,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Scenes.Remove (scene);
|
||||
if (this.m_states.ContainsKey(scene))
|
||||
{
|
||||
AutoBackupModuleState abms = this.m_states[scene];
|
||||
|
@ -275,6 +290,28 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
|
|||
|
||||
#endregion
|
||||
|
||||
private void DoBackup (string module, string[] args)
|
||||
{
|
||||
if (args.Length != 2) {
|
||||
MainConsole.Instance.OutputFormat ("Usage: dobackup <regionname>");
|
||||
return;
|
||||
}
|
||||
bool found = false;
|
||||
string name = args [1];
|
||||
lock (m_Scenes) {
|
||||
foreach (Scene s in m_Scenes) {
|
||||
string test = s.Name.ToString ();
|
||||
if (test == name) {
|
||||
found = true;
|
||||
DoRegionBackup (s);
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
MainConsole.Instance.OutputFormat ("No such region {0}. Nothing to backup", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set up internal state for a given scene. Fairly complex code.
|
||||
/// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene.
|
||||
|
|
|
@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all values by your own or you can build default build and revision
|
||||
// numbers with the '*' character (the default):
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all values by your own or you can build default build and revision
|
||||
// numbers with the '*' character (the default):
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
|
|
@ -84,7 +84,8 @@ namespace OpenSim.Region.Physics.Meshing
|
|||
private List<List<Vector3>> mConvexHulls = null;
|
||||
private List<Vector3> mBoundingHull = null;
|
||||
|
||||
private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
|
||||
// Mesh cache. Static so it can be shared across instances of this class
|
||||
private static Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
|
||||
|
||||
public Meshmerizer(IConfigSource config)
|
||||
{
|
||||
|
@ -927,8 +928,11 @@ namespace OpenSim.Region.Physics.Meshing
|
|||
if (shouldCache)
|
||||
{
|
||||
key = primShape.GetMeshKey(size, lod);
|
||||
if (m_uniqueMeshes.TryGetValue(key, out mesh))
|
||||
return mesh;
|
||||
lock (m_uniqueMeshes)
|
||||
{
|
||||
if (m_uniqueMeshes.TryGetValue(key, out mesh))
|
||||
return mesh;
|
||||
}
|
||||
}
|
||||
|
||||
if (size.X < 0.01f) size.X = 0.01f;
|
||||
|
@ -954,7 +958,10 @@ namespace OpenSim.Region.Physics.Meshing
|
|||
|
||||
if (shouldCache)
|
||||
{
|
||||
m_uniqueMeshes.Add(key, mesh);
|
||||
lock (m_uniqueMeshes)
|
||||
{
|
||||
m_uniqueMeshes.Add(key, mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all values by your own or you can build default build and revision
|
||||
// numbers with the '*' character (the default):
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
|
|
@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
|
|||
// You can specify all values by your own or you can build default build and revision
|
||||
// numbers with the '*' character (the default):
|
||||
|
||||
[assembly : AssemblyVersion("0.8.1.*")]
|
||||
[assembly : AssemblyVersion("0.8.2.*")]
|
||||
|
|
|
@ -30,7 +30,7 @@ using Mono.Addins;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
[assembly: Addin("OpenSim.RegionModules.RegionCombinerModule", OpenSim.VersionInfo.VersionNumber)]
|
||||
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -596,6 +596,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
|
|||
public const int OBJECT_PHYSICS = 21;
|
||||
public const int OBJECT_PHANTOM = 22;
|
||||
public const int OBJECT_TEMP_ON_REZ = 23;
|
||||
public const int OBJECT_RENDER_WEIGHT = 24;
|
||||
public const int OBJECT_HOVER_HEIGHT = 25;
|
||||
public const int OBJECT_BODY_SHAPE_TYPE = 26;
|
||||
public const int OBJECT_LAST_OWNER_ID = 27;
|
||||
|
||||
// Pathfinding types
|
||||
public const int OPT_OTHER = -1;
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ using Mono.Addins;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
[assembly: Addin("OpenSim.Region.ScriptEngine.XEngine", OpenSim.VersionInfo.VersionNumber)]
|
||||
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -82,7 +82,9 @@ namespace OpenSim.Server.Base
|
|||
argvConfig.AddSwitch("Startup", "logconfig", "g");
|
||||
|
||||
// Automagically create the ini file name
|
||||
string fileName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location);
|
||||
string fileName = "";
|
||||
if (Assembly.GetEntryAssembly() != null)
|
||||
fileName = Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location);
|
||||
string iniFile = fileName + ".ini";
|
||||
string logConfig = null;
|
||||
|
||||
|
@ -158,7 +160,11 @@ namespace OpenSim.Server.Base
|
|||
MainConsole.Instance = new RemoteConsole(prompt);
|
||||
((RemoteConsole)MainConsole.Instance).ReadConfig(Config);
|
||||
}
|
||||
else
|
||||
else if (consoleType == "mock")
|
||||
{
|
||||
MainConsole.Instance = new MockConsole();
|
||||
}
|
||||
else if (consoleType == "local")
|
||||
{
|
||||
MainConsole.Instance = new LocalConsole(prompt, startupConfig);
|
||||
}
|
||||
|
|
|
@ -41,7 +41,9 @@ using OpenSim.Server.Handlers.Base;
|
|||
using log4net;
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Server.Handlers.Asset
|
||||
using System.Threading;
|
||||
|
||||
namespace OpenSim.Server.Handlers.Inventory
|
||||
{
|
||||
public class XInventoryInConnector : ServiceConnector
|
||||
{
|
||||
|
@ -123,6 +125,8 @@ namespace OpenSim.Server.Handlers.Asset
|
|||
return HandleGetFolderForType(request);
|
||||
case "GETFOLDERCONTENT":
|
||||
return HandleGetFolderContent(request);
|
||||
case "GETMULTIPLEFOLDERSCONTENT":
|
||||
return HandleGetMultipleFoldersContent(request);
|
||||
case "GETFOLDERITEMS":
|
||||
return HandleGetFolderItems(request);
|
||||
case "ADDFOLDER":
|
||||
|
@ -145,6 +149,8 @@ namespace OpenSim.Server.Handlers.Asset
|
|||
return HandleDeleteItems(request);
|
||||
case "GETITEM":
|
||||
return HandleGetItem(request);
|
||||
case "GETMULTIPLEITEMS":
|
||||
return HandleGetMultipleItems(request);
|
||||
case "GETFOLDER":
|
||||
return HandleGetFolder(request);
|
||||
case "GETACTIVEGESTURES":
|
||||
|
@ -284,6 +290,8 @@ namespace OpenSim.Server.Handlers.Asset
|
|||
InventoryCollection icoll = m_InventoryService.GetFolderContent(principal, folderID);
|
||||
if (icoll != null)
|
||||
{
|
||||
result["FID"] = icoll.FolderID.ToString();
|
||||
result["VERSION"] = icoll.Version.ToString();
|
||||
Dictionary<string, object> folders = new Dictionary<string, object>();
|
||||
int i = 0;
|
||||
if (icoll.Folders != null)
|
||||
|
@ -314,7 +322,71 @@ namespace OpenSim.Server.Handlers.Asset
|
|||
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
|
||||
}
|
||||
|
||||
byte[] HandleGetFolderItems(Dictionary<string,object> request)
|
||||
byte[] HandleGetMultipleFoldersContent(Dictionary<string, object> request)
|
||||
{
|
||||
Dictionary<string, object> resultSet = new Dictionary<string, object>();
|
||||
UUID principal = UUID.Zero;
|
||||
UUID.TryParse(request["PRINCIPAL"].ToString(), out principal);
|
||||
string folderIDstr = request["FOLDERS"].ToString();
|
||||
int count = 0;
|
||||
Int32.TryParse(request["COUNT"].ToString(), out count);
|
||||
|
||||
UUID[] fids = new UUID[count];
|
||||
string[] uuids = folderIDstr.Split(',');
|
||||
int i = 0;
|
||||
foreach (string id in uuids)
|
||||
{
|
||||
UUID fid = UUID.Zero;
|
||||
if (UUID.TryParse(id, out fid))
|
||||
fids[i] = fid;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
InventoryCollection[] icollList = m_InventoryService.GetMultipleFoldersContent(principal, fids);
|
||||
if (icollList != null && icollList.Length > 0)
|
||||
{
|
||||
foreach (InventoryCollection icoll in icollList)
|
||||
{
|
||||
Dictionary<string, object> result = new Dictionary<string, object>();
|
||||
result["FID"] = icoll.FolderID.ToString();
|
||||
result["VERSION"] = icoll.Version.ToString();
|
||||
result["OWNER"] = icoll.OwnerID.ToString();
|
||||
Dictionary<string, object> folders = new Dictionary<string, object>();
|
||||
i = 0;
|
||||
if (icoll.Folders != null)
|
||||
{
|
||||
foreach (InventoryFolderBase f in icoll.Folders)
|
||||
{
|
||||
folders["folder_" + i.ToString()] = EncodeFolder(f);
|
||||
i++;
|
||||
}
|
||||
result["FOLDERS"] = folders;
|
||||
}
|
||||
i = 0;
|
||||
if (icoll.Items != null)
|
||||
{
|
||||
Dictionary<string, object> items = new Dictionary<string, object>();
|
||||
foreach (InventoryItemBase it in icoll.Items)
|
||||
{
|
||||
items["item_" + i.ToString()] = EncodeItem(it);
|
||||
i++;
|
||||
}
|
||||
result["ITEMS"] = items;
|
||||
}
|
||||
|
||||
resultSet["F_" + fids[count++]] = result;
|
||||
//m_log.DebugFormat("[XXX]: Sending {0} {1}", fids[count-1], icoll.FolderID);
|
||||
}
|
||||
}
|
||||
|
||||
string xmlString = ServerUtils.BuildXmlResponse(resultSet);
|
||||
|
||||
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
|
||||
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
|
||||
}
|
||||
|
||||
byte[] HandleGetFolderItems(Dictionary<string, object> request)
|
||||
{
|
||||
Dictionary<string,object> result = new Dictionary<string,object>();
|
||||
UUID principal = UUID.Zero;
|
||||
|
@ -506,6 +578,40 @@ namespace OpenSim.Server.Handlers.Asset
|
|||
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
|
||||
}
|
||||
|
||||
byte[] HandleGetMultipleItems(Dictionary<string, object> request)
|
||||
{
|
||||
Dictionary<string, object> resultSet = new Dictionary<string, object>();
|
||||
UUID principal = UUID.Zero;
|
||||
UUID.TryParse(request["PRINCIPAL"].ToString(), out principal);
|
||||
string itemIDstr = request["ITEMS"].ToString();
|
||||
int count = 0;
|
||||
Int32.TryParse(request["COUNT"].ToString(), out count);
|
||||
|
||||
UUID[] fids = new UUID[count];
|
||||
string[] uuids = itemIDstr.Split(',');
|
||||
int i = 0;
|
||||
foreach (string id in uuids)
|
||||
{
|
||||
UUID fid = UUID.Zero;
|
||||
if (UUID.TryParse(id, out fid))
|
||||
fids[i] = fid;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
InventoryItemBase[] itemsList = m_InventoryService.GetMultipleItems(principal, fids);
|
||||
if (itemsList != null && itemsList.Length > 0)
|
||||
{
|
||||
count = 0;
|
||||
foreach (InventoryItemBase item in itemsList)
|
||||
resultSet["item_" + count++] = (item == null) ? (object)"NULL" : EncodeItem(item);
|
||||
}
|
||||
|
||||
string xmlString = ServerUtils.BuildXmlResponse(resultSet);
|
||||
|
||||
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
|
||||
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
|
||||
}
|
||||
|
||||
byte[] HandleGetFolder(Dictionary<string,object> request)
|
||||
{
|
||||
Dictionary<string, object> result = new Dictionary<string, object>();
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -257,8 +257,7 @@ namespace OpenSim.Server.Handlers.UserAccounts
|
|||
|
||||
byte[] CreateUser(Dictionary<string, object> request)
|
||||
{
|
||||
if (!
|
||||
request.ContainsKey("FirstName")
|
||||
if (! request.ContainsKey("FirstName")
|
||||
&& request.ContainsKey("LastName")
|
||||
&& request.ContainsKey("Password"))
|
||||
return FailureResult();
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ using OpenSim.Services.Connectors;
|
|||
using OpenSim.Services.Interfaces;
|
||||
using OpenSim.Server.Base;
|
||||
|
||||
namespace OpenSim.Service.Connectors
|
||||
namespace OpenSim.Services.Connectors
|
||||
{
|
||||
public class EstateDataRemoteConnector : BaseServiceConnector, IEstateDataService
|
||||
{
|
||||
|
|
|
@ -205,7 +205,7 @@ namespace OpenSim.Services.Connectors
|
|||
InventoryCollection inventory = new InventoryCollection();
|
||||
inventory.Folders = new List<InventoryFolderBase>();
|
||||
inventory.Items = new List<InventoryItemBase>();
|
||||
inventory.UserID = principalID;
|
||||
inventory.OwnerID = principalID;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -235,6 +235,87 @@ namespace OpenSim.Services.Connectors
|
|||
|
||||
return inventory;
|
||||
}
|
||||
|
||||
public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
|
||||
{
|
||||
InventoryCollection[] inventoryArr = new InventoryCollection[folderIDs.Length];
|
||||
//m_log.DebugFormat("[XXX]: In GetMultipleFoldersContent {0}", folderIDs.Length);
|
||||
try
|
||||
{
|
||||
Dictionary<string, object> resultSet = MakeRequest("GETMULTIPLEFOLDERSCONTENT",
|
||||
new Dictionary<string, object> {
|
||||
{ "PRINCIPAL", principalID.ToString() },
|
||||
{ "FOLDERS", String.Join(",", folderIDs) },
|
||||
{ "COUNT", folderIDs.Length.ToString() }
|
||||
});
|
||||
|
||||
if (!CheckReturn(resultSet))
|
||||
return null;
|
||||
|
||||
int i = 0;
|
||||
foreach (KeyValuePair<string, object> kvp in resultSet)
|
||||
{
|
||||
InventoryCollection inventory = new InventoryCollection();
|
||||
if (kvp.Key.StartsWith("F_"))
|
||||
{
|
||||
UUID fid = UUID.Zero;
|
||||
if (UUID.TryParse(kvp.Key.Substring(2), out fid) && fid == folderIDs[i])
|
||||
{
|
||||
inventory.Folders = new List<InventoryFolderBase>();
|
||||
inventory.Items = new List<InventoryItemBase>();
|
||||
|
||||
Dictionary<string, object> ret = (Dictionary<string, object>)kvp.Value;
|
||||
|
||||
if (ret.ContainsKey("FID"))
|
||||
{
|
||||
if (!UUID.TryParse(ret["FID"].ToString(), out inventory.FolderID))
|
||||
m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Could not parse folder id {0}", ret["FID"].ToString());
|
||||
}
|
||||
else
|
||||
m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: FID key not present in response");
|
||||
|
||||
inventory.Version = -1;
|
||||
if (ret.ContainsKey("VERSION"))
|
||||
Int32.TryParse(ret["VERSION"].ToString(), out inventory.Version);
|
||||
if (ret.ContainsKey("OWNER"))
|
||||
UUID.TryParse(ret["OWNER"].ToString(), out inventory.OwnerID);
|
||||
|
||||
//m_log.DebugFormat("[XXX]: Received {0} ({1}) {2} {3}", inventory.FolderID, fid, inventory.Version, inventory.OwnerID);
|
||||
|
||||
Dictionary<string, object> folders =
|
||||
(Dictionary<string, object>)ret["FOLDERS"];
|
||||
Dictionary<string, object> items =
|
||||
(Dictionary<string, object>)ret["ITEMS"];
|
||||
|
||||
foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i
|
||||
{
|
||||
inventory.Folders.Add(BuildFolder((Dictionary<string, object>)o));
|
||||
}
|
||||
foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i
|
||||
{
|
||||
inventory.Items.Add(BuildItem((Dictionary<string, object>)o));
|
||||
}
|
||||
|
||||
inventoryArr[i] = inventory;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Folder id does not match. Expected {0} got {1}",
|
||||
folderIDs[i], fid);
|
||||
m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: {0} {1}", String.Join(",", folderIDs), String.Join(",", resultSet.Keys));
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetMultipleFoldersContent: {0}", e.Message);
|
||||
}
|
||||
|
||||
return inventoryArr;
|
||||
}
|
||||
|
||||
public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID)
|
||||
{
|
||||
|
@ -325,9 +406,13 @@ namespace OpenSim.Services.Connectors
|
|||
|
||||
public bool AddItem(InventoryItemBase item)
|
||||
{
|
||||
if (item.Description == null)
|
||||
item.Description = String.Empty;
|
||||
if (item.CreatorData == null)
|
||||
item.CreatorData = String.Empty;
|
||||
Dictionary<string,object> ret = MakeRequest("ADDITEM",
|
||||
if (item.CreatorId == null)
|
||||
item.CreatorId = String.Empty;
|
||||
Dictionary<string, object> ret = MakeRequest("ADDITEM",
|
||||
new Dictionary<string,object> {
|
||||
{ "AssetID", item.AssetID.ToString() },
|
||||
{ "AssetType", item.AssetType.ToString() },
|
||||
|
@ -446,6 +531,42 @@ namespace OpenSim.Services.Connectors
|
|||
return null;
|
||||
}
|
||||
|
||||
public virtual InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs)
|
||||
{
|
||||
InventoryItemBase[] itemArr = new InventoryItemBase[itemIDs.Length];
|
||||
try
|
||||
{
|
||||
Dictionary<string, object> resultSet = MakeRequest("GETMULTIPLEITEMS",
|
||||
new Dictionary<string, object> {
|
||||
{ "PRINCIPAL", principalID.ToString() },
|
||||
{ "ITEMS", String.Join(",", itemIDs) },
|
||||
{ "COUNT", itemIDs.Length.ToString() }
|
||||
});
|
||||
|
||||
if (!CheckReturn(resultSet))
|
||||
return null;
|
||||
|
||||
int i = 0;
|
||||
foreach (KeyValuePair<string, object> kvp in resultSet)
|
||||
{
|
||||
InventoryCollection inventory = new InventoryCollection();
|
||||
if (kvp.Key.StartsWith("item_"))
|
||||
{
|
||||
if (kvp.Value is Dictionary<string, object>)
|
||||
itemArr[i++] = BuildItem((Dictionary<string, object>)kvp.Value);
|
||||
else
|
||||
itemArr[i++] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.WarnFormat("[XINVENTORY SERVICES CONNECTOR]: Exception in GetMultipleItems: {0}", e.Message);
|
||||
}
|
||||
|
||||
return itemArr;
|
||||
}
|
||||
|
||||
public InventoryFolderBase GetFolder(InventoryFolderBase folder)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -301,6 +301,21 @@ namespace OpenSim.Services.Connectors.SimianGrid
|
|||
return null;
|
||||
}
|
||||
|
||||
public InventoryItemBase[] GetMultipleItems(UUID principalID, UUID[] itemIDs)
|
||||
{
|
||||
InventoryItemBase[] result = new InventoryItemBase[itemIDs.Length];
|
||||
int i = 0;
|
||||
InventoryItemBase item = new InventoryItemBase();
|
||||
item.Owner = principalID;
|
||||
foreach (UUID id in itemIDs)
|
||||
{
|
||||
item.ID = id;
|
||||
result[i++] = GetItem(item);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a folder, given by its UUID
|
||||
/// </summary>
|
||||
|
@ -340,7 +355,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
|
|||
public InventoryCollection GetFolderContent(UUID userID, UUID folderID)
|
||||
{
|
||||
InventoryCollection inventory = new InventoryCollection();
|
||||
inventory.UserID = userID;
|
||||
inventory.OwnerID = userID;
|
||||
|
||||
NameValueCollection requestArgs = new NameValueCollection
|
||||
{
|
||||
|
@ -371,6 +386,18 @@ namespace OpenSim.Services.Connectors.SimianGrid
|
|||
return inventory;
|
||||
}
|
||||
|
||||
public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
|
||||
{
|
||||
InventoryCollection[] invColl = new InventoryCollection[folderIDs.Length];
|
||||
int i = 0;
|
||||
foreach (UUID fid in folderIDs)
|
||||
{
|
||||
invColl[i++] = GetFolderContent(principalID, fid);
|
||||
}
|
||||
|
||||
return invColl;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the items inside a folder
|
||||
/// </summary>
|
||||
|
@ -380,7 +407,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
|
|||
public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
|
||||
{
|
||||
InventoryCollection inventory = new InventoryCollection();
|
||||
inventory.UserID = userID;
|
||||
inventory.OwnerID = userID;
|
||||
|
||||
NameValueCollection requestArgs = new NameValueCollection
|
||||
{
|
||||
|
|
|
@ -215,9 +215,39 @@ namespace OpenSim.Services.Connectors
|
|||
sendData[kvp.Key] = kvp.Value.ToString();
|
||||
}
|
||||
|
||||
return SendAndGetBoolReply(sendData);
|
||||
if (SendAndGetReply(sendData) != null)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create user remotely. Note this this is not part of the IUserAccountsService
|
||||
/// </summary>
|
||||
/// <param name="first"></param>
|
||||
/// <param name="last"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="scopeID"></param>
|
||||
/// <returns></returns>
|
||||
public virtual UserAccount CreateUser(string first, string last, string password, string email, UUID scopeID)
|
||||
{
|
||||
Dictionary<string, object> sendData = new Dictionary<string, object>();
|
||||
//sendData["SCOPEID"] = scopeID.ToString();
|
||||
sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString();
|
||||
sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString();
|
||||
sendData["METHOD"] = "createuser";
|
||||
|
||||
sendData["FirstName"] = first;
|
||||
sendData["LastName"] = last;
|
||||
sendData["Password"] = password;
|
||||
if (!string.IsNullOrEmpty(email))
|
||||
sendData["Email"] = first;
|
||||
sendData["ScopeID"] = scopeID.ToString();
|
||||
|
||||
return SendAndGetReply(sendData);
|
||||
}
|
||||
|
||||
private UserAccount SendAndGetReply(Dictionary<string, object> sendData)
|
||||
{
|
||||
string reply = string.Empty;
|
||||
|
@ -260,7 +290,7 @@ namespace OpenSim.Services.Connectors
|
|||
{
|
||||
string reqString = ServerUtils.BuildQueryString(sendData);
|
||||
string uri = m_ServerURI + "/accounts";
|
||||
// m_log.DebugFormat("[ACCOUNTS CONNECTOR]: queryString = {0}", reqString);
|
||||
//m_log.DebugFormat("[ACCOUNTS CONNECTOR]: queryString = {0}", reqString);
|
||||
try
|
||||
{
|
||||
string reply = SynchronousRestFormsRequester.MakeRequest("POST",
|
||||
|
@ -269,6 +299,7 @@ namespace OpenSim.Services.Connectors
|
|||
m_Auth);
|
||||
if (reply != string.Empty)
|
||||
{
|
||||
//m_log.DebugFormat("[ACCOUNTS CONNECTOR]: reply = {0}", reply);
|
||||
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
|
||||
|
||||
if (replyData.ContainsKey("result"))
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
|
@ -163,7 +163,7 @@ namespace OpenSim.Services.HypergridService
|
|||
protected byte[] AdjustIdentifiers(byte[] data)
|
||||
{
|
||||
string xml = Utils.BytesToString(data);
|
||||
return Utils.StringToBytes(ExternalRepresentationUtils.RewriteSOP(xml, m_HomeURL, m_Cache, UUID.Zero));
|
||||
return Utils.StringToBytes(ExternalRepresentationUtils.RewriteSOP(xml, "HGAssetService", m_HomeURL, m_Cache, UUID.Zero));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -101,7 +101,14 @@ namespace OpenSim.Services.HypergridService
|
|||
Object[] args = new Object[] { config };
|
||||
m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
|
||||
m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args);
|
||||
m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(userAgentService, args);
|
||||
try
|
||||
{
|
||||
m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(userAgentService, args);
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_log.WarnFormat("[HG IM SERVICE]: Unable to create User Agent Service. Missing config var in [HGInstantMessageService]?");
|
||||
}
|
||||
|
||||
m_RegionCache = new ExpiringCache<UUID, GridRegion>();
|
||||
|
||||
|
|
|
@ -153,7 +153,14 @@ namespace OpenSim.Services.HypergridService
|
|||
//public InventoryCollection GetFolderContent(UUID principalID, UUID folderID)
|
||||
//{
|
||||
//}
|
||||
|
||||
|
||||
// NOGO
|
||||
//
|
||||
public override InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderID)
|
||||
{
|
||||
return new InventoryCollection[0];
|
||||
}
|
||||
|
||||
//public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID)
|
||||
//{
|
||||
//}
|
||||
|
|
|
@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
|
|||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("0.8.1.*")]
|
||||
[assembly: AssemblyVersion("0.8.2.*")]
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue