Merging Opensim upstream before generating patch

fsassets
Michael Heilmann 2015-05-19 15:18:45 -04:00
commit 140ea04b9d
136 changed files with 32587 additions and 18424 deletions

View File

@ -30,7 +30,7 @@ using Mono.Addins;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]
[assembly: Addin("OpenSim.Groups", OpenSim.VersionInfo.VersionNumber)] [assembly: Addin("OpenSim.Groups", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]

View File

@ -30,7 +30,7 @@ using Mono.Addins;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]
[assembly: Addin("OpenSim.OfflineIM", OpenSim.VersionInfo.VersionNumber)] [assembly: Addin("OpenSim.OfflineIM", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]

View File

@ -63,7 +63,7 @@ using Mono.Addins;
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("0.7.6.*")] // [assembly: AssemblyVersion("0.7.6.*")]
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]
[assembly: Addin("OpenSim.ApplicationPlugins.LoadRegions", OpenSim.VersionInfo.VersionNumber)] [assembly: Addin("OpenSim.ApplicationPlugins.LoadRegions", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)]

View File

@ -30,7 +30,7 @@ using Mono.Addins;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]
[assembly: Addin("OpenSim.ApplicationPlugins.RegionModulesController", OpenSim.VersionInfo.VersionNumber)] [assembly: Addin("OpenSim.ApplicationPlugins.RegionModulesController", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)]

View File

@ -30,7 +30,7 @@ using Mono.Addins;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]
[assembly: Addin("OpenSim.ApplicationPlugins.RemoteController", OpenSim.VersionInfo.VersionNumber)] [assembly: Addin("OpenSim.ApplicationPlugins.RemoteController", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)]

View File

@ -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;
}
}

View File

@ -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");
}
}
}

View File

@ -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;
}
}
}

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers // You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers // You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers // You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers // You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers // You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -59,4 +59,4 @@ using System.Runtime.InteropServices;
// Revision // Revision
// //
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers // You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
// You can specify all values by your own or you can build default build and revision // You can specify all values by your own or you can build default build and revision
// numbers with the '*' character (the default): // numbers with the '*' character (the default):
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -37,6 +37,8 @@ namespace OpenSim.Framework
{ {
public List<InventoryFolderBase> Folders; public List<InventoryFolderBase> Folders;
public List<InventoryItemBase> Items; public List<InventoryItemBase> Items;
public UUID UserID; public UUID OwnerID;
public UUID FolderID;
public int Version;
} }
} }

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -125,7 +125,8 @@ namespace OpenSim.Framework.Serialization.External
/// <param name="userService">The service for retrieving user account information</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> /// <param name="scopeID">The scope of the user account information (Grid ID)</param>
/// <returns>The SceneObjectPart represented in XML2</returns> /// <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) if (xml == string.Empty || homeURL == string.Empty || userService == null)
return xml; 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) public static string CalcCreatorData(string homeURL, string name)
{ {
return homeURL + ";" + name; return homeURL + ";" + name;

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -292,11 +292,11 @@ namespace OpenSim.Framework.Servers
+ " 3 = full stack trace, including common threads\n", + " 3 = full stack trace, including common threads\n",
HandleDebugThreadpoolLevel); HandleDebugThreadpoolLevel);
m_console.Commands.AddCommand( // m_console.Commands.AddCommand(
"Debug", false, "show threadpool calls active", // "Debug", false, "show threadpool calls active",
"show threadpool calls active", // "show threadpool calls active",
"Show details about threadpool calls that are still active (currently waiting or in progress)", // "Show details about threadpool calls that are still active (currently waiting or in progress)",
HandleShowThreadpoolCallsActive); // HandleShowThreadpoolCallsActive);
m_console.Commands.AddCommand( m_console.Commands.AddCommand(
"Debug", false, "show threadpool calls complete", "Debug", false, "show threadpool calls complete",

View File

@ -30,7 +30,7 @@ using Mono.Addins;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]
[assembly: AddinRoot("OpenSim", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinRoot("OpenSim", OpenSim.VersionInfo.VersionNumber)]
[assembly: ImportAddinAssembly("OpenSim.Framework.dll")] [assembly: ImportAddinAssembly("OpenSim.Framework.dll")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -201,11 +201,12 @@ namespace OpenSim.Region.ClientStack.Linden
Scene.EventManager.OnRegisterCaps += RegisterCaps; Scene.EventManager.OnRegisterCaps += RegisterCaps;
int nworkers = 2; // was 2
if (ProcessQueuedRequestsAsync && m_workerThreads == null) 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, m_workerThreads[i] = WorkManager.StartThread(DoInventoryRequests,
String.Format("InventoryWorkerThread{0}", i), String.Format("InventoryWorkerThread{0}", i),
@ -364,7 +365,11 @@ namespace OpenSim.Region.ClientStack.Linden
requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null); requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
lock (responses) 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; responses[requestID] = response;
}
WebFetchInvDescModule.ProcessedRequestsCount++; WebFetchInvDescModule.ProcessedRequestsCount++;
} }

View File

