831 lines
24 KiB
C#
831 lines
24 KiB
C#
/*
|
|
* 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.Security;
|
|
using OpenMetaverse;
|
|
using OpenMetaverse.Packets;
|
|
using OpenSim.Framework;
|
|
using OpenSim.Region.Framework.Interfaces;
|
|
using OpenSim.Region.Framework.Scenes;
|
|
using OpenSim.Region.OptionalModules.Scripting.Minimodule.Object;
|
|
using OpenSim.Region.Physics.Manager;
|
|
using PrimType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.PrimType;
|
|
using SculptType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType;
|
|
|
|
namespace OpenSim.Region.OptionalModules.Scripting.Minimodule
|
|
{
|
|
class SOPObject : MarshalByRefObject, IObject, IObjectPhysics, IObjectShape, IObjectSound
|
|
{
|
|
private readonly Scene m_rootScene;
|
|
private readonly uint m_localID;
|
|
private readonly ISecurityCredential m_security;
|
|
|
|
[Obsolete("Replace with 'credential' constructor [security]")]
|
|
public SOPObject(Scene rootScene, uint localID)
|
|
{
|
|
m_rootScene = rootScene;
|
|
m_localID = localID;
|
|
}
|
|
|
|
public SOPObject(Scene rootScene, uint localID, ISecurityCredential credential)
|
|
{
|
|
m_rootScene = rootScene;
|
|
m_localID = localID;
|
|
m_security = credential;
|
|
}
|
|
|
|
/// <summary>
|
|
/// This needs to run very, very quickly.
|
|
/// It is utilized in nearly every property and method.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private SceneObjectPart GetSOP()
|
|
{
|
|
return m_rootScene.GetSceneObjectPart(m_localID);
|
|
}
|
|
|
|
private bool CanEdit()
|
|
{
|
|
if (!m_security.CanEditObject(this))
|
|
{
|
|
throw new SecurityException("Insufficient Permission to edit object with UUID [" + GetSOP().UUID + "]");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#region OnTouch
|
|
|
|
private event OnTouchDelegate _OnTouch;
|
|
private bool _OnTouchActive = false;
|
|
|
|
public event OnTouchDelegate OnTouch
|
|
{
|
|
add
|
|
{
|
|
if (CanEdit())
|
|
{
|
|
if (!_OnTouchActive)
|
|
{
|
|
GetSOP().Flags |= PrimFlags.Touch;
|
|
_OnTouchActive = true;
|
|
m_rootScene.EventManager.OnObjectGrab += EventManager_OnObjectGrab;
|
|
}
|
|
|
|
_OnTouch += value;
|
|
}
|
|
}
|
|
remove
|
|
{
|
|
_OnTouch -= value;
|
|
|
|
if (_OnTouch == null)
|
|
{
|
|
GetSOP().Flags &= ~PrimFlags.Touch;
|
|
_OnTouchActive = false;
|
|
m_rootScene.EventManager.OnObjectGrab -= EventManager_OnObjectGrab;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EventManager_OnObjectGrab(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs)
|
|
{
|
|
if (_OnTouchActive && m_localID == localID)
|
|
{
|
|
TouchEventArgs e = new TouchEventArgs();
|
|
e.Avatar = new SPAvatar(m_rootScene, remoteClient.AgentId, m_security);
|
|
e.TouchBiNormal = surfaceArgs.Binormal;
|
|
e.TouchMaterialIndex = surfaceArgs.FaceIndex;
|
|
e.TouchNormal = surfaceArgs.Normal;
|
|
e.TouchPosition = surfaceArgs.Position;
|
|
e.TouchST = new Vector2(surfaceArgs.STCoord.X, surfaceArgs.STCoord.Y);
|
|
e.TouchUV = new Vector2(surfaceArgs.UVCoord.X, surfaceArgs.UVCoord.Y);
|
|
|
|
IObject sender = this;
|
|
|
|
if (_OnTouch != null)
|
|
_OnTouch(sender, e);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public bool Exists
|
|
{
|
|
get { return GetSOP() != null; }
|
|
}
|
|
|
|
public uint LocalID
|
|
{
|
|
get { return m_localID; }
|
|
}
|
|
|
|
public UUID GlobalID
|
|
{
|
|
get { return GetSOP().UUID; }
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get { return GetSOP().Name; }
|
|
set
|
|
{
|
|
if (CanEdit())
|
|
GetSOP().Name = value;
|
|
}
|
|
}
|
|
|
|
public string Description
|
|
{
|
|
get { return GetSOP().Description; }
|
|
set
|
|
{
|
|
if (CanEdit())
|
|
GetSOP().Description = value;
|
|
}
|
|
}
|
|
|
|
public UUID OwnerId
|
|
{
|
|
get { return GetSOP().OwnerID;}
|
|
}
|
|
|
|
public UUID CreatorId
|
|
{
|
|
get { return GetSOP().CreatorID;}
|
|
}
|
|
|
|
public IObject[] Children
|
|
{
|
|
get
|
|
{
|
|
SceneObjectPart my = GetSOP();
|
|
IObject[] rets = null;
|
|
|
|
int total = my.ParentGroup.PrimCount;
|
|
|
|
rets = new IObject[total];
|
|
|
|
int i = 0;
|
|
|
|
foreach (SceneObjectPart part in my.ParentGroup.Parts)
|
|
{
|
|
rets[i++] = new SOPObject(m_rootScene, part.LocalId, m_security);
|
|
}
|
|
|
|
return rets;
|
|
}
|
|
}
|
|
|
|
public IObject Root
|
|
{
|
|
get { return new SOPObject(m_rootScene, GetSOP().ParentGroup.RootPart.LocalId, m_security); }
|
|
}
|
|
|
|
public IObjectMaterial[] Materials
|
|
{
|
|
get
|
|
{
|
|
SceneObjectPart sop = GetSOP();
|
|
IObjectMaterial[] rets = new IObjectMaterial[getNumberOfSides(sop)];
|
|
|
|
for (int i = 0; i < rets.Length; i++)
|
|
{
|
|
rets[i] = new SOPObjectMaterial(i, sop);
|
|
}
|
|
|
|
return rets;
|
|
}
|
|
}
|
|
|
|
public Vector3 Scale
|
|
{
|
|
get { return GetSOP().Scale; }
|
|
set
|
|
{
|
|
if (CanEdit())
|
|
GetSOP().Scale = value;
|
|
}
|
|
}
|
|
|
|
public Quaternion WorldRotation
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public Quaternion OffsetRotation
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public Vector3 WorldPosition
|
|
{
|
|
get { return GetSOP().AbsolutePosition; }
|
|
set
|
|
{
|
|
if (CanEdit())
|
|
{
|
|
SceneObjectPart pos = GetSOP();
|
|
pos.UpdateOffSet(value - pos.AbsolutePosition);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Vector3 OffsetPosition
|
|
{
|
|
get { return GetSOP().OffsetPosition; }
|
|
set
|
|
{
|
|
if (CanEdit())
|
|
{
|
|
GetSOP().OffsetPosition = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public Vector3 SitTarget
|
|
{
|
|
get { return GetSOP().SitTargetPosition; }
|
|
set
|
|
{
|
|
if (CanEdit())
|
|
{
|
|
GetSOP().SitTargetPosition = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public string SitTargetText
|
|
{
|
|
get { return GetSOP().SitName; }
|
|
set
|
|
{
|
|
if (CanEdit())
|
|
{
|
|
GetSOP().SitName = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public string TouchText
|
|
{
|
|
get { return GetSOP().TouchName; }
|
|
set
|
|
{
|
|
if (CanEdit())
|
|
{
|
|
GetSOP().TouchName = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public string Text
|
|
{
|
|
get { return GetSOP().Text; }
|
|
set
|
|
{
|
|
if (CanEdit())
|
|
{
|
|
GetSOP().SetText(value,new Vector3(1.0f,1.0f,1.0f),1.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsRotationLockedX
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public bool IsRotationLockedY
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public bool IsRotationLockedZ
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public bool IsSandboxed
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public bool IsImmotile
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public bool IsAlwaysReturned
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public bool IsTemporary
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public bool IsFlexible
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public PhysicsMaterial PhysicsMaterial
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public IObjectPhysics Physics
|
|
{
|
|
get { return this; }
|
|
}
|
|
|
|
public IObjectShape Shape
|
|
{
|
|
get { return this; }
|
|
}
|
|
|
|
public IObjectInventory Inventory
|
|
{
|
|
get { return new SOPObjectInventory(m_rootScene, GetSOP().TaskInventory); }
|
|
}
|
|
|
|
#region Public Functions
|
|
|
|
public void Say(string msg)
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
SceneObjectPart sop = GetSOP();
|
|
m_rootScene.SimChat(msg, ChatTypeEnum.Say, sop.AbsolutePosition, sop.Name, sop.UUID, false);
|
|
}
|
|
|
|
public void Say(string msg,int channel)
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
SceneObjectPart sop = GetSOP();
|
|
m_rootScene.SimChat(Utils.StringToBytes(msg), ChatTypeEnum.Say,channel, sop.AbsolutePosition, sop.Name, sop.UUID, false);
|
|
}
|
|
|
|
public void Dialog(UUID avatar, string message, string[] buttons, int chat_channel)
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
IDialogModule dm = m_rootScene.RequestModuleInterface<IDialogModule>();
|
|
|
|
if (dm == null)
|
|
return;
|
|
|
|
if (buttons.Length < 1)
|
|
{
|
|
Say("ERROR: No less than 1 button can be shown",2147483647);
|
|
return;
|
|
}
|
|
if (buttons.Length > 12)
|
|
{
|
|
Say("ERROR: No more than 12 buttons can be shown",2147483647);
|
|
return;
|
|
}
|
|
|
|
foreach (string button in buttons)
|
|
{
|
|
if (button == String.Empty)
|
|
{
|
|
Say("ERROR: button label cannot be blank",2147483647);
|
|
return;
|
|
}
|
|
if (button.Length > 24)
|
|
{
|
|
Say("ERROR: button label cannot be longer than 24 characters",2147483647);
|
|
return;
|
|
}
|
|
}
|
|
|
|
dm.SendDialogToUser(
|
|
avatar, GetSOP().Name, GetSOP().UUID, GetSOP().OwnerID,
|
|
message, new UUID("00000000-0000-2222-3333-100000001000"), chat_channel, buttons);
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region Supporting Functions
|
|
|
|
// Helper functions to understand if object has cut, hollow, dimple, and other affecting number of faces
|
|
private static void hasCutHollowDimpleProfileCut(int primType, PrimitiveBaseShape shape, out bool hasCut, out bool hasHollow,
|
|
out bool hasDimple, out bool hasProfileCut)
|
|
{
|
|
if (primType == (int)PrimType.Box
|
|
||
|
|
primType == (int)PrimType.Cylinder
|
|
||
|
|
primType == (int)PrimType.Prism)
|
|
|
|
hasCut = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0);
|
|
else
|
|
hasCut = (shape.PathBegin > 0) || (shape.PathEnd > 0);
|
|
|
|
hasHollow = shape.ProfileHollow > 0;
|
|
hasDimple = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0); // taken from llSetPrimitiveParms
|
|
hasProfileCut = hasDimple; // is it the same thing?
|
|
|
|
}
|
|
|
|
private static int getScriptPrimType(PrimitiveBaseShape primShape)
|
|
{
|
|
if (primShape.SculptEntry)
|
|
return (int) PrimType.Sculpt;
|
|
if ((primShape.ProfileCurve & 0x07) == (byte) ProfileShape.Square)
|
|
{
|
|
if (primShape.PathCurve == (byte) Extrusion.Straight)
|
|
return (int) PrimType.Box;
|
|
if (primShape.PathCurve == (byte) Extrusion.Curve1)
|
|
return (int) PrimType.Tube;
|
|
}
|
|
else if ((primShape.ProfileCurve & 0x07) == (byte) ProfileShape.Circle)
|
|
{
|
|
if (primShape.PathCurve == (byte) Extrusion.Straight)
|
|
return (int) PrimType.Cylinder;
|
|
if (primShape.PathCurve == (byte) Extrusion.Curve1)
|
|
return (int) PrimType.Torus;
|
|
}
|
|
else if ((primShape.ProfileCurve & 0x07) == (byte) ProfileShape.HalfCircle)
|
|
{
|
|
if (primShape.PathCurve == (byte) Extrusion.Curve1 || primShape.PathCurve == (byte) Extrusion.Curve2)
|
|
return (int) PrimType.Sphere;
|
|
}
|
|
else if ((primShape.ProfileCurve & 0x07) == (byte) ProfileShape.EquilateralTriangle)
|
|
{
|
|
if (primShape.PathCurve == (byte) Extrusion.Straight)
|
|
return (int) PrimType.Prism;
|
|
if (primShape.PathCurve == (byte) Extrusion.Curve1)
|
|
return (int) PrimType.Ring;
|
|
}
|
|
return (int) PrimType.NotPrimitive;
|
|
}
|
|
|
|
private static int getNumberOfSides(SceneObjectPart part)
|
|
{
|
|
int ret;
|
|
bool hasCut;
|
|
bool hasHollow;
|
|
bool hasDimple;
|
|
bool hasProfileCut;
|
|
|
|
int primType = getScriptPrimType(part.Shape);
|
|
hasCutHollowDimpleProfileCut(primType, part.Shape, out hasCut, out hasHollow, out hasDimple, out hasProfileCut);
|
|
|
|
switch (primType)
|
|
{
|
|
default:
|
|
case (int) PrimType.Box:
|
|
ret = 6;
|
|
if (hasCut) ret += 2;
|
|
if (hasHollow) ret += 1;
|
|
break;
|
|
case (int) PrimType.Cylinder:
|
|
ret = 3;
|
|
if (hasCut) ret += 2;
|
|
if (hasHollow) ret += 1;
|
|
break;
|
|
case (int) PrimType.Prism:
|
|
ret = 5;
|
|
if (hasCut) ret += 2;
|
|
if (hasHollow) ret += 1;
|
|
break;
|
|
case (int) PrimType.Sphere:
|
|
ret = 1;
|
|
if (hasCut) ret += 2;
|
|
if (hasDimple) ret += 2;
|
|
if (hasHollow)
|
|
ret += 1; // GOTCHA: LSL shows 2 additional sides here.
|
|
// This has been fixed, but may cause porting issues.
|
|
break;
|
|
case (int) PrimType.Torus:
|
|
ret = 1;
|
|
if (hasCut) ret += 2;
|
|
if (hasProfileCut) ret += 2;
|
|
if (hasHollow) ret += 1;
|
|
break;
|
|
case (int) PrimType.Tube:
|
|
ret = 4;
|
|
if (hasCut) ret += 2;
|
|
if (hasProfileCut) ret += 2;
|
|
if (hasHollow) ret += 1;
|
|
break;
|
|
case (int) PrimType.Ring:
|
|
ret = 3;
|
|
if (hasCut) ret += 2;
|
|
if (hasProfileCut) ret += 2;
|
|
if (hasHollow) ret += 1;
|
|
break;
|
|
case (int) PrimType.Sculpt:
|
|
ret = 1;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region IObjectPhysics
|
|
|
|
public bool Enabled
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public bool Phantom
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public bool PhantomCollisions
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public double Density
|
|
{
|
|
get { return (GetSOP().PhysActor.Mass/Scale.X*Scale.Y/Scale.Z); }
|
|
set { throw new NotImplementedException(); }
|
|
}
|
|
|
|
public double Mass
|
|
{
|
|
get { return GetSOP().PhysActor.Mass; }
|
|
set { throw new NotImplementedException(); }
|
|
}
|
|
|
|
public double Buoyancy
|
|
{
|
|
get { return GetSOP().PhysActor.Buoyancy; }
|
|
set { GetSOP().PhysActor.Buoyancy = (float)value; }
|
|
}
|
|
|
|
public Vector3 GeometricCenter
|
|
{
|
|
get
|
|
{
|
|
Vector3 tmp = GetSOP().PhysActor.GeometricCenter;
|
|
return tmp;
|
|
}
|
|
}
|
|
|
|
public Vector3 CenterOfMass
|
|
{
|
|
get
|
|
{
|
|
Vector3 tmp = GetSOP().PhysActor.CenterOfMass;
|
|
return tmp;
|
|
}
|
|
}
|
|
|
|
public Vector3 RotationalVelocity
|
|
{
|
|
get
|
|
{
|
|
Vector3 tmp = GetSOP().PhysActor.RotationalVelocity;
|
|
return tmp;
|
|
}
|
|
set
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
GetSOP().PhysActor.RotationalVelocity = value;
|
|
}
|
|
}
|
|
|
|
public Vector3 Velocity
|
|
{
|
|
get
|
|
{
|
|
Vector3 tmp = GetSOP().PhysActor.Velocity;
|
|
return tmp;
|
|
}
|
|
set
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
GetSOP().PhysActor.Velocity = value;
|
|
}
|
|
}
|
|
|
|
public Vector3 Torque
|
|
{
|
|
get
|
|
{
|
|
Vector3 tmp = GetSOP().PhysActor.Torque;
|
|
return tmp;
|
|
}
|
|
set
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
GetSOP().PhysActor.Torque = value;
|
|
}
|
|
}
|
|
|
|
public Vector3 Acceleration
|
|
{
|
|
get
|
|
{
|
|
Vector3 tmp = GetSOP().PhysActor.Acceleration;
|
|
return tmp;
|
|
}
|
|
}
|
|
|
|
public Vector3 Force
|
|
{
|
|
get
|
|
{
|
|
Vector3 tmp = GetSOP().PhysActor.Force;
|
|
return tmp;
|
|
}
|
|
set
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
GetSOP().PhysActor.Force = value;
|
|
}
|
|
}
|
|
|
|
public bool FloatOnWater
|
|
{
|
|
set
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
GetSOP().PhysActor.FloatOnWater = value;
|
|
}
|
|
}
|
|
|
|
public void AddForce(Vector3 force, bool pushforce)
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
GetSOP().PhysActor.AddForce(force, pushforce);
|
|
}
|
|
|
|
public void AddAngularForce(Vector3 force, bool pushforce)
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
GetSOP().PhysActor.AddAngularForce(force, pushforce);
|
|
}
|
|
|
|
public void SetMomentum(Vector3 momentum)
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
GetSOP().PhysActor.SetMomentum(momentum);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Implementation of IObjectShape
|
|
|
|
private UUID m_sculptMap = UUID.Zero;
|
|
|
|
public UUID SculptMap
|
|
{
|
|
get { return m_sculptMap; }
|
|
set
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
m_sculptMap = value;
|
|
SetPrimitiveSculpted(SculptMap, (byte) SculptType);
|
|
}
|
|
}
|
|
|
|
private SculptType m_sculptType = Object.SculptType.Default;
|
|
|
|
public SculptType SculptType
|
|
{
|
|
get { return m_sculptType; }
|
|
set
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
m_sculptType = value;
|
|
SetPrimitiveSculpted(SculptMap, (byte) SculptType);
|
|
}
|
|
}
|
|
|
|
public HoleShape HoleType
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public double HoleSize
|
|
{
|
|
get { throw new System.NotImplementedException(); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
public PrimType PrimType
|
|
{
|
|
get { return (PrimType)getScriptPrimType(GetSOP().Shape); }
|
|
set { throw new System.NotImplementedException(); }
|
|
}
|
|
|
|
private void SetPrimitiveSculpted(UUID map, byte type)
|
|
{
|
|
ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
|
|
|
|
SceneObjectPart part = GetSOP();
|
|
|
|
UUID sculptId = map;
|
|
|
|
shapeBlock.ObjectLocalID = part.LocalId;
|
|
shapeBlock.PathScaleX = 100;
|
|
shapeBlock.PathScaleY = 150;
|
|
|
|
// retain pathcurve
|
|
shapeBlock.PathCurve = part.Shape.PathCurve;
|
|
|
|
part.Shape.SetSculptProperties((byte)type, sculptId);
|
|
part.Shape.SculptEntry = true;
|
|
part.UpdateShape(shapeBlock);
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region Implementation of IObjectSound
|
|
|
|
public IObjectSound Sound
|
|
{
|
|
get { return this; }
|
|
}
|
|
|
|
public void Play(UUID asset, double volume)
|
|
{
|
|
if (!CanEdit())
|
|
return;
|
|
|
|
GetSOP().SendSound(asset.ToString(), volume, true, 0, 0, false, false);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|