mirror of
https://github.com/opensim/opensim.git
synced 2026-08-12 12:25:42 +08:00
Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
This commit is contained in:
@@ -61,11 +61,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||
public bool m_jumping = false;
|
||||
public float m_jumpVelocity = 0f;
|
||||
// private int m_landing = 0;
|
||||
public bool Falling
|
||||
{
|
||||
get { return m_falling; }
|
||||
}
|
||||
private bool m_falling = false;
|
||||
|
||||
/// <summary>
|
||||
/// Is the avatar falling?
|
||||
/// </summary>
|
||||
public bool Falling { get; private set; }
|
||||
|
||||
private float m_fallHeight;
|
||||
|
||||
/// <value>
|
||||
@@ -223,7 +224,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||
m_animTickFall = 0;
|
||||
m_animTickJump = 0;
|
||||
m_jumping = false;
|
||||
m_falling = true;
|
||||
Falling = false;
|
||||
m_jumpVelocity = 0f;
|
||||
actor.Selected = false;
|
||||
m_fallHeight = actor.Position.Z; // save latest flying height
|
||||
@@ -238,10 +239,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||
}
|
||||
else if (move.Z < 0f)
|
||||
{
|
||||
if (actor != null && actor.IsColliding)
|
||||
{
|
||||
if (actor != null && actor.IsColliding)
|
||||
return "LAND";
|
||||
}
|
||||
else
|
||||
return "HOVER_DOWN";
|
||||
}
|
||||
@@ -260,7 +259,8 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||
float fallElapsed = (float)(Environment.TickCount - m_animTickFall);
|
||||
float fallVelocity = (actor != null) ? actor.Velocity.Z : 0.0f;
|
||||
|
||||
if (!m_jumping && (fallVelocity < -3.0f) ) m_falling = true;
|
||||
if (!m_jumping && (fallVelocity < -3.0f))
|
||||
Falling = true;
|
||||
|
||||
if (m_animTickFall == 0 || (fallVelocity >= 0.0f))
|
||||
{
|
||||
@@ -290,20 +290,20 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||
// Start jumping, prejump
|
||||
m_animTickFall = 0;
|
||||
m_jumping = true;
|
||||
m_falling = false;
|
||||
Falling = false;
|
||||
actor.Selected = true; // borrowed for jumping flag
|
||||
m_animTickJump = Environment.TickCount;
|
||||
m_jumpVelocity = 0.35f;
|
||||
return "PREJUMP";
|
||||
}
|
||||
|
||||
if(m_jumping)
|
||||
if (m_jumping)
|
||||
{
|
||||
if ( (jumptime > (JUMP_PERIOD * 1.5f)) && actor.IsColliding)
|
||||
if ((jumptime > (JUMP_PERIOD * 1.5f)) && actor.IsColliding)
|
||||
{
|
||||
// end jumping
|
||||
m_jumping = false;
|
||||
m_falling = false;
|
||||
Falling = false;
|
||||
actor.Selected = false; // borrowed for jumping flag
|
||||
m_jumpVelocity = 0f;
|
||||
m_animTickFall = Environment.TickCount;
|
||||
@@ -330,7 +330,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||
|
||||
if (CurrentMovementAnimation == "FALLDOWN")
|
||||
{
|
||||
m_falling = false;
|
||||
Falling = false;
|
||||
m_animTickFall = Environment.TickCount;
|
||||
// TODO: SOFT_LAND support
|
||||
float fallHeight = m_fallHeight - actor.Position.Z;
|
||||
@@ -364,7 +364,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||
if (move.X != 0f || move.Y != 0f)
|
||||
{
|
||||
m_fallHeight = actor.Position.Z; // save latest flying height
|
||||
m_falling = false;
|
||||
Falling = false;
|
||||
// Walking / crouchwalking / running
|
||||
if (move.Z < 0f)
|
||||
return "CROUCHWALK";
|
||||
@@ -375,7 +375,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||
}
|
||||
else if (!m_jumping)
|
||||
{
|
||||
m_falling = false;
|
||||
Falling = false;
|
||||
// Not walking
|
||||
if (move.Z < 0)
|
||||
return "CROUCH";
|
||||
@@ -388,7 +388,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||
}
|
||||
#endregion Ground Movement
|
||||
|
||||
m_falling = false;
|
||||
Falling = false;
|
||||
|
||||
return CurrentMovementAnimation;
|
||||
}
|
||||
|
||||
@@ -979,25 +979,40 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID)
|
||||
{
|
||||
SceneObjectPart part = GetSceneObjectPart(localID);
|
||||
if (part == null)
|
||||
return;
|
||||
|
||||
SceneObjectGroup group = part.ParentGroup;
|
||||
if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId))
|
||||
return;
|
||||
|
||||
TaskInventoryItem item = group.GetInventoryItem(localID, itemID);
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
if (item.Type == 10)
|
||||
SceneObjectGroup group = null;
|
||||
if (part != null)
|
||||
{
|
||||
part.RemoveScriptEvents(itemID);
|
||||
EventManager.TriggerRemoveScript(localID, itemID);
|
||||
group = part.ParentGroup;
|
||||
}
|
||||
if (part != null && group != null)
|
||||
{
|
||||
if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId))
|
||||
return;
|
||||
|
||||
TaskInventoryItem item = group.GetInventoryItem(localID, itemID);
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
InventoryFolderBase destFolder = InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.TrashFolder);
|
||||
|
||||
// Move the item to trash. If this is a copiable item, only
|
||||
// a copy will be moved and we will still need to delete
|
||||
// the item from the prim. If it was no copy, is will be
|
||||
// deleted by this method.
|
||||
MoveTaskInventoryItem(remoteClient, destFolder.ID, part, itemID);
|
||||
|
||||
if (group.GetInventoryItem(localID, itemID) != null)
|
||||
{
|
||||
if (item.Type == 10)
|
||||
{
|
||||
part.RemoveScriptEvents(itemID);
|
||||
EventManager.TriggerRemoveScript(localID, itemID);
|
||||
}
|
||||
|
||||
group.RemoveInventoryItem(localID, itemID);
|
||||
}
|
||||
part.SendPropertiesToClient(remoteClient);
|
||||
}
|
||||
|
||||
group.RemoveInventoryItem(localID, itemID);
|
||||
part.SendPropertiesToClient(remoteClient);
|
||||
}
|
||||
|
||||
private InventoryItemBase CreateAgentInventoryItemFromTask(UUID destAgent, SceneObjectPart part, UUID itemId)
|
||||
@@ -1058,7 +1073,15 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (!Permissions.BypassPermissions())
|
||||
{
|
||||
if ((taskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
|
||||
{
|
||||
if (taskItem.Type == 10)
|
||||
{
|
||||
part.RemoveScriptEvents(itemId);
|
||||
EventManager.TriggerRemoveScript(part.LocalId, itemId);
|
||||
}
|
||||
|
||||
part.Inventory.RemoveInventoryItem(itemId);
|
||||
}
|
||||
}
|
||||
|
||||
return agentItem;
|
||||
@@ -1421,7 +1444,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// If we've found the item in the user's inventory or in the library
|
||||
if (item != null)
|
||||
{
|
||||
part.ParentGroup.AddInventoryItem(remoteClient, primLocalID, item, copyID);
|
||||
part.ParentGroup.AddInventoryItem(remoteClient.AgentId, primLocalID, item, copyID);
|
||||
m_log.InfoFormat(
|
||||
"[PRIM INVENTORY]: Update with item {0} requested of prim {1} for {2}",
|
||||
item.Name, primLocalID, remoteClient.Name);
|
||||
@@ -1449,20 +1472,27 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// m_log.DebugFormat(
|
||||
// "[PRIM INVENTORY]: Updating item {0} in {1} for UpdateTaskInventory()",
|
||||
// currentItem.Name, part.Name);
|
||||
|
||||
IAgentAssetTransactions agentTransactions = this.RequestModuleInterface<IAgentAssetTransactions>();
|
||||
if (agentTransactions != null)
|
||||
{
|
||||
agentTransactions.HandleTaskItemUpdateFromTransaction(
|
||||
remoteClient, part, transactionID, currentItem);
|
||||
|
||||
if ((InventoryType)itemInfo.InvType == InventoryType.Notecard)
|
||||
remoteClient.SendAgentAlertMessage("Notecard saved", false);
|
||||
else if ((InventoryType)itemInfo.InvType == InventoryType.LSL)
|
||||
remoteClient.SendAgentAlertMessage("Script saved", false);
|
||||
else
|
||||
remoteClient.SendAgentAlertMessage("Item saved", false);
|
||||
}
|
||||
// Viewers from at least Linden Lab 1.23 onwards use a capability to update script contents rather
|
||||
// than UDP. With viewers from at least 1.23 onwards, changing properties on scripts (e.g. renaming) causes
|
||||
// this to spew spurious errors and "thing saved" messages.
|
||||
// Rather than retaining complexity in the code and removing useful error messages, I'm going to
|
||||
// comment this section out. If this was still working for very old viewers and there is
|
||||
// a large population using them which cannot upgrade to 1.23 or derivatives then we can revisit
|
||||
// this - justincc
|
||||
// IAgentAssetTransactions agentTransactions = this.RequestModuleInterface<IAgentAssetTransactions>();
|
||||
// if (agentTransactions != null)
|
||||
// {
|
||||
// agentTransactions.HandleTaskItemUpdateFromTransaction(
|
||||
// remoteClient, part, transactionID, currentItem);
|
||||
//
|
||||
// if ((InventoryType)itemInfo.InvType == InventoryType.Notecard)
|
||||
// remoteClient.SendAgentAlertMessage("Notecard saved", false);
|
||||
// else if ((InventoryType)itemInfo.InvType == InventoryType.LSL)
|
||||
// remoteClient.SendAgentAlertMessage("Script saved", false);
|
||||
// else
|
||||
// remoteClient.SendAgentAlertMessage("Item saved", false);
|
||||
// }
|
||||
|
||||
// Base ALWAYS has move
|
||||
currentItem.BasePermissions |= (uint)PermissionMask.Move;
|
||||
@@ -1537,104 +1567,141 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// Rez a script into a prim's inventory, either ex nihilo or from an existing avatar inventory
|
||||
/// </summary>
|
||||
/// <param name="remoteClient"></param>
|
||||
/// <param name="itemID"> </param>
|
||||
/// <param name="itemBase"> </param>
|
||||
/// <param name="transactionID"></param>
|
||||
/// <param name="localID"></param>
|
||||
public void RezScript(IClientAPI remoteClient, InventoryItemBase itemBase, UUID transactionID, uint localID)
|
||||
{
|
||||
UUID itemID = itemBase.ID;
|
||||
SceneObjectPart partWhereRezzed;
|
||||
|
||||
if (itemBase.ID != UUID.Zero)
|
||||
partWhereRezzed = RezScriptFromAgentInventory(remoteClient.AgentId, itemBase.ID, localID);
|
||||
else
|
||||
partWhereRezzed = RezNewScript(remoteClient.AgentId, itemBase);
|
||||
|
||||
if (partWhereRezzed != null)
|
||||
partWhereRezzed.SendPropertiesToClient(remoteClient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rez a script into a prim from an agent inventory.
|
||||
/// </summary>
|
||||
/// <param name="agentID"></param>
|
||||
/// <param name="fromItemID"></param>
|
||||
/// <param name="localID"></param>
|
||||
/// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
|
||||
public SceneObjectPart RezScriptFromAgentInventory(UUID agentID, UUID fromItemID, uint localID)
|
||||
{
|
||||
UUID copyID = UUID.Random();
|
||||
InventoryItemBase item = new InventoryItemBase(fromItemID, agentID);
|
||||
item = InventoryService.GetItem(item);
|
||||
|
||||
if (itemID != UUID.Zero) // transferred from an avatar inventory to the prim's inventory
|
||||
// Try library
|
||||
// XXX clumsy, possibly should be one call
|
||||
if (null == item && LibraryService != null && LibraryService.LibraryRootFolder != null)
|
||||
{
|
||||
InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
|
||||
item = InventoryService.GetItem(item);
|
||||
item = LibraryService.LibraryRootFolder.FindItem(fromItemID);
|
||||
}
|
||||
|
||||
// Try library
|
||||
// XXX clumsy, possibly should be one call
|
||||
if (null == item && LibraryService != null && LibraryService.LibraryRootFolder != null)
|
||||
if (item != null)
|
||||
{
|
||||
SceneObjectPart part = GetSceneObjectPart(localID);
|
||||
if (part != null)
|
||||
{
|
||||
item = LibraryService.LibraryRootFolder.FindItem(itemID);
|
||||
}
|
||||
if (!Permissions.CanEditObjectInventory(part.UUID, agentID))
|
||||
return null;
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
SceneObjectPart part = GetSceneObjectPart(localID);
|
||||
if (part != null)
|
||||
{
|
||||
if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId))
|
||||
return;
|
||||
part.ParentGroup.AddInventoryItem(agentID, localID, item, copyID);
|
||||
// TODO: switch to posting on_rez here when scripts
|
||||
// have state in inventory
|
||||
part.Inventory.CreateScriptInstance(copyID, 0, false, DefaultScriptEngine, 0);
|
||||
|
||||
part.ParentGroup.AddInventoryItem(remoteClient, localID, item, copyID);
|
||||
// TODO: switch to posting on_rez here when scripts
|
||||
// have state in inventory
|
||||
part.Inventory.CreateScriptInstance(copyID, 0, false, DefaultScriptEngine, 0);
|
||||
// m_log.InfoFormat("[PRIMINVENTORY]: " +
|
||||
// "Rezzed script {0} into prim local ID {1} for user {2}",
|
||||
// item.inventoryName, localID, remoteClient.Name);
|
||||
part.ParentGroup.ResumeScripts();
|
||||
|
||||
// m_log.InfoFormat("[PRIMINVENTORY]: " +
|
||||
// "Rezzed script {0} into prim local ID {1} for user {2}",
|
||||
// item.inventoryName, localID, remoteClient.Name);
|
||||
part.SendPropertiesToClient(remoteClient);
|
||||
part.ParentGroup.ResumeScripts();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[PRIM INVENTORY]: " +
|
||||
"Could not rez script {0} into prim local ID {1} for user {2}"
|
||||
+ " because the prim could not be found in the region!",
|
||||
item.Name, localID, remoteClient.Name);
|
||||
}
|
||||
return part;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[PRIM INVENTORY]: Could not find script inventory item {0} to rez for {1}!",
|
||||
itemID, remoteClient.Name);
|
||||
"[PRIM INVENTORY]: " +
|
||||
"Could not rez script {0} into prim local ID {1} for user {2}"
|
||||
+ " because the prim could not be found in the region!",
|
||||
item.Name, localID, agentID);
|
||||
}
|
||||
}
|
||||
else // script has been rezzed directly into a prim's inventory
|
||||
else
|
||||
{
|
||||
SceneObjectPart part = GetSceneObjectPart(itemBase.Folder);
|
||||
if (part == null)
|
||||
return;
|
||||
|
||||
if (!Permissions.CanCreateObjectInventory(
|
||||
itemBase.InvType, part.UUID, remoteClient.AgentId))
|
||||
return;
|
||||
|
||||
AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType,
|
||||
Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"),
|
||||
remoteClient.AgentId);
|
||||
AssetService.Store(asset);
|
||||
|
||||
TaskInventoryItem taskItem = new TaskInventoryItem();
|
||||
|
||||
taskItem.ResetIDs(itemBase.Folder);
|
||||
taskItem.ParentID = itemBase.Folder;
|
||||
taskItem.CreationDate = (uint)itemBase.CreationDate;
|
||||
taskItem.Name = itemBase.Name;
|
||||
taskItem.Description = itemBase.Description;
|
||||
taskItem.Type = itemBase.AssetType;
|
||||
taskItem.InvType = itemBase.InvType;
|
||||
taskItem.OwnerID = itemBase.Owner;
|
||||
taskItem.CreatorID = itemBase.CreatorIdAsUuid;
|
||||
taskItem.BasePermissions = itemBase.BasePermissions;
|
||||
taskItem.CurrentPermissions = itemBase.CurrentPermissions;
|
||||
taskItem.EveryonePermissions = itemBase.EveryOnePermissions;
|
||||
taskItem.GroupPermissions = itemBase.GroupPermissions;
|
||||
taskItem.NextPermissions = itemBase.NextPermissions;
|
||||
taskItem.GroupID = itemBase.GroupID;
|
||||
taskItem.GroupPermissions = 0;
|
||||
taskItem.Flags = itemBase.Flags;
|
||||
taskItem.PermsGranter = UUID.Zero;
|
||||
taskItem.PermsMask = 0;
|
||||
taskItem.AssetID = asset.FullID;
|
||||
|
||||
part.Inventory.AddInventoryItem(taskItem, false);
|
||||
part.SendPropertiesToClient(remoteClient);
|
||||
|
||||
part.Inventory.CreateScriptInstance(taskItem, 0, false, DefaultScriptEngine, 0);
|
||||
part.ParentGroup.ResumeScripts();
|
||||
m_log.ErrorFormat(
|
||||
"[PRIM INVENTORY]: Could not find script inventory item {0} to rez for {1}!",
|
||||
fromItemID, agentID);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rez a new script from nothing.
|
||||
/// </summary>
|
||||
/// <param name="remoteClient"></param>
|
||||
/// <param name="itemBase"></param>
|
||||
/// <returns>The part where the script was rezzed if successful. False otherwise.</returns>
|
||||
public SceneObjectPart RezNewScript(UUID agentID, InventoryItemBase itemBase)
|
||||
{
|
||||
// The part ID is the folder ID!
|
||||
SceneObjectPart part = GetSceneObjectPart(itemBase.Folder);
|
||||
if (part == null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENE INVENTORY]: Could not find part with id {0} for {1} to rez new script",
|
||||
// itemBase.Folder, agentID);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!Permissions.CanCreateObjectInventory(itemBase.InvType, part.UUID, agentID))
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENE INVENTORY]: No permission to create new script in {0} for {1}", part.Name, agentID);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
AssetBase asset = CreateAsset(itemBase.Name, itemBase.Description, (sbyte)itemBase.AssetType,
|
||||
Encoding.ASCII.GetBytes("default\n{\n state_entry()\n {\n llSay(0, \"Script running\");\n }\n}"),
|
||||
agentID);
|
||||
AssetService.Store(asset);
|
||||
|
||||
TaskInventoryItem taskItem = new TaskInventoryItem();
|
||||
|
||||
taskItem.ResetIDs(itemBase.Folder);
|
||||
taskItem.ParentID = itemBase.Folder;
|
||||
taskItem.CreationDate = (uint)itemBase.CreationDate;
|
||||
taskItem.Name = itemBase.Name;
|
||||
taskItem.Description = itemBase.Description;
|
||||
taskItem.Type = itemBase.AssetType;
|
||||
taskItem.InvType = itemBase.InvType;
|
||||
taskItem.OwnerID = itemBase.Owner;
|
||||
taskItem.CreatorID = itemBase.CreatorIdAsUuid;
|
||||
taskItem.BasePermissions = itemBase.BasePermissions;
|
||||
taskItem.CurrentPermissions = itemBase.CurrentPermissions;
|
||||
taskItem.EveryonePermissions = itemBase.EveryOnePermissions;
|
||||
taskItem.GroupPermissions = itemBase.GroupPermissions;
|
||||
taskItem.NextPermissions = itemBase.NextPermissions;
|
||||
taskItem.GroupID = itemBase.GroupID;
|
||||
taskItem.GroupPermissions = 0;
|
||||
taskItem.Flags = itemBase.Flags;
|
||||
taskItem.PermsGranter = UUID.Zero;
|
||||
taskItem.PermsMask = 0;
|
||||
taskItem.AssetID = asset.FullID;
|
||||
|
||||
part.Inventory.AddInventoryItem(taskItem, false);
|
||||
part.Inventory.CreateScriptInstance(taskItem, 0, false, DefaultScriptEngine, 0);
|
||||
part.ParentGroup.ResumeScripts();
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1643,7 +1710,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// <param name="remoteClient"></param>
|
||||
/// <param name="itemID"> </param>
|
||||
/// <param name="localID"></param>
|
||||
public void RezScript(UUID srcId, SceneObjectPart srcPart, UUID destId, int pin, int running, int start_param)
|
||||
public void RezScriptFromPrim(UUID srcId, SceneObjectPart srcPart, UUID destId, int pin, int running, int start_param)
|
||||
{
|
||||
TaskInventoryItem srcTaskItem = srcPart.Inventory.GetInventoryItem(srcId);
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
#region Fields
|
||||
|
||||
public bool EmergencyMonitoring = false;
|
||||
public bool DEBUG = false;
|
||||
|
||||
public SynchronizeSceneHandler SynchronizeScene;
|
||||
public SimStatsReporter StatsReporter;
|
||||
@@ -599,23 +600,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
"reload estate",
|
||||
"Reload the estate data", HandleReloadEstate);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand("region", false, "delete object owner",
|
||||
"delete object owner <UUID>",
|
||||
"Delete object by owner", HandleDeleteObject);
|
||||
MainConsole.Instance.Commands.AddCommand("region", false, "delete object creator",
|
||||
"delete object creator <UUID>",
|
||||
"Delete object by creator", HandleDeleteObject);
|
||||
MainConsole.Instance.Commands.AddCommand("region", false, "delete object uuid",
|
||||
"delete object uuid <UUID>",
|
||||
"Delete object by uuid", HandleDeleteObject);
|
||||
MainConsole.Instance.Commands.AddCommand("region", false, "delete object name",
|
||||
"delete object name <name>",
|
||||
"Delete object by name", HandleDeleteObject);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand("region", false, "delete object outside",
|
||||
"delete object outside",
|
||||
"Delete all objects outside boundaries", HandleDeleteObject);
|
||||
|
||||
//Bind Storage Manager functions to some land manager functions for this scene
|
||||
EventManager.OnLandObjectAdded +=
|
||||
new EventManager.LandObjectAdded(simDataService.StoreLandObject);
|
||||
@@ -1942,6 +1926,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// If true, the object is made persistent into the scene.
|
||||
/// If false, the object will not persist over server restarts
|
||||
/// </param>
|
||||
/// <returns>true if the object was added. false if not</returns>
|
||||
public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup)
|
||||
{
|
||||
return AddNewSceneObject(sceneObject, attachToBackup, true);
|
||||
@@ -1959,6 +1944,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// If true, updates for the new scene object are sent to all viewers in range.
|
||||
/// If false, it is left to the caller to schedule the update
|
||||
/// </param>
|
||||
/// <returns>true if the object was added. false if not</returns>
|
||||
public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
|
||||
{
|
||||
if (m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup, sendClientUpdates))
|
||||
@@ -2528,7 +2514,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type);
|
||||
m_eventManager.TriggerOnNewPresence(sp);
|
||||
|
||||
sp.TeleportFlags = (TeleportFlags)aCircuit.teleportFlags;
|
||||
sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags;
|
||||
|
||||
// The first agent upon login is a root agent by design.
|
||||
// For this agent we will have to rez the attachments.
|
||||
@@ -3070,11 +3056,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
public override void RemoveClient(UUID agentID, bool closeChildAgents)
|
||||
{
|
||||
CheckHeartbeat();
|
||||
bool childagentYN = false;
|
||||
bool isChildAgent = false;
|
||||
ScenePresence avatar = GetScenePresence(agentID);
|
||||
if (avatar != null)
|
||||
{
|
||||
childagentYN = avatar.IsChildAgent;
|
||||
isChildAgent = avatar.IsChildAgent;
|
||||
|
||||
if (avatar.ParentID != 0)
|
||||
{
|
||||
@@ -3085,9 +3071,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[SCENE]: Removing {0} agent {1} from region {2}",
|
||||
(childagentYN ? "child" : "root"), agentID, RegionInfo.RegionName);
|
||||
(isChildAgent ? "child" : "root"), agentID, RegionInfo.RegionName);
|
||||
|
||||
m_sceneGraph.removeUserCount(!childagentYN);
|
||||
m_sceneGraph.removeUserCount(!isChildAgent);
|
||||
|
||||
// TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop
|
||||
// unnecessary operations. This should go away once NPCs have no accompanying IClientAPI
|
||||
@@ -3117,8 +3103,18 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
m_eventManager.TriggerOnRemovePresence(agentID);
|
||||
|
||||
if (AttachmentsModule != null && !avatar.IsChildAgent && avatar.PresenceType != PresenceType.Npc)
|
||||
AttachmentsModule.SaveChangedAttachments(avatar);
|
||||
if (AttachmentsModule != null && !isChildAgent && avatar.PresenceType != PresenceType.Npc)
|
||||
{
|
||||
IUserManagement uMan = RequestModuleInterface<IUserManagement>();
|
||||
// Don't save attachments for HG visitors, it
|
||||
// messes up their inventory. When a HG visitor logs
|
||||
// out on a foreign grid, their attachments will be
|
||||
// reloaded in the state they were in when they left
|
||||
// the home grid. This is best anyway as the visited
|
||||
// grid may use an incompatible script engine.
|
||||
if (uMan == null || uMan.IsLocalGridUser(avatar.UUID))
|
||||
AttachmentsModule.SaveChangedAttachments(avatar, false);
|
||||
}
|
||||
|
||||
ForEachClient(
|
||||
delegate(IClientAPI client)
|
||||
@@ -3333,7 +3329,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
// Let the SP know how we got here. This has a lot of interesting
|
||||
// uses down the line.
|
||||
sp.TeleportFlags = (TeleportFlags)teleportFlags;
|
||||
sp.TeleportFlags = (TPFlags)teleportFlags;
|
||||
|
||||
if (sp.IsChildAgent)
|
||||
{
|
||||
@@ -4867,93 +4863,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDeleteObject(string module, string[] cmd)
|
||||
{
|
||||
if (cmd.Length < 3)
|
||||
return;
|
||||
|
||||
string mode = cmd[2];
|
||||
string o = "";
|
||||
|
||||
if (mode != "outside")
|
||||
{
|
||||
if (cmd.Length < 4)
|
||||
return;
|
||||
|
||||
o = cmd[3];
|
||||
}
|
||||
|
||||
List<SceneObjectGroup> deletes = new List<SceneObjectGroup>();
|
||||
|
||||
UUID match;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case "owner":
|
||||
if (!UUID.TryParse(o, out match))
|
||||
return;
|
||||
ForEachSOG(delegate (SceneObjectGroup g)
|
||||
{
|
||||
if (g.OwnerID == match && !g.IsAttachment)
|
||||
deletes.Add(g);
|
||||
});
|
||||
break;
|
||||
case "creator":
|
||||
if (!UUID.TryParse(o, out match))
|
||||
return;
|
||||
ForEachSOG(delegate (SceneObjectGroup g)
|
||||
{
|
||||
if (g.RootPart.CreatorID == match && !g.IsAttachment)
|
||||
deletes.Add(g);
|
||||
});
|
||||
break;
|
||||
case "uuid":
|
||||
if (!UUID.TryParse(o, out match))
|
||||
return;
|
||||
ForEachSOG(delegate (SceneObjectGroup g)
|
||||
{
|
||||
if (g.UUID == match && !g.IsAttachment)
|
||||
deletes.Add(g);
|
||||
});
|
||||
break;
|
||||
case "name":
|
||||
ForEachSOG(delegate (SceneObjectGroup g)
|
||||
{
|
||||
if (g.RootPart.Name == o && !g.IsAttachment)
|
||||
deletes.Add(g);
|
||||
});
|
||||
break;
|
||||
case "outside":
|
||||
ForEachSOG(delegate (SceneObjectGroup g)
|
||||
{
|
||||
SceneObjectPart rootPart = g.RootPart;
|
||||
bool delete = false;
|
||||
|
||||
if (rootPart.GroupPosition.Z < 0.0 || rootPart.GroupPosition.Z > 10000.0)
|
||||
{
|
||||
delete = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ILandObject parcel = LandChannel.GetLandObject(rootPart.GroupPosition.X, rootPart.GroupPosition.Y);
|
||||
|
||||
if (parcel == null || parcel.LandData.Name == "NO LAND")
|
||||
delete = true;
|
||||
}
|
||||
|
||||
if (delete && !g.IsAttachment && !deletes.Contains(g))
|
||||
deletes.Add(g);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (SceneObjectGroup g in deletes)
|
||||
{
|
||||
m_log.InfoFormat("[SCENE]: Deleting object {0}", g.UUID);
|
||||
DeleteSceneObject(g, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleReloadEstate(string module, string[] cmd)
|
||||
{
|
||||
if (MainConsole.Instance.ConsoleScene == null ||
|
||||
@@ -5076,6 +4985,36 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
if (position == Vector3.Zero) // Teleport
|
||||
{
|
||||
if (!RegionInfo.EstateSettings.AllowDirectTeleport)
|
||||
{
|
||||
SceneObjectGroup telehub;
|
||||
if (RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject)) != null)
|
||||
{
|
||||
List<SpawnPoint> spawnPoints = RegionInfo.RegionSettings.SpawnPoints();
|
||||
bool banned = true;
|
||||
foreach (SpawnPoint sp in spawnPoints)
|
||||
{
|
||||
Vector3 spawnPoint = sp.GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
|
||||
ILandObject land = LandChannel.GetLandObject(spawnPoint.X, spawnPoint.Y);
|
||||
if (land == null)
|
||||
continue;
|
||||
if (land.IsEitherBannedOrRestricted(agentID))
|
||||
continue;
|
||||
banned = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (banned)
|
||||
{
|
||||
reason = "No suitable landing point found";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reason = String.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,12 +41,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
public delegate void PhysicsCrash();
|
||||
|
||||
public delegate void ObjectDuplicateDelegate(EntityBase original, EntityBase clone);
|
||||
|
||||
public delegate void ObjectCreateDelegate(EntityBase obj);
|
||||
|
||||
public delegate void ObjectDeleteDelegate(EntityBase obj);
|
||||
|
||||
/// <summary>
|
||||
/// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components
|
||||
/// should be migrated out over time.
|
||||
@@ -60,10 +54,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
protected internal event PhysicsCrash UnRecoverableError;
|
||||
private PhysicsCrash handlerPhysicsCrash = null;
|
||||
|
||||
public event ObjectDuplicateDelegate OnObjectDuplicate;
|
||||
public event ObjectCreateDelegate OnObjectCreate;
|
||||
public event ObjectDeleteDelegate OnObjectRemove;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Fields
|
||||
@@ -364,11 +354,23 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// </returns>
|
||||
protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
|
||||
{
|
||||
if (sceneObject == null || sceneObject.RootPart.UUID == UUID.Zero)
|
||||
if (sceneObject.UUID == UUID.Zero)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[SCENEGRAPH]: Tried to add scene object {0} to {1} with illegal UUID of {2}",
|
||||
sceneObject.Name, m_parentScene.RegionInfo.RegionName, UUID.Zero);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Entities.ContainsKey(sceneObject.UUID))
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENEGRAPH]: Scene graph for {0} already contains object {1} in AddSceneObject()",
|
||||
// m_parentScene.RegionInfo.RegionName, sceneObject.UUID);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENEGRAPH]: Adding scene object {0} {1}, with {2} parts on {3}",
|
||||
@@ -405,9 +407,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (attachToBackup)
|
||||
sceneObject.AttachToBackup();
|
||||
|
||||
if (OnObjectCreate != null)
|
||||
OnObjectCreate(sceneObject);
|
||||
|
||||
lock (SceneObjectGroupsByFullID)
|
||||
SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject;
|
||||
|
||||
@@ -456,9 +455,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if ((grp.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics)
|
||||
RemovePhysicalPrim(grp.PrimCount);
|
||||
}
|
||||
|
||||
if (OnObjectRemove != null)
|
||||
OnObjectRemove(Entities[uuid]);
|
||||
|
||||
lock (SceneObjectGroupsByFullID)
|
||||
SceneObjectGroupsByFullID.Remove(grp.UUID);
|
||||
@@ -1154,8 +1150,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// <param name="action"></param>
|
||||
protected internal void ForEachSOG(Action<SceneObjectGroup> action)
|
||||
{
|
||||
// FIXME: Need to lock here, really.
|
||||
List<SceneObjectGroup> objlist = new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values);
|
||||
List<SceneObjectGroup> objlist;
|
||||
lock (SceneObjectGroupsByFullID)
|
||||
objlist = new List<SceneObjectGroup>(SceneObjectGroupsByFullID.Values);
|
||||
|
||||
foreach (SceneObjectGroup obj in objlist)
|
||||
{
|
||||
try
|
||||
@@ -1164,7 +1162,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Catch it and move on. This includes situations where splist has inconsistent info
|
||||
// Catch it and move on. This includes situations where objlist has inconsistent info
|
||||
m_log.WarnFormat(
|
||||
"[SCENEGRAPH]: Problem processing action in ForEachSOG: {0} {1}", e.Message, e.StackTrace);
|
||||
}
|
||||
@@ -1399,10 +1397,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// <summary>
|
||||
/// Update the texture entry of the given prim.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// A texture entry is an object that contains details of all the textures of the prim's face. In this case,
|
||||
/// the texture is given in its byte serialized form.
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="localID"></param>
|
||||
/// <param name="texture"></param>
|
||||
/// <param name="remoteClient"></param>
|
||||
@@ -1980,9 +1978,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// required for physics to update it's position
|
||||
copy.AbsolutePosition = copy.AbsolutePosition;
|
||||
|
||||
if (OnObjectDuplicate != null)
|
||||
OnObjectDuplicate(original, copy);
|
||||
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,13 +83,12 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// <summary>
|
||||
/// Add an inventory item from a user's inventory to a prim in this scene object.
|
||||
/// </summary>
|
||||
/// <param name="remoteClient">The client adding the item.</param>
|
||||
/// <param name="agentID">The agent adding the item.</param>
|
||||
/// <param name="localID">The local ID of the part receiving the add.</param>
|
||||
/// <param name="item">The user inventory item being added.</param>
|
||||
/// <param name="copyItemID">The item UUID that should be used by the new item.</param>
|
||||
/// <returns></returns>
|
||||
public bool AddInventoryItem(IClientAPI remoteClient, uint localID,
|
||||
InventoryItemBase item, UUID copyItemID)
|
||||
public bool AddInventoryItem(UUID agentID, uint localID, InventoryItemBase item, UUID copyItemID)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[PRIM INVENTORY]: Adding inventory item {0} from {1} to part with local ID {2}",
|
||||
@@ -111,9 +110,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
taskItem.Type = item.AssetType;
|
||||
taskItem.InvType = item.InvType;
|
||||
|
||||
if (remoteClient != null &&
|
||||
remoteClient.AgentId != part.OwnerID &&
|
||||
m_scene.Permissions.PropagatePermissions())
|
||||
if (agentID != part.OwnerID && m_scene.Permissions.PropagatePermissions())
|
||||
{
|
||||
taskItem.BasePermissions = item.BasePermissions &
|
||||
item.NextPermissions;
|
||||
@@ -148,11 +145,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// taskItem.SaleType = item.SaleType;
|
||||
taskItem.CreationDate = (uint)item.CreationDate;
|
||||
|
||||
bool addFromAllowedDrop = false;
|
||||
if (remoteClient != null)
|
||||
{
|
||||
addFromAllowedDrop = remoteClient.AgentId != part.OwnerID;
|
||||
}
|
||||
bool addFromAllowedDrop = agentID != part.OwnerID;
|
||||
|
||||
part.Inventory.AddInventoryItem(taskItem, addFromAllowedDrop);
|
||||
|
||||
|
||||
@@ -264,6 +264,12 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
set { RootPart.Name = value; }
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get { return RootPart.Description; }
|
||||
set { RootPart.Description = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Added because the Parcel code seems to use it
|
||||
/// but not sure a object should have this
|
||||
@@ -441,6 +447,12 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
public UUID LastOwnerID
|
||||
{
|
||||
get { return m_rootPart.LastOwnerID; }
|
||||
set { m_rootPart.LastOwnerID = value; }
|
||||
}
|
||||
|
||||
public UUID OwnerID
|
||||
{
|
||||
get { return m_rootPart.OwnerID; }
|
||||
@@ -1613,12 +1625,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
RootPart.PhysActor.PIDActive = false;
|
||||
}
|
||||
|
||||
public void stopLookAt()
|
||||
{
|
||||
if (RootPart.PhysActor != null)
|
||||
RootPart.PhysActor.APIDActive = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
|
||||
/// </summary>
|
||||
|
||||
@@ -217,11 +217,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
public Quaternion SpinOldOrientation = Quaternion.Identity;
|
||||
|
||||
public Quaternion m_APIDTarget = Quaternion.Identity;
|
||||
|
||||
public float m_APIDDamp = 0;
|
||||
|
||||
public float m_APIDStrength = 0;
|
||||
protected int m_APIDIterations = 0;
|
||||
protected Quaternion m_APIDTarget = Quaternion.Identity;
|
||||
protected float m_APIDDamp = 0;
|
||||
protected float m_APIDStrength = 0;
|
||||
|
||||
/// <summary>
|
||||
/// This part's inventory
|
||||
@@ -394,7 +393,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
private string m_creatorData = string.Empty;
|
||||
/// <summary>
|
||||
/// Data about the creator in the form profile_url;name
|
||||
/// Data about the creator in the form home_url;name
|
||||
/// </summary>
|
||||
public string CreatorData
|
||||
{
|
||||
@@ -405,7 +404,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// <summary>
|
||||
/// Used by the DB layer to retrieve / store the entire user identification.
|
||||
/// The identification can either be a simple UUID or a string of the form
|
||||
/// uuid[;profile_url[;name]]
|
||||
/// uuid[;home_url[;name]]
|
||||
/// </summary>
|
||||
public string CreatorIdentification
|
||||
{
|
||||
@@ -563,22 +562,21 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Quaternion APIDTarget
|
||||
protected Quaternion APIDTarget
|
||||
{
|
||||
get { return m_APIDTarget; }
|
||||
set { m_APIDTarget = value; }
|
||||
}
|
||||
|
||||
|
||||
public float APIDDamp
|
||||
protected float APIDDamp
|
||||
{
|
||||
get { return m_APIDDamp; }
|
||||
set { m_APIDDamp = value; }
|
||||
}
|
||||
|
||||
|
||||
public float APIDStrength
|
||||
protected float APIDStrength
|
||||
{
|
||||
get { return m_APIDStrength; }
|
||||
set { m_APIDStrength = value; }
|
||||
@@ -1946,19 +1944,13 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
public Vector3 GetWorldPosition()
|
||||
{
|
||||
Quaternion parentRot = ParentGroup.RootPart.RotationOffset;
|
||||
|
||||
Vector3 axPos = OffsetPosition;
|
||||
|
||||
axPos *= parentRot;
|
||||
Vector3 translationOffsetPosition = axPos;
|
||||
|
||||
// m_log.DebugFormat("[SCENE OBJECT PART]: Found group pos {0} for part {1}", GroupPosition, Name);
|
||||
|
||||
Vector3 worldPos = GroupPosition + translationOffsetPosition;
|
||||
|
||||
// m_log.DebugFormat("[SCENE OBJECT PART]: Found world pos {0} for part {1}", worldPos, Name);
|
||||
|
||||
return worldPos;
|
||||
if(_parentID == 0)
|
||||
return GroupPosition;
|
||||
else
|
||||
return ParentGroup.AbsolutePosition + translationOffsetPosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2688,11 +2680,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
|
||||
public void RotLookAt(Quaternion target, float strength, float damping)
|
||||
{
|
||||
rotLookAt(target, strength, damping);
|
||||
}
|
||||
|
||||
public void rotLookAt(Quaternion target, float strength, float damping)
|
||||
{
|
||||
if (ParentGroup.IsAttachment)
|
||||
{
|
||||
@@ -2708,17 +2695,26 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
APIDDamp = damping;
|
||||
APIDStrength = strength;
|
||||
APIDTarget = target;
|
||||
|
||||
if (APIDStrength <= 0)
|
||||
{
|
||||
m_log.WarnFormat("[SceneObjectPart] Invalid rotation strength {0}",APIDStrength);
|
||||
return;
|
||||
}
|
||||
|
||||
m_APIDIterations = 1 + (int)(Math.PI * APIDStrength);
|
||||
}
|
||||
|
||||
// Necessary to get the lookat deltas applied
|
||||
ParentGroup.QueueForUpdateCheck();
|
||||
}
|
||||
|
||||
public void startLookAt(Quaternion rot, float damp, float strength)
|
||||
public void StartLookAt(Quaternion target, float strength, float damping)
|
||||
{
|
||||
APIDDamp = damp;
|
||||
APIDStrength = strength;
|
||||
APIDTarget = rot;
|
||||
RotLookAt(target,strength,damping);
|
||||
}
|
||||
|
||||
public void stopLookAt()
|
||||
public void StopLookAt()
|
||||
{
|
||||
APIDTarget = Quaternion.Identity;
|
||||
}
|
||||
@@ -3413,13 +3409,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
public void StopLookAt()
|
||||
{
|
||||
ParentGroup.stopLookAt();
|
||||
|
||||
ParentGroup.ScheduleGroupForTerseUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the text displayed for this part.
|
||||
/// </summary>
|
||||
@@ -4521,10 +4510,18 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// <summary>
|
||||
/// Update the texture entry for this part.
|
||||
/// </summary>
|
||||
/// <param name="textureEntry"></param>
|
||||
public void UpdateTextureEntry(byte[] textureEntry)
|
||||
/// <param name="serializedTextureEntry"></param>
|
||||
public void UpdateTextureEntry(byte[] serializedTextureEntry)
|
||||
{
|
||||
UpdateTextureEntry(new Primitive.TextureEntry(serializedTextureEntry, 0, serializedTextureEntry.Length));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the texture entry for this part.
|
||||
/// </summary>
|
||||
/// <param name="newTex"></param>
|
||||
public void UpdateTextureEntry(Primitive.TextureEntry newTex)
|
||||
{
|
||||
Primitive.TextureEntry newTex = new Primitive.TextureEntry(textureEntry, 0, textureEntry.Length);
|
||||
Primitive.TextureEntry oldTex = Shape.Textures;
|
||||
|
||||
Changed changeFlags = 0;
|
||||
@@ -4556,7 +4553,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
break;
|
||||
}
|
||||
|
||||
m_shape.TextureEntry = textureEntry;
|
||||
m_shape.TextureEntry = newTex.GetBytes();
|
||||
if (changeFlags != 0)
|
||||
TriggerScriptChangedEvent(changeFlags);
|
||||
UpdateFlag = UpdateRequired.FULL;
|
||||
@@ -4727,24 +4724,20 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
if (APIDTarget != Quaternion.Identity)
|
||||
{
|
||||
if (Single.IsNaN(APIDTarget.W) == true)
|
||||
if (m_APIDIterations <= 1)
|
||||
{
|
||||
UpdateRotation(APIDTarget);
|
||||
APIDTarget = Quaternion.Identity;
|
||||
return;
|
||||
}
|
||||
Quaternion rot = RotationOffset;
|
||||
Quaternion dir = (rot - APIDTarget);
|
||||
float speed = ((APIDStrength / APIDDamp) * (float)(Math.PI / 180.0f));
|
||||
if (dir.Z > speed)
|
||||
{
|
||||
rot.Z -= speed;
|
||||
}
|
||||
if (dir.Z < -speed)
|
||||
{
|
||||
rot.Z += speed;
|
||||
}
|
||||
rot.Normalize();
|
||||
|
||||
Quaternion rot = Quaternion.Slerp(RotationOffset,APIDTarget,1.0f/(float)m_APIDIterations);
|
||||
UpdateRotation(rot);
|
||||
|
||||
m_APIDIterations--;
|
||||
|
||||
// This ensures that we'll check this object on the next iteration
|
||||
ParentGroup.QueueForUpdateCheck();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -40,6 +40,7 @@ using OpenSim.Region.Framework.Scenes.Types;
|
||||
using OpenSim.Region.Physics.Manager;
|
||||
using GridRegion = OpenSim.Services.Interfaces.GridRegion;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags;
|
||||
|
||||
namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
@@ -892,6 +893,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
pos.Y = crossedBorder.BorderLine.Z - 1;
|
||||
}
|
||||
|
||||
CheckAndAdjustLandingPoint(ref pos);
|
||||
|
||||
if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
@@ -1056,6 +1059,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
bool isFlying = Flying;
|
||||
RemoveFromPhysicalScene();
|
||||
Velocity = Vector3.Zero;
|
||||
CheckLandingPoint(ref pos);
|
||||
AbsolutePosition = pos;
|
||||
AddToPhysicalScene(isFlying);
|
||||
|
||||
@@ -1066,6 +1070,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
bool isFlying = Flying;
|
||||
RemoveFromPhysicalScene();
|
||||
CheckLandingPoint(ref pos);
|
||||
AbsolutePosition = pos;
|
||||
AddToPhysicalScene(isFlying);
|
||||
|
||||
@@ -1180,6 +1185,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
client.Name, Scene.RegionInfo.RegionName, AbsolutePosition);
|
||||
|
||||
Vector3 look = Velocity;
|
||||
|
||||
if ((look.X == 0) && (look.Y == 0) && (look.Z == 0))
|
||||
{
|
||||
look = new Vector3(0.99f, 0.042f, 0);
|
||||
@@ -1206,7 +1212,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
m_callbackURI = null;
|
||||
}
|
||||
|
||||
//m_log.DebugFormat("[SCENE PRESENCE] Completed movement");
|
||||
// m_log.DebugFormat("[SCENE PRESENCE] Completed movement");
|
||||
|
||||
ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);
|
||||
ValidateAndSendAppearanceAndAgentData();
|
||||
@@ -1274,8 +1280,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENE PRESENCE]: In {0} received agent update from {1}",
|
||||
// Scene.RegionInfo.RegionName, remoteClient.Name);
|
||||
// "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}",
|
||||
// Scene.RegionInfo.RegionName, remoteClient.Name, agentData.ControlFlags);
|
||||
|
||||
if (IsChildAgent)
|
||||
{
|
||||
@@ -2312,6 +2318,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
|
||||
public void AddNewMovement(Vector3 vec)
|
||||
{
|
||||
// m_log.DebugFormat("[SCENE PRESENCE]: Adding new movement {0} for {1}", vec, Name);
|
||||
|
||||
Vector3 direc = vec * Rotation;
|
||||
direc.Normalize();
|
||||
|
||||
@@ -3801,5 +3809,146 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
m_reprioritization_called = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckLandingPoint(ref Vector3 pos)
|
||||
{
|
||||
// Never constrain lures
|
||||
if ((TeleportFlags & TeleportFlags.ViaLure) != 0)
|
||||
return;
|
||||
|
||||
if (m_scene.RegionInfo.EstateSettings.AllowDirectTeleport)
|
||||
return;
|
||||
|
||||
ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y);
|
||||
|
||||
if (land.LandData.LandingType == (byte)LandingType.LandingPoint &&
|
||||
land.LandData.UserLocation != Vector3.Zero &&
|
||||
land.LandData.OwnerID != m_uuid &&
|
||||
(!m_scene.Permissions.IsGod(m_uuid)) &&
|
||||
(!m_scene.RegionInfo.EstateSettings.IsEstateManager(m_uuid)))
|
||||
{
|
||||
float curr = Vector3.Distance(AbsolutePosition, pos);
|
||||
if (Vector3.Distance(land.LandData.UserLocation, pos) < curr)
|
||||
pos = land.LandData.UserLocation;
|
||||
else
|
||||
ControllingClient.SendAlertMessage("Can't teleport closer to destination");
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckAndAdjustTelehub(SceneObjectGroup telehub, ref Vector3 pos)
|
||||
{
|
||||
if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) ==
|
||||
(TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) ||
|
||||
(m_teleportFlags & TeleportFlags.ViaLandmark) != 0 ||
|
||||
(m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
|
||||
(m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)
|
||||
{
|
||||
if (GodLevel < 200 &&
|
||||
((!m_scene.Permissions.IsGod(m_uuid) &&
|
||||
!m_scene.RegionInfo.EstateSettings.IsEstateManager(m_uuid)) ||
|
||||
(m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
|
||||
(m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0))
|
||||
{
|
||||
SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray();
|
||||
if (spawnPoints.Length == 0)
|
||||
return;
|
||||
|
||||
float distance = 9999;
|
||||
int closest = -1;
|
||||
|
||||
for (int i = 0 ; i < spawnPoints.Length ; i++)
|
||||
{
|
||||
Vector3 spawnPosition = spawnPoints[i].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
|
||||
Vector3 offset = spawnPosition - pos;
|
||||
float d = Vector3.Mag(offset);
|
||||
if (d >= distance)
|
||||
continue;
|
||||
ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y);
|
||||
if (land == null)
|
||||
continue;
|
||||
if (land.IsEitherBannedOrRestricted(UUID))
|
||||
continue;
|
||||
distance = d;
|
||||
closest = i;
|
||||
}
|
||||
if (closest == -1)
|
||||
return;
|
||||
|
||||
pos = spawnPoints[closest].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckAndAdjustLandingPoint(ref Vector3 pos)
|
||||
{
|
||||
SceneObjectGroup telehub = null;
|
||||
if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null)
|
||||
{
|
||||
if (!m_scene.RegionInfo.EstateSettings.AllowDirectTeleport)
|
||||
{
|
||||
CheckAndAdjustTelehub(telehub, ref pos);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y);
|
||||
if (land != null)
|
||||
{
|
||||
if (Scene.DEBUG)
|
||||
TeleportFlagsDebug();
|
||||
|
||||
// If we come in via login, landmark or map, we want to
|
||||
// honor landing points. If we come in via Lure, we want
|
||||
// to ignore them.
|
||||
if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) ==
|
||||
(TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) ||
|
||||
(m_teleportFlags & TeleportFlags.ViaLandmark) != 0 ||
|
||||
(m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
|
||||
(m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)
|
||||
{
|
||||
// Don't restrict gods, estate managers, or land owners to
|
||||
// the TP point. This behaviour mimics agni.
|
||||
if (land.LandData.LandingType == (byte)LandingType.LandingPoint &&
|
||||
land.LandData.UserLocation != Vector3.Zero &&
|
||||
GodLevel < 200 &&
|
||||
((land.LandData.OwnerID != m_uuid &&
|
||||
!m_scene.Permissions.IsGod(m_uuid) &&
|
||||
!m_scene.RegionInfo.EstateSettings.IsEstateManager(m_uuid)) ||
|
||||
(m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
|
||||
(m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0))
|
||||
{
|
||||
pos = land.LandData.UserLocation;
|
||||
}
|
||||
}
|
||||
|
||||
land.SendLandUpdateToClient(ControllingClient);
|
||||
}
|
||||
}
|
||||
|
||||
private void TeleportFlagsDebug() {
|
||||
|
||||
// Some temporary debugging help to show all the TeleportFlags we have...
|
||||
bool HG = false;
|
||||
if((m_teleportFlags & TeleportFlags.ViaHGLogin) == TeleportFlags.ViaHGLogin)
|
||||
HG = true;
|
||||
|
||||
m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************");
|
||||
|
||||
uint i = 0u;
|
||||
for (int x = 0; x <= 30 ; x++, i = 1u << x)
|
||||
{
|
||||
i = 1u << x;
|
||||
|
||||
if((m_teleportFlags & (TeleportFlags)i) == (TeleportFlags)i)
|
||||
if (HG == false)
|
||||
m_log.InfoFormat("[SCENE PRESENCE]: Teleport Flags include {0}", ((TeleportFlags) i).ToString());
|
||||
else
|
||||
m_log.InfoFormat("[SCENE PRESENCE]: HG Teleport Flags include {0}", ((TeleportFlags)i).ToString());
|
||||
}
|
||||
|
||||
m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
|
||||
/// Deserialize a scene object from the original xml format
|
||||
/// </summary>
|
||||
/// <param name="xmlData"></param>
|
||||
/// <returns></returns>
|
||||
/// <returns>The scene object deserialized. Null on failure.</returns>
|
||||
public static SceneObjectGroup FromOriginalXmlFormat(string xmlData)
|
||||
{
|
||||
//m_log.DebugFormat("[SOG]: Starting deserialization of SOG");
|
||||
@@ -1134,12 +1134,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
|
||||
|
||||
if (sop.CreatorData != null && sop.CreatorData != string.Empty)
|
||||
writer.WriteElementString("CreatorData", sop.CreatorData);
|
||||
else if (options.ContainsKey("profile"))
|
||||
else if (options.ContainsKey("home"))
|
||||
{
|
||||
if (m_UserManagement == null)
|
||||
m_UserManagement = sop.ParentGroup.Scene.RequestModuleInterface<IUserManagement>();
|
||||
string name = m_UserManagement.GetUserName(sop.CreatorID);
|
||||
writer.WriteElementString("CreatorData", (string)options["profile"] + "/" + sop.CreatorID + ";" + name);
|
||||
writer.WriteElementString("CreatorData", (string)options["home"] + ";" + name);
|
||||
}
|
||||
|
||||
WriteUUID(writer, "FolderID", sop.FolderID, options);
|
||||
@@ -1192,8 +1192,13 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
|
||||
writer.WriteElementString("ObjectSaleType", sop.ObjectSaleType.ToString());
|
||||
writer.WriteElementString("OwnershipCost", sop.OwnershipCost.ToString());
|
||||
WriteUUID(writer, "GroupID", sop.GroupID, options);
|
||||
WriteUUID(writer, "OwnerID", sop.OwnerID, options);
|
||||
WriteUUID(writer, "LastOwnerID", sop.LastOwnerID, options);
|
||||
|
||||
UUID ownerID = options.ContainsKey("wipe-owners") ? UUID.Zero : sop.OwnerID;
|
||||
WriteUUID(writer, "OwnerID", ownerID, options);
|
||||
|
||||
UUID lastOwnerID = options.ContainsKey("wipe-owners") ? UUID.Zero : sop.LastOwnerID;
|
||||
WriteUUID(writer, "LastOwnerID", lastOwnerID, options);
|
||||
|
||||
writer.WriteElementString("BaseMask", sop.BaseMask.ToString());
|
||||
writer.WriteElementString("OwnerMask", sop.OwnerMask.ToString());
|
||||
writer.WriteElementString("GroupMask", sop.GroupMask.ToString());
|
||||
@@ -1277,17 +1282,16 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
|
||||
writer.WriteElementString("BasePermissions", item.BasePermissions.ToString());
|
||||
writer.WriteElementString("CreationDate", item.CreationDate.ToString());
|
||||
|
||||
|
||||
WriteUUID(writer, "CreatorID", item.CreatorID, options);
|
||||
|
||||
if (item.CreatorData != null && item.CreatorData != string.Empty)
|
||||
writer.WriteElementString("CreatorData", item.CreatorData);
|
||||
else if (options.ContainsKey("profile"))
|
||||
else if (options.ContainsKey("home"))
|
||||
{
|
||||
if (m_UserManagement == null)
|
||||
m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
|
||||
string name = m_UserManagement.GetUserName(item.CreatorID);
|
||||
writer.WriteElementString("CreatorData", (string)options["profile"] + "/" + item.CreatorID + ";" + name);
|
||||
writer.WriteElementString("CreatorData", (string)options["home"] + ";" + name);
|
||||
}
|
||||
|
||||
writer.WriteElementString("Description", item.Description);
|
||||
@@ -1298,10 +1302,16 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
|
||||
writer.WriteElementString("InvType", item.InvType.ToString());
|
||||
WriteUUID(writer, "ItemID", item.ItemID, options);
|
||||
WriteUUID(writer, "OldItemID", item.OldItemID, options);
|
||||
WriteUUID(writer, "LastOwnerID", item.LastOwnerID, options);
|
||||
|
||||
UUID lastOwnerID = options.ContainsKey("wipe-owners") ? UUID.Zero : item.LastOwnerID;
|
||||
WriteUUID(writer, "LastOwnerID", lastOwnerID, options);
|
||||
|
||||
writer.WriteElementString("Name", item.Name);
|
||||
writer.WriteElementString("NextPermissions", item.NextPermissions.ToString());
|
||||
WriteUUID(writer, "OwnerID", item.OwnerID, options);
|
||||
|
||||
UUID ownerID = options.ContainsKey("wipe-owners") ? UUID.Zero : item.OwnerID;
|
||||
WriteUUID(writer, "OwnerID", ownerID, options);
|
||||
|
||||
writer.WriteElementString("CurrentPermissions", item.CurrentPermissions.ToString());
|
||||
WriteUUID(writer, "ParentID", item.ParentID, options);
|
||||
WriteUUID(writer, "ParentPartID", item.ParentPartID, options);
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 NUnit.Framework;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Communications;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Tests.Common;
|
||||
using OpenSim.Tests.Common.Mock;
|
||||
|
||||
namespace OpenSim.Region.Framework.Scenes.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SceneObjectScriptTests
|
||||
{
|
||||
[Test]
|
||||
public void TestAddScript()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
UUID userId = TestHelpers.ParseTail(0x1);
|
||||
UUID itemId = TestHelpers.ParseTail(0x2);
|
||||
string itemName = "Test Script Item";
|
||||
|
||||
Scene scene = SceneHelpers.SetupScene();
|
||||
SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId);
|
||||
scene.AddNewSceneObject(so, true);
|
||||
|
||||
InventoryItemBase itemTemplate = new InventoryItemBase();
|
||||
itemTemplate.Name = itemName;
|
||||
itemTemplate.Folder = so.UUID;
|
||||
itemTemplate.InvType = (int)InventoryType.LSL;
|
||||
|
||||
SceneObjectPart partWhereScriptAdded = scene.RezNewScript(userId, itemTemplate);
|
||||
|
||||
Assert.That(partWhereScriptAdded, Is.Not.Null);
|
||||
|
||||
IEntityInventory primInventory = partWhereScriptAdded.Inventory;
|
||||
Assert.That(primInventory.GetInventoryList().Count, Is.EqualTo(1));
|
||||
Assert.That(primInventory.ContainsScripts(), Is.True);
|
||||
|
||||
IList<TaskInventoryItem> primItems = primInventory.GetInventoryItems(itemName);
|
||||
Assert.That(primItems.Count, Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user