@ -3747,6 +3747,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
avp.Sender.IsTrial = false; avp.Sender.IsTrial = false;
avp.Sender.ID = agentID; avp.Sender.ID = agentID;
avp.AppearanceData = new AvatarAppearancePacket.AppearanceDataBlock[0]; 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()); //m_log.DebugFormat("[CLIENT]: Sending appearance for {0} to {1}", agentID.ToString(), AgentId.ToString());
OutPacket(avp, ThrottleOutPacketType.Task); OutPacket(avp, ThrottleOutPacketType.Task);
} }
@ -4465,7 +4466,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
uint priority = 0; // time based ordering only uint priority = 0; // time based ordering only
lock (m_entityProps.SyncRoot) 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) private void ResendPropertyUpdate(ObjectPropertyUpdate update)

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -35,6 +35,7 @@ using System.Xml;
using log4net; using log4net;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Framework.Serialization.External;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Scenes.Serialization; using OpenSim.Region.Framework.Scenes.Serialization;
@ -189,217 +190,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
return Utils.StringToBytes(RewriteSOP(xml)); 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) protected string RewriteSOP(string xmlData)
{ {
// Console.WriteLine("Input XML [{0}]", 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 // TODO: unused

View File

@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library
{ {
InventoryFolderImpl folder = null; InventoryFolderImpl folder = null;
InventoryCollection inv = new InventoryCollection(); InventoryCollection inv = new InventoryCollection();
inv.UserID = m_Library.Owner; inv.OwnerID = m_Library.Owner;
if (folderID != m_Library.ID) if (folderID != m_Library.ID)
{ {
@ -87,6 +87,34 @@ namespace OpenSim.Region.CoreModules.Framework.Library
return inv; 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> /// <summary>
/// Add a new folder to the user's inventory /// Add a new folder to the user's inventory
/// </summary> /// </summary>

View File

@ -154,7 +154,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
#endregion ISharedRegionModule #endregion ISharedRegionModule
#region Event Handlers #region Event Handlers
void EventManager_OnPrimsLoaded(Scene s) void EventManager_OnPrimsLoaded(Scene s)
@ -180,7 +180,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
void HandleUUIDNameRequest(UUID uuid, IClientAPI client) void HandleUUIDNameRequest(UUID uuid, IClientAPI client)
{ {
// m_log.DebugFormat( // 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); // uuid, remote_client.Name);
if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) 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. // appear to clear this when the user asks it to clear the cache, but others may not.
// //
// So to avoid clients // 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. // instead drop the request entirely.
if (GetUser(uuid, out user)) if (GetUser(uuid, out user))
{ {
@ -220,7 +220,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
} }
// else // else
// m_log.DebugFormat( // 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); // uuid, client.Name);
}); });
} }
@ -416,7 +416,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
m_log.Debug("[USER MANAGEMENT MODULE]: GetServerURLs call failed ", e); m_log.Debug("[USER MANAGEMENT MODULE]: GetServerURLs call failed ", e);
userdata.ServerURLs = new Dictionary<string, object>(); userdata.ServerURLs = new Dictionary<string, object>();
} }
if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null) if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
return userdata.ServerURLs[serverType].ToString(); return userdata.ServerURLs[serverType].ToString();
} }
@ -620,7 +620,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
AddUser(id, string.Empty, string.Empty, string.Empty); AddUser(id, string.Empty, string.Empty, string.Empty);
} }
else else
{ {
string homeURL; string homeURL;
string firstname = string.Empty; string firstname = string.Empty;
string lastname = string.Empty; string lastname = string.Empty;
@ -676,7 +676,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
else else
{ {
lock(m_UserCache) lock(m_UserCache)
{ {
if(!m_UserCache.ContainsKey(id)) if(!m_UserCache.ContainsKey(id))
{ {
UserData newUser = new UserData(); UserData newUser = new UserData();
@ -726,6 +726,21 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
"Show the bindings between user UUIDs and user names", "Show the bindings between user UUIDs and user names",
String.Empty, String.Empty,
HandleShowUsers); 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) private void HandleShowUser(string module, string[] cmd)

View File

@ -30,7 +30,7 @@ using Mono.Addins;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]
[assembly: Addin("OpenSim.Region.CoreModules", OpenSim.VersionInfo.VersionNumber)] [assembly: Addin("OpenSim.Region.CoreModules", OpenSim.VersionInfo.VersionNumber)]

View File

@ -389,6 +389,25 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
return connector.GetFolderContent(userID, folderID); 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) public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
{ {
//m_log.Debug("[HG INVENTORY CONNECTOR]: GetFolderItems " + folderID); //m_log.Debug("[HG INVENTORY CONNECTOR]: GetFolderItems " + folderID);
@ -596,6 +615,23 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
return connector.GetItem(item); 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) public InventoryFolderBase GetFolder(InventoryFolderBase folder)
{ {
if (folder == null) if (folder == null)

View File

@ -106,7 +106,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
if (m_Inventories.TryGetValue(userID, out inv)) if (m_Inventories.TryGetValue(userID, out inv))
{ {
c = new InventoryCollection(); c = new InventoryCollection();
c.UserID = userID; c.OwnerID = userID;
c.Folders = inv.Folders.FindAll(delegate(InventoryFolderBase f) c.Folders = inv.Folders.FindAll(delegate(InventoryFolderBase f)
{ {

View File

@ -195,6 +195,19 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
return invCol; 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) public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
{ {
return m_InventoryService.GetFolderItems(userID, folderID); return m_InventoryService.GetFolderItems(userID, folderID);
@ -294,6 +307,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
return item; return item;
} }
public InventoryItemBase[] GetMultipleItems(UUID userID, UUID[] itemIDs)
{
return m_InventoryService.GetMultipleItems(userID, itemIDs);
}
public InventoryFolderBase GetFolder(InventoryFolderBase folder) public InventoryFolderBase GetFolder(InventoryFolderBase folder)
{ {
return m_InventoryService.GetFolder(folder); return m_InventoryService.GetFolder(folder);

View File

@ -204,6 +204,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
return invCol; return invCol;
} }
public virtual InventoryCollection[] GetMultipleFoldersContent(UUID principalID, UUID[] folderIDs)
{
return m_RemoteConnector.GetMultipleFoldersContent(principalID, folderIDs);
}
public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
{ {
return m_RemoteConnector.GetFolderItems(userID, folderID); return m_RemoteConnector.GetFolderItems(userID, folderID);
@ -298,6 +303,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory
return m_RemoteConnector.GetItem(item); 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) public InventoryFolderBase GetFolder(InventoryFolderBase folder)
{ {
//m_log.DebugFormat("[XINVENTORY CONNECTOR]: GetFolder {0}", folder.ID); //m_log.DebugFormat("[XINVENTORY CONNECTOR]: GetFolder {0}", folder.ID);

View File

@ -335,7 +335,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home")) if (asset.Type == (sbyte)AssetType.Object && asset.Data != null && m_options.ContainsKey("home"))
{ {
//m_log.DebugFormat("[ARCHIVER]: Rewriting object data for {0}", asset.ID); //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); asset.Data = Utils.StringToBytes(xml);
} }
return asset; return asset;

View File

@ -98,11 +98,17 @@ namespace OpenSim.Region.CoreModules.World.Land
// caches ExtendedLandData // caches ExtendedLandData
private Cache parcelInfoCache; private Cache parcelInfoCache;
/// <summary> /// <summary>
/// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions. /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions.
/// </summary> /// </summary>
private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>(); 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 #region INonSharedRegionModule Members
public Type ReplaceableInterface public Type ReplaceableInterface
@ -112,6 +118,14 @@ namespace OpenSim.Region.CoreModules.World.Land
public void Initialise(IConfigSource source) 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) public void AddRegion(Scene scene)
@ -1129,11 +1143,26 @@ namespace OpenSim.Region.CoreModules.World.Land
#region Parcel Updating #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> /// <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> /// </summary>
/// <param name="remote_client">The object representing the client</param> /// <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; const int LAND_BLOCKS_PER_PACKET = 1024;
@ -1141,15 +1170,58 @@ namespace OpenSim.Region.CoreModules.World.Land
int byteArrayCount = 0; int byteArrayCount = 0;
int sequenceID = 0; int sequenceID = 0;
// Layer data is in landUnit (4m) chunks int xLow = 0;
for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++) 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); byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * LandUnit, y * LandUnit), x, y, remote_client);
byteArrayCount++; byteArrayCount++;
if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
{ {
// m_log.DebugFormat("{0} SendParcelOverlay, sending packet, bytes={1}", LogHeader, byteArray.Length);
remote_client.SendLandParcelOverlay(byteArray, sequenceID); remote_client.SendLandParcelOverlay(byteArray, sequenceID);
byteArrayCount = 0; byteArrayCount = 0;
sequenceID++; sequenceID++;
@ -1162,6 +1234,7 @@ namespace OpenSim.Region.CoreModules.World.Land
if (byteArrayCount != 0) if (byteArrayCount != 0)
{ {
remote_client.SendLandParcelOverlay(byteArray, sequenceID); 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); 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) public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client)

View File

@ -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>]";
}
}
}

View File

@ -24,65 +24,53 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System;
using System.Reflection;
using System;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
namespace OpenSim.Region.CoreModules.World.Terrain 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) /// <summary>
{ /// Gets a string describing the usage.
m_module = module; /// </summary>
} /// <returns>
/// A string describing parameters for creating the feature.
public abstract string CreateFeature(ITerrainChannel map, string[] args); /// Format is "feature-name <arg1> <arg2> ..."
/// </returns>
public abstract string GetUsage(); 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>
/// 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);
} }
} }

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -24,7 +24,6 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -42,7 +41,7 @@ using OpenSim.Framework;
using OpenSim.Framework.Console; using OpenSim.Framework.Console;
using OpenSim.Region.CoreModules.Framework.InterfaceCommander; using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; 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.FloodBrushes;
using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes; using OpenSim.Region.CoreModules.World.Terrain.PaintBrushes;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
@ -75,14 +74,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
#endregion #endregion
/// <summary>
/// Terrain Features
/// </summary>
public enum TerrainFeatures: byte
{
Rectangle = 1,
}
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
#pragma warning disable 414 #pragma warning disable 414
@ -90,26 +81,19 @@ namespace OpenSim.Region.CoreModules.World.Terrain
#pragma warning restore 414 #pragma warning restore 414
private readonly Commander m_commander = new Commander("terrain"); private readonly Commander m_commander = new Commander("terrain");
private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects = private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects =
new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>(); new Dictionary<StandardTerrainEffects, ITerrainFloodEffect>();
private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>(); private readonly Dictionary<string, ITerrainLoader> m_loaders = new Dictionary<string, ITerrainLoader>();
private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects = private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects =
new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>(); new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>();
private Dictionary<string, ITerrainEffect> m_plugineffects; private Dictionary<string, ITerrainEffect> m_plugineffects;
private Dictionary<string, ITerrainModifier> m_modifyOperations =
private Dictionary<string, ITerrainFeature> m_featureEffects = new Dictionary<string, ITerrainModifier>();
new Dictionary<string, ITerrainFeature>();
private ITerrainChannel m_channel; private ITerrainChannel m_channel;
private ITerrainChannel m_revert; private ITerrainChannel m_revert;
private Scene m_scene; private Scene m_scene;
private volatile bool m_tainted; private volatile bool m_tainted;
private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5); private readonly Stack<LandUndoState> m_undo = new Stack<LandUndoState>(5);
private String m_InitialTerrain = "pinhead-island"; private String m_InitialTerrain = "pinhead-island";
// If true, send terrain patch updates to clients based on their view distance // 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); return (updateCount > 0);
} }
public void SetByXY(int x, int y, bool state) public void SetByXY(int x, int y, bool state)
{ {
this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state); this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state);
} }
public bool GetByPatch(int patchX, int patchY) public bool GetByPatch(int patchX, int patchY)
{ {
return updated[patchX, patchY]; return updated[patchX, patchY];
} }
public void SetByPatch(int patchX, int patchY, bool state) public void SetByPatch(int patchX, int patchY, bool state)
{ {
bool prevState = updated[patchX, patchY]; bool prevState = updated[patchX, patchY];
@ -153,11 +140,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
updateCount--; updateCount--;
updated[patchX, patchY] = state; updated[patchX, patchY] = state;
} }
public void SetAll(bool state) public void SetAll(bool state)
{ {
updateCount = 0; updateCount = 0;
for (int xx = 0; xx < updated.GetLength(0); xx++) for(int xx = 0; xx < updated.GetLength(0); xx++)
for (int yy = 0; yy < updated.GetLength(1); yy++) for(int yy = 0; yy < updated.GetLength(1); yy++)
updated[xx, yy] = state; updated[xx, yy] = state;
if (state) if (state)
updateCount = updated.GetLength(0) * updated.GetLength(1); 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) 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. // Only set tainted. The patch bit may be set if the patch was to be sent later.
if (terrData.IsTaintedAt(xx, yy, false)) if (terrData.IsTaintedAt(xx, yy, false))
@ -201,8 +189,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
#region ICommandableModule Members #region ICommandableModule Members
public ICommander CommandInterface public ICommander CommandInterface {
{
get { return m_commander; } get { return m_commander; }
} }
@ -230,7 +217,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_scene = scene; m_scene = scene;
// Install terrain module in the simulator // Install terrain module in the simulator
lock (m_scene) lock(m_scene)
{ {
if (m_scene.Heightmap == null) if (m_scene.Heightmap == null)
{ {
@ -262,7 +249,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
string supportedFilesSeparatorForTileSave = ""; string supportedFilesSeparatorForTileSave = "";
m_supportFileExtensionsForTileSave = ""; 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 + ")"; m_supportedFileExtensions += supportedFilesSeparator + loader.Key + " (" + loader.Value + ")";
supportedFilesSeparator = ", "; supportedFilesSeparator = ", ";
@ -285,7 +272,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
public void RemoveRegion(Scene scene) public void RemoveRegion(Scene scene)
{ {
lock (m_scene) lock(m_scene)
{ {
// remove the commands // remove the commands
m_scene.UnregisterModuleCommander(m_commander.Name); 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; } get { return null; }
} }
public string Name public string Name {
{
get { return "TerrainModule"; } 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> /// <param name="filename">Filename to terrain file. Type is determined by extension.</param>
public void LoadFromFile(string filename) 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)) if (filename.EndsWith(loader.Key))
{ {
lock (m_scene) lock(m_scene)
{ {
try try
{ {
@ -349,20 +334,20 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_channel = channel; m_channel = channel;
UpdateRevertMap(); UpdateRevertMap();
} }
catch (NotImplementedException) catch(NotImplementedException)
{ {
m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value +
" parser does not support file loading. (May be save only)"); " 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)); throw new TerrainException(String.Format("unable to load heightmap: parser {0} does not support loading", loader.Value));
} }
catch (FileNotFoundException) catch(FileNotFoundException)
{ {
m_log.Error( m_log.Error(
"[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)"); "[TERRAIN]: Unable to load heightmap, file not found. (A directory permissions error may also cause this)");
throw new TerrainException( throw new TerrainException(
String.Format("unable to load heightmap: file {0} not found (or permissions do not allow access", filename)); 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); m_log.ErrorFormat("[TERRAIN]: Unable to load heightmap: {0}", e.Message);
throw new TerrainException( throw new TerrainException(
@ -386,7 +371,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{ {
try try
{ {
foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
{ {
if (filename.EndsWith(loader.Key)) 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)); 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, public void LoadFromStream(string filename, Vector3 displacement,
float radianRotation, Vector2 rotationDisplacement, Stream stream) 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)) if (filename.EndsWith(loader.Key))
{ {
lock (m_scene) lock(m_scene)
{ {
try try
{ {
@ -441,7 +426,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement); m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement);
UpdateRevertMap(); UpdateRevertMap();
} }
catch (NotImplementedException) catch(NotImplementedException)
{ {
m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value + m_log.Error("[TERRAIN]: Unable to load heightmap, the " + loader.Value +
" parser does not support file loading. (May be save only)"); " parser does not support file loading. (May be save only)");
@ -501,7 +486,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{ {
try try
{ {
foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) foreach(KeyValuePair<string, ITerrainLoader> loader in m_loaders)
{ {
if (filename.EndsWith(loader.Key)) 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."); 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")); 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. // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients.
// ITerrainModule.TaintTerrain() // 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 // 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()); pups.SetAll(m_scene.Heightmap.GetTerrainData());
} }
@ -539,7 +524,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId); ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId);
if (presence != null) if (presence != null)
{ {
lock (m_perClientPatchUpdates) lock(m_perClientPatchUpdates)
{ {
PatchUpdates pups; PatchUpdates pups;
if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out 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>(); m_plugineffects = new Dictionary<string, ITerrainEffect>();
LoadPlugins(Assembly.GetCallingAssembly()); LoadPlugins(Assembly.GetCallingAssembly());
string plugineffectsPath = "Terrain"; string plugineffectsPath = "Terrain";
// Load the files in the Terrain/ dir // Load the files in the Terrain/ dir
if (!Directory.Exists(plugineffectsPath)) if (!Directory.Exists(plugineffectsPath))
return; return;
string[] files = Directory.GetFiles(plugineffectsPath); string[] files = Directory.GetFiles(plugineffectsPath);
foreach (string file in files) foreach(string file in files)
{ {
m_log.Info("Loading effects in " + file); m_log.Info("Loading effects in " + file);
try try
@ -580,7 +565,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
Assembly library = Assembly.LoadFrom(file); Assembly library = Assembly.LoadFrom(file);
LoadPlugins(library); LoadPlugins(library);
} }
catch (BadImageFormatException) catch(BadImageFormatException)
{ {
} }
} }
@ -588,7 +573,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
private void LoadPlugins(Assembly library) private void LoadPlugins(Assembly library)
{ {
foreach (Type pluginType in library.GetTypes()) foreach(Type pluginType in library.GetTypes())
{ {
try try
{ {
@ -610,7 +595,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_log.Info("L ... " + typeName); 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) public void InstallPlugin(string pluginName, ITerrainEffect effect)
{ {
lock (m_plugineffects) lock(m_plugineffects)
{ {
if (!m_plugineffects.ContainsKey(pluginName)) if (!m_plugineffects.ContainsKey(pluginName))
{ {
@ -661,8 +646,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea(); m_floodeffects[StandardTerrainEffects.Flatten] = new FlattenArea();
m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert); m_floodeffects[StandardTerrainEffects.Revert] = new RevertArea(m_revert);
// Terrain Feature effects // Terrain Modifier operations
m_featureEffects["rectangle"] = new RectangleFeature(this); 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 // Filesystem load/save loaders
m_loaders[".r32"] = new RAW32(); m_loaders[".r32"] = new RAW32();
@ -707,22 +698,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain
/// <param name="fileStartY">Where to begin our slice</param> /// <param name="fileStartY">Where to begin our slice</param>
public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) public void LoadFromFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY)
{ {
int offsetX = (int) m_scene.RegionInfo.RegionLocX - fileStartX; int offsetX = (int)m_scene.RegionInfo.RegionLocX - fileStartX;
int offsetY = (int) m_scene.RegionInfo.RegionLocY - fileStartY; int offsetY = (int)m_scene.RegionInfo.RegionLocY - fileStartY;
if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight)
{ {
// this region is included in the tile request // 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)) if (filename.EndsWith(loader.Key))
{ {
lock (m_scene) lock(m_scene)
{ {
ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY,
fileWidth, fileHeight, fileWidth, fileHeight,
(int) m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeX,
(int) m_scene.RegionInfo.RegionSizeY); (int)m_scene.RegionInfo.RegionSizeY);
m_scene.Heightmap = channel; m_scene.Heightmap = channel;
m_channel = channel; m_channel = channel;
UpdateRevertMap(); UpdateRevertMap();
@ -761,11 +752,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
} }
// this region is included in the tile request // 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()) if (filename.EndsWith(loader.Key) && loader.Value.SupportsTileSave())
{ {
lock (m_scene) lock(m_scene)
{ {
loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, loader.Value.SaveFile(m_channel, filename, offsetX, offsetY,
fileWidth, fileHeight, fileWidth, fileHeight,
@ -777,7 +768,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1, fileStartX, fileStartY, fileStartX + fileWidth - 1, fileStartY + fileHeight - 1,
m_scene.RegionInfo.RegionName, filename); m_scene.RegionInfo.RegionName, filename);
} }
return; return;
} }
} }
@ -799,9 +790,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
TerrainData terrData = m_channel.GetTerrainData(); TerrainData terrData = m_channel.GetTerrainData();
bool shouldTaint = false; 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)) if (terrData.IsTaintedAt(x, y))
{ {
@ -856,7 +847,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
string[] tmpArgs = new string[args.Length - 2]; string[] tmpArgs = new string[args.Length - 2];
int i; int i;
for (i = 2; i < args.Length; i++) for(i = 2; i < args.Length; i++)
tmpArgs[i - 2] = args[i]; tmpArgs[i - 2] = args[i];
m_commander.ProcessConsoleCommand(args[1], tmpArgs); m_commander.ProcessConsoleCommand(args[1], tmpArgs);
@ -874,7 +865,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
client.OnLandUndo += client_OnLandUndo; client.OnLandUndo += client_OnLandUndo;
client.OnUnackedTerrain += client_OnUnackedTerrain; client.OnUnackedTerrain += client_OnUnackedTerrain;
} }
/// <summary> /// <summary>
/// Installs terrain brush hook to IClientAPI /// Installs terrain brush hook to IClientAPI
/// </summary> /// </summary>
@ -890,10 +881,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain; presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain;
} }
lock (m_perClientPatchUpdates) lock(m_perClientPatchUpdates)
m_perClientPatchUpdates.Remove(client); m_perClientPatchUpdates.Remove(client);
} }
/// <summary> /// <summary>
/// Scan over changes in the terrain and limit height changes. This enforces the /// Scan over changes in the terrain and limit height changes. This enforces the
/// non-estate owner limits on rate of terrain editting. /// non-estate owner limits on rate of terrain editting.
@ -904,12 +895,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
TerrainData terrData = m_channel.GetTerrainData(); TerrainData terrData = m_channel.GetTerrainData();
bool wasLimited = false; 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 (terrData.IsTaintedAt(x, y, false /* clearOnTest */))
{ {
// If we should respect the estate settings then // If we should respect the estate settings then
// fixup and height deltas that don't respect them. // fixup and height deltas that don't respect them.
// Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values. // 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 // loop through the height map for this patch and compare it against
// the revert map // 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 requestedHeight = terrData[x, y];
float bakedHeight = (float)m_revert[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) private void client_OnLandUndo(IClientAPI client)
{ {
lock (m_undo) lock(m_undo)
{ {
if (m_undo.Count > 0) if (m_undo.Count > 0)
{ {
@ -981,19 +972,19 @@ namespace OpenSim.Region.CoreModules.World.Terrain
if (m_sendTerrainUpdatesByViewDistance) if (m_sendTerrainUpdatesByViewDistance)
{ {
// Add that this patch needs to be sent to the accounting for each client. // Add that this patch needs to be sent to the accounting for each client.
lock (m_perClientPatchUpdates) lock(m_perClientPatchUpdates)
{ {
m_scene.ForEachScenePresence(presence => m_scene.ForEachScenePresence(presence =>
{
PatchUpdates thisClientUpdates;
if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates))
{ {
PatchUpdates thisClientUpdates; // There is a ScenePresence without a send patch map. Create one.
if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates)) thisClientUpdates = new PatchUpdates(terrData, presence);
{ m_perClientPatchUpdates.Add(presence.UUID, 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);
} }
thisClientUpdates.SetByXY(x, y, true);
}
); );
} }
} }
@ -1005,11 +996,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
float[] heightMap = new float[10]; float[] heightMap = new float[10];
m_scene.ForEachClient( m_scene.ForEachClient(
delegate(IClientAPI controller) delegate(IClientAPI controller)
{ {
controller.SendLayerData(x / Constants.TerrainPatchSize, controller.SendLayerData(x / Constants.TerrainPatchSize,
y / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize,
heightMap); heightMap);
} }
); );
} }
} }
@ -1019,12 +1010,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain
public int PatchX; public int PatchX;
public int PatchY; public int PatchY;
public float Dist; public float Dist;
public PatchesToSend(int pX, int pY, float pDist) public PatchesToSend(int pX, int pY, float pDist)
{ {
PatchX = pX; PatchX = pX;
PatchY = pY; PatchY = pY;
Dist = pDist; Dist = pDist;
} }
public int CompareTo(PatchesToSend other) public int CompareTo(PatchesToSend other)
{ {
return Dist.CompareTo(other.Dist); 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. // Loop through all the per-client info and send any patches necessary.
private void CheckSendingPatchesToClients() 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()) if (pups.HasUpdates())
{ {
@ -1062,7 +1055,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
int[] yPieces = new int[toSend.Count]; int[] yPieces = new int[toSend.Count];
float[] patchPieces = new float[toSend.Count * 2]; float[] patchPieces = new float[toSend.Count * 2];
int pieceIndex = 0; int pieceIndex = 0;
foreach (PatchesToSend pts in toSend) foreach(PatchesToSend pts in toSend)
{ {
patchPieces[pieceIndex++] = pts.PatchX; patchPieces[pieceIndex++] = pts.PatchX;
patchPieces[pieceIndex++] = pts.PatchY; patchPieces[pieceIndex++] = pts.PatchY;
@ -1083,25 +1076,25 @@ namespace OpenSim.Region.CoreModules.World.Terrain
return ret; return ret;
// Compute the area of patches within our draw distance // 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.Max(startX, 0);
startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize); startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize);
int startY = (((int) (presence.AbsolutePosition.Y - presence.DrawDistance))/Constants.TerrainPatchSize) - 2; int startY = (((int)(presence.AbsolutePosition.Y - presence.DrawDistance)) / Constants.TerrainPatchSize) - 2;
startY = Math.Max(startY, 0); startY = Math.Max(startY, 0);
startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize); startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize);
int endX = (((int) (presence.AbsolutePosition.X + presence.DrawDistance))/Constants.TerrainPatchSize) + 2; int endX = (((int)(presence.AbsolutePosition.X + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2;
endX = Math.Max(endX, 0); endX = Math.Max(endX, 0);
endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize); endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize);
int endY = (((int) (presence.AbsolutePosition.Y + presence.DrawDistance))/Constants.TerrainPatchSize) + 2; int endY = (((int)(presence.AbsolutePosition.Y + presence.DrawDistance)) / Constants.TerrainPatchSize) + 2;
endY = Math.Max(endY, 0); 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}>", // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, start=<{4},{5}>, end=<{6},{7}>",
// LogHeader, m_scene.RegionInfo.RegionName, // LogHeader, m_scene.RegionInfo.RegionName,
// presence.DrawDistance, presence.AbsolutePosition, // presence.DrawDistance, presence.AbsolutePosition,
// startX, startY, endX, endY); // 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 //Need to make sure we don't send the same ones over and over
Vector3 presencePos = presence.AbsolutePosition; Vector3 presencePos = presence.AbsolutePosition;
@ -1133,28 +1126,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain
bool allowed = false; bool allowed = false;
if (north == south && east == west) 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(); allowMask.Initialize();
int n = size + 1; int n = size + 1;
if (n > 2) if (n > 2)
n = 4; n = 4;
int zx = (int) (west + 0.5); int zx = (int)(west + 0.5);
int zy = (int) (north + 0.5); int zy = (int)(north + 0.5);
int dx; int dx;
for (dx=-n; dx<=n; dx++) for(dx=-n; dx<=n; dx++)
{ {
int dy; int dy;
for (dy=-n; dy<=n; dy++) for(dy=-n; dy<=n; dy++)
{ {
int x = zx + dx; int x = zx + dx;
int y = zy + dy; 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; allowMask[x, y] = true;
allowed = true; allowed = true;
@ -1165,7 +1158,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
if (allowed) if (allowed)
{ {
StoreUndoState(); StoreUndoState();
m_painteffects[(StandardTerrainEffects) action].PaintEffect( m_painteffects[(StandardTerrainEffects)action].PaintEffect(
m_channel, allowMask, west, south, height, size, seconds); m_channel, allowMask, west, south, height, size, seconds);
//revert changes outside estate limits //revert changes outside estate limits
@ -1180,22 +1173,22 @@ namespace OpenSim.Region.CoreModules.World.Terrain
} }
else 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(); fillArea.Initialize();
int x; int x;
for (x = 0; x < m_channel.Width; x++) for(x = 0; x < m_channel.Width; x++)
{ {
int y; int y;
for (y = 0; y < m_channel.Height; y++) for(y = 0; y < m_channel.Height; y++)
{ {
if (x < east && x > west) if (x < east && x > west)
{ {
if (y < north && y > south) 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; fillArea[x, y] = true;
allowed = true; allowed = true;
@ -1208,7 +1201,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
if (allowed) if (allowed)
{ {
StoreUndoState(); StoreUndoState();
m_floodeffects[(StandardTerrainEffects) action].FloodEffect(m_channel, fillArea, size); m_floodeffects[(StandardTerrainEffects)action].FloodEffect(m_channel, fillArea, size);
//revert changes outside estate limits //revert changes outside estate limits
if (!god) if (!god)
@ -1232,7 +1225,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter InterfaceBakeTerrain(null); //bake terrain does not use the passed in parameter
} }
} }
protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY) protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY)
{ {
//m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY); //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY);
@ -1243,7 +1236,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
private void StoreUndoState() private void StoreUndoState()
{ {
lock (m_undo) lock(m_undo)
{ {
if (m_undo.Count > 0) if (m_undo.Count > 0)
{ {
@ -1264,21 +1257,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain
private void InterfaceLoadFile(Object[] args) private void InterfaceLoadFile(Object[] args)
{ {
LoadFromFile((string) args[0]); LoadFromFile((string)args[0]);
} }
private void InterfaceLoadTileFile(Object[] args) private void InterfaceLoadTileFile(Object[] args)
{ {
LoadFromFile((string) args[0], LoadFromFile((string)args[0],
(int) args[1], (int)args[1],
(int) args[2], (int)args[2],
(int) args[3], (int)args[3],
(int) args[4]); (int)args[4]);
} }
private void InterfaceSaveFile(Object[] args) private void InterfaceSaveFile(Object[] args)
{ {
SaveToFile((string) args[0]); SaveToFile((string)args[0]);
} }
private void InterfaceSaveTileFile(Object[] args) private void InterfaceSaveTileFile(Object[] args)
@ -1298,8 +1291,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
private void InterfaceRevertTerrain(Object[] args) private void InterfaceRevertTerrain(Object[] args)
{ {
int x, y; 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] = m_revert[x, y]; m_channel[x, y] = m_revert[x, y];
} }
@ -1310,9 +1303,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
if (direction.ToLower().StartsWith("y")) 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 height = m_channel[x, y];
double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - 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")) 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 height = m_channel[x, y];
double flippedHeight = m_channel[(int)m_channel.Width - 1 - 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 width = m_channel.Width;
int height = m_channel.Height; 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]; double currHeight = m_channel[x, y];
if (currHeight < currMin) if (currHeight < currMin)
@ -1388,12 +1381,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain
//m_log.InfoFormat("Scale = {0}", scale); //m_log.InfoFormat("Scale = {0}", scale);
// scale the heightmap accordingly // 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; double currHeight = m_channel[x, y] - currMin;
m_channel[x, y] = desiredMin + (currHeight * scale); m_channel[x, y] = desiredMin + (currHeight * scale);
} }
} }
@ -1404,42 +1397,42 @@ namespace OpenSim.Region.CoreModules.World.Terrain
private void InterfaceElevateTerrain(Object[] args) private void InterfaceElevateTerrain(Object[] args)
{ {
int x, y; 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] += (double) args[0]; m_channel[x, y] += (double)args[0];
} }
private void InterfaceMultiplyTerrain(Object[] args) private void InterfaceMultiplyTerrain(Object[] args)
{ {
int x, y; 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] *= (double) args[0]; m_channel[x, y] *= (double)args[0];
} }
private void InterfaceLowerTerrain(Object[] args) private void InterfaceLowerTerrain(Object[] args)
{ {
int x, y; 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] -= (double) args[0]; m_channel[x, y] -= (double)args[0];
} }
public void InterfaceFillTerrain(Object[] args) public void InterfaceFillTerrain(Object[] args)
{ {
int x, y; 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] = (double) args[0]; m_channel[x, y] = (double)args[0];
} }
private void InterfaceMinTerrain(Object[] args) private void InterfaceMinTerrain(Object[] args)
{ {
int x, y; 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]); 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) private void InterfaceMaxTerrain(Object[] args)
{ {
int x, y; 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]); 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; double sum = 0;
int x; int x;
for (x = 0; x < m_channel.Width; x++) for(x = 0; x < m_channel.Width; x++)
{ {
int y; int y;
for (y = 0; y < m_channel.Height; y++) for(y = 0; y < m_channel.Height; y++)
{ {
sum += m_channel[x, y]; sum += m_channel[x, y];
if (max < 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) private void InterfaceEnableExperimentalBrushes(Object[] args)
{ {
if ((bool) args[0]) if ((bool)args[0])
{ {
m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere(); m_painteffects[StandardTerrainEffects.Revert] = new WeatherSphere();
m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere(); m_painteffects[StandardTerrainEffects.Flatten] = new OlsenSphere();
@ -1520,7 +1513,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
if (firstArg == "list") if (firstArg == "list")
{ {
MainConsole.Instance.Output("List of loaded plugins"); 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); 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 // Add this to our scene so scripts can call these functions
m_scene.RegisterModuleCommander(m_commander); m_scene.RegisterModuleCommander(m_commander);
// Add Feature command to Scene, since Command object requires fixed-length arglists // Add Modify command to Scene, since Command object requires fixed-length arglists
m_scene.AddCommand("Terrain", this, "terrain feature", m_scene.AddCommand("Terrain", this, "terrain modify",
"terrain feature <type> <parameters...>", "Constructs a feature of the requested type.", FeatureCommand); "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; 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 else
{ {
result = feature.CreateFeature(m_channel, cmd); result = operation.ModifyTerrain(m_channel, cmd);
} }
if(result == String.Empty) if (result == String.Empty)
{ {
result = "Created Feature"; result = "Modified terrain";
m_log.DebugFormat("Created terrain feature {0}", featureType); m_log.DebugFormat("Performed terrain operation {0}", operationType);
} }
} }
else 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
} }
} }

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -31,6 +31,6 @@ using Mono.Addins;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]
[assembly: AddinRoot("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinRoot("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]

View File

@ -1653,7 +1653,7 @@ namespace OpenSim.Region.Framework.Scenes
// These variables will be used to save the precise frame time using the // 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 // 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 // the frame times, which are the sums of the sections for each given name
double preciseTotalFrameTime = 0.0; double preciseTotalFrameTime = 0.0;
double preciseSimFrameTime = 0.0; double preciseSimFrameTime = 0.0;
@ -1698,7 +1698,7 @@ namespace OpenSim.Region.Framework.Scenes
// input took // input took
simFrameStopwatch.Stop(); simFrameStopwatch.Stop();
preciseSimFrameTime = preciseSimFrameTime =
simFrameStopwatch.Elapsed.TotalMilliseconds; simFrameStopwatch.Elapsed.TotalMilliseconds;
terrainMS = Util.EnvironmentTickCountSubtract(tmpMS); terrainMS = Util.EnvironmentTickCountSubtract(tmpMS);
} }
@ -1717,7 +1717,7 @@ namespace OpenSim.Region.Framework.Scenes
// Begin the stopwatch to track the time to prepare physics // Begin the stopwatch to track the time to prepare physics
physicsFrameStopwatch.Start(); physicsFrameStopwatch.Start();
if (PhysicsEnabled && Frame % m_update_physics == 0) if (PhysicsEnabled && Frame % m_update_physics == 0)
m_sceneGraph.UpdatePreparePhysics(); m_sceneGraph.UpdatePreparePhysics();
// Get the time it took to prepare the physics, this // Get the time it took to prepare the physics, this
// would report the most precise time that physics was // would report the most precise time that physics was
@ -1738,7 +1738,7 @@ namespace OpenSim.Region.Framework.Scenes
// took // took
simFrameStopwatch.Stop(); simFrameStopwatch.Stop();
preciseSimFrameTime += preciseSimFrameTime +=
simFrameStopwatch.Elapsed.TotalMilliseconds; simFrameStopwatch.Elapsed.TotalMilliseconds;
agentMS = Util.EnvironmentTickCountSubtract(tmpMS); agentMS = Util.EnvironmentTickCountSubtract(tmpMS);
// Perform the main physics update. This will do the actual work of moving objects and avatars according to their // 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 // Get the elapsed time for the simulation frame
simFrameStopwatch.Stop(); simFrameStopwatch.Stop();
preciseSimFrameTime += preciseSimFrameTime +=
simFrameStopwatch.Elapsed.TotalMilliseconds; simFrameStopwatch.Elapsed.TotalMilliseconds;
if (!UpdateOnTimer) if (!UpdateOnTimer)
{ {
@ -1872,7 +1872,7 @@ namespace OpenSim.Region.Framework.Scenes
// Get the total frame time // Get the total frame time
totalFrameStopwatch.Stop(); totalFrameStopwatch.Stop();
preciseTotalFrameTime = preciseTotalFrameTime =
totalFrameStopwatch.Elapsed.TotalMilliseconds; totalFrameStopwatch.Elapsed.TotalMilliseconds;
// Restart the stopwatch for the total time of the next frame // Restart the stopwatch for the total time of the next frame
totalFrameStopwatch.Restart(); totalFrameStopwatch.Restart();
@ -1897,7 +1897,7 @@ namespace OpenSim.Region.Framework.Scenes
// Send the correct time values to the stats reporter for the // Send the correct time values to the stats reporter for the
// frame times // frame times
StatsReporter.addFrameTimeMilliseconds(preciseTotalFrameTime, StatsReporter.addFrameTimeMilliseconds(preciseTotalFrameTime,
preciseSimFrameTime, precisePhysicsFrameTime, 0.0); preciseSimFrameTime, precisePhysicsFrameTime, 0.0);
// Send the correct number of frames that the physics library // Send the correct number of frames that the physics library
// has processed to the stats reporter // has processed to the stats reporter

View File

@ -2672,20 +2672,27 @@ namespace OpenSim.Region.Framework.Scenes
} }
else else
{ {
//NonPhysicalGrabMovement(pos); NonPhysicalGrabMovement(pos);
} }
} }
else 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) public void NonPhysicalGrabMovement(Vector3 pos)
{ {
AbsolutePosition = pos; if(!IsAttachment && ScriptCount() == 0)
m_rootPart.SendTerseUpdateToAllClients(); UpdateGroupPosition(pos);
} }
/// <summary> /// <summary>
@ -2781,16 +2788,27 @@ namespace OpenSim.Region.Framework.Scenes
} }
else else
{ {
//NonPhysicalSpinMovement(pos); NonPhysicalSpinMovement(newOrientation);
} }
} }
else 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> /// <summary>
/// Set the name of a prim /// Set the name of a prim
/// </summary> /// </summary>

View File

@ -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");
}
}
}

View File

@ -30,7 +30,7 @@ using Mono.Addins;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]
[assembly: Addin("OpenSim.Region.OptionalModules", OpenSim.VersionInfo.VersionNumber)] [assembly: Addin("OpenSim.Region.OptionalModules", OpenSim.VersionInfo.VersionNumber)]

View File

@ -115,6 +115,9 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
private delegate T DefaultGetter<T>(string settingName, T defaultValue); private delegate T DefaultGetter<T>(string settingName, T defaultValue);
private bool m_enabled; private bool m_enabled;
private ICommandConsole m_console;
private List<Scene> m_Scenes = new List<Scene> ();
/// <summary> /// <summary>
/// Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState! /// 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. /// Currently a no-op for AutoBackup because we have to wait for region to be fully loaded.
/// </summary> /// </summary>
/// <param name="scene"></param> /// <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> /// <summary>
@ -220,7 +235,7 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
{ {
return; return;
} }
m_Scenes.Remove (scene);
if (this.m_states.ContainsKey(scene)) if (this.m_states.ContainsKey(scene))
{ {
AutoBackupModuleState abms = this.m_states[scene]; AutoBackupModuleState abms = this.m_states[scene];
@ -275,6 +290,28 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup
#endregion #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> /// <summary>
/// Set up internal state for a given scene. Fairly complex code. /// 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. /// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene.

View File

@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
// You can specify all values by your own or you can build default build and revision // You can specify all values by your own or you can build default build and revision
// numbers with the '*' character (the default): // numbers with the '*' character (the default):
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
// You can specify all values by your own or you can build default build and revision // You can specify all values by your own or you can build default build and revision
// numbers with the '*' character (the default): // numbers with the '*' character (the default):
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -84,7 +84,8 @@ namespace OpenSim.Region.Physics.Meshing
private List<List<Vector3>> mConvexHulls = null; private List<List<Vector3>> mConvexHulls = null;
private List<Vector3> mBoundingHull = 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) public Meshmerizer(IConfigSource config)
{ {
@ -927,8 +928,11 @@ namespace OpenSim.Region.Physics.Meshing
if (shouldCache) if (shouldCache)
{ {
key = primShape.GetMeshKey(size, lod); key = primShape.GetMeshKey(size, lod);
if (m_uniqueMeshes.TryGetValue(key, out mesh)) lock (m_uniqueMeshes)
return mesh; {
if (m_uniqueMeshes.TryGetValue(key, out mesh))
return mesh;
}
} }
if (size.X < 0.01f) size.X = 0.01f; if (size.X < 0.01f) size.X = 0.01f;
@ -954,7 +958,10 @@ namespace OpenSim.Region.Physics.Meshing
if (shouldCache) if (shouldCache)
{ {
m_uniqueMeshes.Add(key, mesh); lock (m_uniqueMeshes)
{
m_uniqueMeshes.Add(key, mesh);
}
} }
} }

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
// You can specify all values by your own or you can build default build and revision // You can specify all values by your own or you can build default build and revision
// numbers with the '*' character (the default): // numbers with the '*' character (the default):
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
// You can specify all values by your own or you can build default build and revision // You can specify all values by your own or you can build default build and revision
// numbers with the '*' character (the default): // numbers with the '*' character (the default):
[assembly : AssemblyVersion("0.8.1.*")] [assembly : AssemblyVersion("0.8.2.*")]

View File

@ -30,7 +30,7 @@ using Mono.Addins;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]
[assembly: Addin("OpenSim.RegionModules.RegionCombinerModule", OpenSim.VersionInfo.VersionNumber)] [assembly: Addin("OpenSim.RegionModules.RegionCombinerModule", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -596,6 +596,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
public const int OBJECT_PHYSICS = 21; public const int OBJECT_PHYSICS = 21;
public const int OBJECT_PHANTOM = 22; public const int OBJECT_PHANTOM = 22;
public const int OBJECT_TEMP_ON_REZ = 23; 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 // Pathfinding types
public const int OPT_OTHER = -1; public const int OPT_OTHER = -1;

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -30,7 +30,7 @@ using Mono.Addins;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]
[assembly: Addin("OpenSim.Region.ScriptEngine.XEngine", OpenSim.VersionInfo.VersionNumber)] [assembly: Addin("OpenSim.Region.ScriptEngine.XEngine", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -82,7 +82,9 @@ namespace OpenSim.Server.Base
argvConfig.AddSwitch("Startup", "logconfig", "g"); argvConfig.AddSwitch("Startup", "logconfig", "g");
// Automagically create the ini file name // 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 iniFile = fileName + ".ini";
string logConfig = null; string logConfig = null;
@ -158,7 +160,11 @@ namespace OpenSim.Server.Base
MainConsole.Instance = new RemoteConsole(prompt); MainConsole.Instance = new RemoteConsole(prompt);
((RemoteConsole)MainConsole.Instance).ReadConfig(Config); ((RemoteConsole)MainConsole.Instance).ReadConfig(Config);
} }
else else if (consoleType == "mock")
{
MainConsole.Instance = new MockConsole();
}
else if (consoleType == "local")
{ {
MainConsole.Instance = new LocalConsole(prompt, startupConfig); MainConsole.Instance = new LocalConsole(prompt, startupConfig);
} }

View File

@ -41,7 +41,9 @@ using OpenSim.Server.Handlers.Base;
using log4net; using log4net;
using OpenMetaverse; using OpenMetaverse;
namespace OpenSim.Server.Handlers.Asset using System.Threading;
namespace OpenSim.Server.Handlers.Inventory
{ {
public class XInventoryInConnector : ServiceConnector public class XInventoryInConnector : ServiceConnector
{ {
@ -123,6 +125,8 @@ namespace OpenSim.Server.Handlers.Asset
return HandleGetFolderForType(request); return HandleGetFolderForType(request);
case "GETFOLDERCONTENT": case "GETFOLDERCONTENT":
return HandleGetFolderContent(request); return HandleGetFolderContent(request);
case "GETMULTIPLEFOLDERSCONTENT":
return HandleGetMultipleFoldersContent(request);
case "GETFOLDERITEMS": case "GETFOLDERITEMS":
return HandleGetFolderItems(request); return HandleGetFolderItems(request);
case "ADDFOLDER": case "ADDFOLDER":
@ -145,6 +149,8 @@ namespace OpenSim.Server.Handlers.Asset
return HandleDeleteItems(request); return HandleDeleteItems(request);
case "GETITEM": case "GETITEM":
return HandleGetItem(request); return HandleGetItem(request);
case "GETMULTIPLEITEMS":
return HandleGetMultipleItems(request);
case "GETFOLDER": case "GETFOLDER":
return HandleGetFolder(request); return HandleGetFolder(request);
case "GETACTIVEGESTURES": case "GETACTIVEGESTURES":
@ -284,6 +290,8 @@ namespace OpenSim.Server.Handlers.Asset
InventoryCollection icoll = m_InventoryService.GetFolderContent(principal, folderID); InventoryCollection icoll = m_InventoryService.GetFolderContent(principal, folderID);
if (icoll != null) if (icoll != null)
{ {
result["FID"] = icoll.FolderID.ToString();
result["VERSION"] = icoll.Version.ToString();
Dictionary<string, object> folders = new Dictionary<string, object>(); Dictionary<string, object> folders = new Dictionary<string, object>();
int i = 0; int i = 0;
if (icoll.Folders != null) if (icoll.Folders != null)
@ -314,7 +322,71 @@ namespace OpenSim.Server.Handlers.Asset
return Util.UTF8NoBomEncoding.GetBytes(xmlString); 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>(); Dictionary<string,object> result = new Dictionary<string,object>();
UUID principal = UUID.Zero; UUID principal = UUID.Zero;
@ -506,6 +578,40 @@ namespace OpenSim.Server.Handlers.Asset
return Util.UTF8NoBomEncoding.GetBytes(xmlString); 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) byte[] HandleGetFolder(Dictionary<string,object> request)
{ {
Dictionary<string, object> result = new Dictionary<string, object>(); Dictionary<string, object> result = new Dictionary<string, object>();

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -257,8 +257,7 @@ namespace OpenSim.Server.Handlers.UserAccounts
byte[] CreateUser(Dictionary<string, object> request) byte[] CreateUser(Dictionary<string, object> request)
{ {
if (! if (! request.ContainsKey("FirstName")
request.ContainsKey("FirstName")
&& request.ContainsKey("LastName") && request.ContainsKey("LastName")
&& request.ContainsKey("Password")) && request.ContainsKey("Password"))
return FailureResult(); return FailureResult();

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -40,7 +40,7 @@ using OpenSim.Services.Connectors;
using OpenSim.Services.Interfaces; using OpenSim.Services.Interfaces;
using OpenSim.Server.Base; using OpenSim.Server.Base;
namespace OpenSim.Service.Connectors namespace OpenSim.Services.Connectors
{ {
public class EstateDataRemoteConnector : BaseServiceConnector, IEstateDataService public class EstateDataRemoteConnector : BaseServiceConnector, IEstateDataService
{ {

View File

@ -205,7 +205,7 @@ namespace OpenSim.Services.Connectors
InventoryCollection inventory = new InventoryCollection(); InventoryCollection inventory = new InventoryCollection();
inventory.Folders = new List<InventoryFolderBase>(); inventory.Folders = new List<InventoryFolderBase>();
inventory.Items = new List<InventoryItemBase>(); inventory.Items = new List<InventoryItemBase>();
inventory.UserID = principalID; inventory.OwnerID = principalID;
try try
{ {
@ -235,6 +235,87 @@ namespace OpenSim.Services.Connectors
return inventory; 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) public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID)
{ {
@ -325,9 +406,13 @@ namespace OpenSim.Services.Connectors
public bool AddItem(InventoryItemBase item) public bool AddItem(InventoryItemBase item)
{ {
if (item.Description == null)
item.Description = String.Empty;
if (item.CreatorData == null) if (item.CreatorData == null)
item.CreatorData = String.Empty; 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> { new Dictionary<string,object> {
{ "AssetID", item.AssetID.ToString() }, { "AssetID", item.AssetID.ToString() },
{ "AssetType", item.AssetType.ToString() }, { "AssetType", item.AssetType.ToString() },
@ -446,6 +531,42 @@ namespace OpenSim.Services.Connectors
return null; 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) public InventoryFolderBase GetFolder(InventoryFolderBase folder)
{ {
try try

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -301,6 +301,21 @@ namespace OpenSim.Services.Connectors.SimianGrid
return null; 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> /// <summary>
/// Get a folder, given by its UUID /// Get a folder, given by its UUID
/// </summary> /// </summary>
@ -340,7 +355,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
public InventoryCollection GetFolderContent(UUID userID, UUID folderID) public InventoryCollection GetFolderContent(UUID userID, UUID folderID)
{ {
InventoryCollection inventory = new InventoryCollection(); InventoryCollection inventory = new InventoryCollection();
inventory.UserID = userID; inventory.OwnerID = userID;
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
@ -371,6 +386,18 @@ namespace OpenSim.Services.Connectors.SimianGrid
return inventory; 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> /// <summary>
/// Gets the items inside a folder /// Gets the items inside a folder
/// </summary> /// </summary>
@ -380,7 +407,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID)
{ {
InventoryCollection inventory = new InventoryCollection(); InventoryCollection inventory = new InventoryCollection();
inventory.UserID = userID; inventory.OwnerID = userID;
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {

View File

@ -215,9 +215,39 @@ namespace OpenSim.Services.Connectors
sendData[kvp.Key] = kvp.Value.ToString(); 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) private UserAccount SendAndGetReply(Dictionary<string, object> sendData)
{ {
string reply = string.Empty; string reply = string.Empty;
@ -260,7 +290,7 @@ namespace OpenSim.Services.Connectors
{ {
string reqString = ServerUtils.BuildQueryString(sendData); string reqString = ServerUtils.BuildQueryString(sendData);
string uri = m_ServerURI + "/accounts"; string uri = m_ServerURI + "/accounts";
// m_log.DebugFormat("[ACCOUNTS CONNECTOR]: queryString = {0}", reqString); //m_log.DebugFormat("[ACCOUNTS CONNECTOR]: queryString = {0}", reqString);
try try
{ {
string reply = SynchronousRestFormsRequester.MakeRequest("POST", string reply = SynchronousRestFormsRequester.MakeRequest("POST",
@ -269,6 +299,7 @@ namespace OpenSim.Services.Connectors
m_Auth); m_Auth);
if (reply != string.Empty) if (reply != string.Empty)
{ {
//m_log.DebugFormat("[ACCOUNTS CONNECTOR]: reply = {0}", reply);
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData.ContainsKey("result")) if (replyData.ContainsKey("result"))

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // Revision
// //
[assembly: AssemblyVersion("0.8.1.*")] [assembly: AssemblyVersion("0.8.2.*")]

View File

@ -163,7 +163,7 @@ namespace OpenSim.Services.HypergridService
protected byte[] AdjustIdentifiers(byte[] data) protected byte[] AdjustIdentifiers(byte[] data)
{ {
string xml = Utils.BytesToString(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));
} }
} }

View File

@ -101,7 +101,14 @@ namespace OpenSim.Services.HypergridService
Object[] args = new Object[] { config }; Object[] args = new Object[] { config };
m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args); m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args);
m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, 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>(); m_RegionCache = new ExpiringCache<UUID, GridRegion>();

View File

@ -153,7 +153,14 @@ namespace OpenSim.Services.HypergridService
//public InventoryCollection GetFolderContent(UUID principalID, UUID folderID) //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) //public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID)
//{ //{
//} //}

View File

@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number // Build Number
// Revision // 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