aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes
diff options
context:
space:
mode:
authorDr Scofield2009-02-06 16:55:34 +0000
committerDr Scofield2009-02-06 16:55:34 +0000
commit9b66108081a8c8cf79faaa6c541554091c40850e (patch)
tree095a232ae5a9de3a9244bcd34da08294f61eeea5 /OpenSim/Region/Framework/Scenes
parent* removed superfluous constants class (diff)
downloadopensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.zip
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.gz
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.bz2
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.xz
This changeset is the step 1 of 2 in refactoring
OpenSim.Region.Environment into a "framework" part and a modules only part. This first changeset refactors OpenSim.Region.Environment.Scenes, OpenSim.Region.Environment.Interfaces, and OpenSim.Region.Interfaces into OpenSim.Region.Framework.{Interfaces,Scenes} leaving only region modules in OpenSim.Region.Environment. The next step will be to move region modules up from OpenSim.Region.Environment.Modules to OpenSim.Region.CoreModules and then sort out which modules are really core modules and which should move out to forge. I've been very careful to NOT BREAK anything. i hope i've succeeded. as this is the work of a whole week i hope i managed to keep track with the applied patches of the last week --- could any of you that did check in stuff have a look at whether it survived? thx!
Diffstat (limited to 'OpenSim/Region/Framework/Scenes')
-rw-r--r--OpenSim/Region/Framework/Scenes/Animation.cs59
-rw-r--r--OpenSim/Region/Framework/Scenes/AnimationSet.cs155
-rw-r--r--OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs165
-rw-r--r--OpenSim/Region/Framework/Scenes/AvatarAnimations.cs63
-rw-r--r--OpenSim/Region/Framework/Scenes/EntityBase.cs253
-rw-r--r--OpenSim/Region/Framework/Scenes/EntityManager.cs279
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs981
-rw-r--r--OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs376
-rw-r--r--OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs152
-rw-r--r--OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.cs84
-rw-r--r--OpenSim/Region/Framework/Scenes/Hypergrid/HGSceneCommunicationService.cs360
-rw-r--r--OpenSim/Region/Framework/Scenes/IScenePresenceBody.cs37
-rw-r--r--OpenSim/Region/Framework/Scenes/ReturnInfo.cs39
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs2665
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs632
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Permissions.cs1334
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs4239
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneBase.cs419
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs1095
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneGraph.cs1814
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneManager.cs669
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs401
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs3012
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs3826
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs891
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs3649
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneXmlLoader.cs289
-rw-r--r--OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs46
-rw-r--r--OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs86
-rw-r--r--OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs38
-rw-r--r--OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs119
-rw-r--r--OpenSim/Region/Framework/Scenes/SimStatsReporter.cs450
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainChannel.cs242
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainUtil.cs132
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs176
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs139
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs249
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs292
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs105
-rw-r--r--OpenSim/Region/Framework/Scenes/Types/BasicQuadTreeNode.cs269
-rw-r--r--OpenSim/Region/Framework/Scenes/Types/UpdateQueue.cs134
-rw-r--r--OpenSim/Region/Framework/Scenes/UndoState.cs116
42 files changed, 30531 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Animation.cs b/OpenSim/Region/Framework/Scenes/Animation.cs
new file mode 100644
index 0000000..3504717
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Animation.cs
@@ -0,0 +1,59 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenMetaverse;
30
31namespace OpenSim.Region.Framework.Scenes
32{
33 public class Animation
34 {
35 private UUID animID;
36 public UUID AnimID
37 {
38 get { return animID; }
39 set { animID = value; }
40 }
41
42 private int sequenceNum;
43 public int SequenceNum
44 {
45 get { return sequenceNum; }
46 set { sequenceNum = value; }
47 }
48
49 public Animation()
50 {
51 }
52
53 public Animation(UUID animID, int sequenceNum)
54 {
55 this.animID = animID;
56 this.sequenceNum = sequenceNum;
57 }
58 }
59}
diff --git a/OpenSim/Region/Framework/Scenes/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/AnimationSet.cs
new file mode 100644
index 0000000..f53bb78
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/AnimationSet.cs
@@ -0,0 +1,155 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31
32namespace OpenSim.Region.Framework.Scenes
33{
34 public class AnimationSet
35 {
36 public static AvatarAnimations Animations = new AvatarAnimations();
37
38 private Animation m_defaultAnimation = new Animation();
39 private List<Animation> m_animations = new List<Animation>();
40
41 public Animation DefaultAnimation
42 {
43 get { return m_defaultAnimation; }
44 }
45 public AnimationSet()
46 {
47 ResetDefaultAnimation();
48 }
49
50 public bool HasAnimation(UUID animID)
51 {
52 if (m_defaultAnimation.AnimID == animID)
53 return true;
54
55 for (int i = 0; i < m_animations.Count; ++i)
56 {
57 if (m_animations[i].AnimID == animID)
58 return true;
59 }
60
61 return false;
62 }
63
64 public bool Add(UUID animID, int sequenceNum)
65 {
66 lock (m_animations)
67 {
68 if (!HasAnimation(animID))
69 {
70 m_animations.Add(new Animation(animID, sequenceNum));
71 return true;
72 }
73 }
74 return false;
75 }
76
77 public bool Remove(UUID animID)
78 {
79 lock (m_animations)
80 {
81 if (m_defaultAnimation.AnimID == animID)
82 {
83 ResetDefaultAnimation();
84 }
85 else if (HasAnimation(animID))
86 {
87 for (int i = 0; i < m_animations.Count; i++)
88 {
89 if (m_animations[i].AnimID == animID)
90 {
91 m_animations.RemoveAt(i);
92 return true;
93 }
94 }
95 }
96 }
97 return false;
98 }
99
100 public void Clear()
101 {
102 ResetDefaultAnimation();
103 m_animations.Clear();
104 }
105
106 /// <summary>
107 /// The default animation is reserved for "main" animations
108 /// that are mutually exclusive, e.g. flying and sitting.
109 /// </summary>
110 public bool SetDefaultAnimation(UUID animID, int sequenceNum)
111 {
112 if (m_defaultAnimation.AnimID != animID)
113 {
114 m_defaultAnimation = new Animation(animID, sequenceNum);
115 return true;
116 }
117 return false;
118 }
119
120 protected bool ResetDefaultAnimation()
121 {
122 return TrySetDefaultAnimation("STAND", 1);
123 }
124
125 /// <summary>
126 /// Set the animation as the default animation if it's known
127 /// </summary>
128 public bool TrySetDefaultAnimation(string anim, int sequenceNum)
129 {
130 if (Animations.AnimsUUID.ContainsKey(anim))
131 {
132 return SetDefaultAnimation(Animations.AnimsUUID[anim], sequenceNum);
133 }
134 return false;
135 }
136
137 public void GetArrays(out UUID[] animIDs, out int[] sequenceNums)
138 {
139 lock (m_animations)
140 {
141 animIDs = new UUID[m_animations.Count + 1];
142 sequenceNums = new int[m_animations.Count + 1];
143
144 animIDs[0] = m_defaultAnimation.AnimID;
145 sequenceNums[0] = m_defaultAnimation.SequenceNum;
146
147 for (int i = 0; i < m_animations.Count; ++i)
148 {
149 animIDs[i + 1] = m_animations[i].AnimID;
150 sequenceNums[i + 1] = m_animations[i].SequenceNum;
151 }
152 }
153 }
154 }
155}
diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
new file mode 100644
index 0000000..178f1f7
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs
@@ -0,0 +1,165 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Timers;
32using log4net;
33using OpenMetaverse;
34using OpenMetaverse.Packets;
35using OpenSim.Framework;
36
37namespace OpenSim.Region.Framework.Scenes
38{
39 class DeleteToInventoryHolder
40 {
41 public DeRezAction action;
42 public IClientAPI remoteClient;
43 public SceneObjectGroup objectGroup;
44 public UUID folderID;
45 public bool permissionToDelete;
46 }
47
48 /// <summary>
49 /// Asynchronously derez objects. This is used to derez large number of objects to inventory without holding
50 /// up the main client thread.
51 /// </summary>
52 public class AsyncSceneObjectGroupDeleter
53 {
54 private static readonly ILog m_log
55 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 /// <value>
58 /// Is the deleter currently enabled?
59 /// </value>
60 public bool Enabled;
61
62 private Timer m_inventoryTicker = new Timer(2000);
63 private readonly Queue<DeleteToInventoryHolder> m_inventoryDeletes = new Queue<DeleteToInventoryHolder>();
64 private Scene m_scene;
65
66 public AsyncSceneObjectGroupDeleter(Scene scene)
67 {
68 m_scene = scene;
69
70 m_inventoryTicker.AutoReset = false;
71 m_inventoryTicker.Elapsed += InventoryRunDeleteTimer;
72 }
73
74 /// <summary>
75 /// Delete the given object from the scene
76 /// </summary>
77 public void DeleteToInventory(DeRezAction action, UUID folderID,
78 SceneObjectGroup objectGroup, IClientAPI remoteClient,
79 bool permissionToDelete)
80 {
81 if (Enabled)
82 m_inventoryTicker.Stop();
83
84 lock (m_inventoryDeletes)
85 {
86 DeleteToInventoryHolder dtis = new DeleteToInventoryHolder();
87 dtis.action = action;
88 dtis.folderID = folderID;
89 dtis.objectGroup = objectGroup;
90 dtis.remoteClient = remoteClient;
91 dtis.permissionToDelete = permissionToDelete;
92
93 m_inventoryDeletes.Enqueue(dtis);
94 }
95
96 if (Enabled)
97 m_inventoryTicker.Start();
98
99 // Visually remove it, even if it isnt really gone yet. This means that if we crash before the object
100 // has gone to inventory, it will reappear in the region again on restart instead of being lost.
101 // This is not ideal since the object will still be available for manipulation when it should be, but it's
102 // better than losing the object for now.
103 if (permissionToDelete)
104 objectGroup.DeleteGroup(false);
105 }
106
107 private void InventoryRunDeleteTimer(object sender, ElapsedEventArgs e)
108 {
109 m_log.Debug("[SCENE]: Starting send to inventory loop");
110
111 while (InventoryDeQueueAndDelete())
112 {
113 m_log.Debug("[SCENE]: Sent item successfully to inventory, continuing...");
114 }
115 }
116
117 /// <summary>
118 /// Move the next object in the queue to inventory. Then delete it properly from the scene.
119 /// </summary>
120 /// <returns></returns>
121 public bool InventoryDeQueueAndDelete()
122 {
123 DeleteToInventoryHolder x = null;
124
125 try
126 {
127 lock (m_inventoryDeletes)
128 {
129 int left = m_inventoryDeletes.Count;
130 if (left > 0)
131 {
132 m_log.DebugFormat(
133 "[SCENE]: Sending object to user's inventory, {0} item(s) remaining.", left);
134
135 x = m_inventoryDeletes.Dequeue();
136
137 try
138 {
139 m_scene.DeleteToInventory(x.action, x.folderID, x.objectGroup, x.remoteClient);
140 if (x.permissionToDelete)
141 m_scene.DeleteSceneObject(x.objectGroup, false);
142 }
143 catch (Exception e)
144 {
145 m_log.DebugFormat("Exception background sending object: " + e);
146 }
147
148 return true;
149 }
150 }
151 }
152 catch (Exception e)
153 {
154 // We can't put the object group details in here since the root part may have disappeared (which is where these sit).
155 // FIXME: This needs to be fixed.
156 m_log.ErrorFormat(
157 "[SCENE]: Queued sending of scene object to agent {0} {1} failed: {2}",
158 (x != null ? x.remoteClient.Name : "unavailable"), (x != null ? x.remoteClient.AgentId.ToString() : "unavailable"), e.ToString());
159 }
160
161 m_log.Debug("[SCENE]: No objects left in inventory send queue.");
162 return false;
163 }
164 }
165}
diff --git a/OpenSim/Region/Framework/Scenes/AvatarAnimations.cs b/OpenSim/Region/Framework/Scenes/AvatarAnimations.cs
new file mode 100644
index 0000000..562fcf9
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/AvatarAnimations.cs
@@ -0,0 +1,63 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29using System.Xml;
30using OpenMetaverse;
31
32namespace OpenSim.Region.Framework.Scenes
33{
34 public class AvatarAnimations
35 {
36 public Dictionary<string, UUID> AnimsUUID = new Dictionary<string, UUID>();
37 public Dictionary<UUID, string> AnimsNames = new Dictionary<UUID, string>();
38 public Dictionary<UUID, string> AnimStateNames = new Dictionary<UUID, string>();
39
40 public AvatarAnimations()
41 {
42 using (XmlTextReader reader = new XmlTextReader("data/avataranimations.xml"))
43 {
44 XmlDocument doc = new XmlDocument();
45 doc.Load(reader);
46 foreach (XmlNode nod in doc.DocumentElement.ChildNodes)
47 {
48 if (nod.Attributes["name"] != null)
49 {
50 string name = (string)nod.Attributes["name"].Value;
51 UUID id = (UUID)nod.InnerText;
52 string animState = (string)nod.Attributes["state"].Value;
53
54 AnimsUUID.Add(name, id);
55 AnimsNames.Add(id, name);
56 if (animState != "")
57 AnimStateNames.Add(id, animState);
58 }
59 }
60 }
61 }
62 }
63}
diff --git a/OpenSim/Region/Framework/Scenes/EntityBase.cs b/OpenSim/Region/Framework/Scenes/EntityBase.cs
new file mode 100644
index 0000000..5055e44
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/EntityBase.cs
@@ -0,0 +1,253 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Runtime.Serialization;
30using System.Security.Permissions;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Framework.Scenes
34{
35 [Serializable]
36 public abstract class EntityBase : ISerializable
37 {
38 /// <summary>
39 /// The scene to which this entity belongs
40 /// </summary>
41 public Scene Scene
42 {
43 get { return m_scene; }
44 }
45 protected Scene m_scene;
46
47 protected UUID m_uuid;
48
49 public virtual UUID UUID
50 {
51 get { return m_uuid; }
52 set { m_uuid = value; }
53 }
54
55 protected string m_name;
56
57 /// <summary>
58 /// The name of this entity
59 /// </summary>
60 public virtual string Name
61 {
62 get { return m_name; }
63 set { m_name = value; }
64 }
65
66 /// <summary>
67 /// Signals whether this entity was in a scene but has since been removed from it.
68 /// </summary>
69 public bool IsDeleted
70 {
71 get { return m_isDeleted; }
72 }
73 protected bool m_isDeleted;
74
75 protected Vector3 m_pos;
76
77 /// <summary>
78 ///
79 /// </summary>
80 public virtual Vector3 AbsolutePosition
81 {
82 get { return m_pos; }
83 set { m_pos = value; }
84 }
85
86 protected Vector3 m_velocity;
87 protected Vector3 m_rotationalvelocity;
88
89 /// <summary>
90 /// Current velocity of the entity.
91 /// </summary>
92 public virtual Vector3 Velocity
93 {
94 get { return m_velocity; }
95 set { m_velocity = value; }
96 }
97
98 protected Quaternion m_rotation = new Quaternion(0f, 0f, 1f, 0f);
99
100 public virtual Quaternion Rotation
101 {
102 get { return m_rotation; }
103 set { m_rotation = value; }
104 }
105
106 protected uint m_localId;
107
108 public virtual uint LocalId
109 {
110 get { return m_localId; }
111 set { m_localId = value; }
112 }
113
114 /// <summary>
115 /// Creates a new Entity (should not occur on it's own)
116 /// </summary>
117 public EntityBase()
118 {
119 m_uuid = UUID.Zero;
120
121 m_pos = Vector3.Zero;
122 m_velocity = Vector3.Zero;
123 Rotation = Quaternion.Identity;
124 m_name = "(basic entity)";
125 m_rotationalvelocity = Vector3.Zero;
126 }
127
128 /// <summary>
129 ///
130 /// </summary>
131 public abstract void UpdateMovement();
132
133 /// <summary>
134 /// Performs any updates that need to be done at each frame, as opposed to immediately.
135 /// These included scheduled updates and updates that occur due to physics processing.
136 /// </summary>
137 public abstract void Update();
138
139 /// <summary>
140 /// Copies the entity
141 /// </summary>
142 /// <returns></returns>
143 public virtual EntityBase Copy()
144 {
145 return (EntityBase) MemberwiseClone();
146 }
147
148
149 public abstract void SetText(string text, Vector3 color, double alpha);
150
151 protected EntityBase(SerializationInfo info, StreamingContext context)
152 {
153 //System.Console.WriteLine("EntityBase Deserialize BGN");
154
155 if (info == null)
156 {
157 throw new ArgumentNullException("info");
158 }
159
160 m_uuid = new UUID((Guid)info.GetValue("m_uuid", typeof(Guid)));
161 m_name = (string)info.GetValue("m_name", typeof(string));
162
163 m_pos
164 = new Vector3(
165 (float)info.GetValue("m_pos.X", typeof(float)),
166 (float)info.GetValue("m_pos.Y", typeof(float)),
167 (float)info.GetValue("m_pos.Z", typeof(float)));
168
169 m_velocity
170 = new Vector3(
171 (float)info.GetValue("m_velocity.X", typeof(float)),
172 (float)info.GetValue("m_velocity.Y", typeof(float)),
173 (float)info.GetValue("m_velocity.Z", typeof(float)));
174
175 m_rotationalvelocity
176 = new Vector3(
177 (float)info.GetValue("m_rotationalvelocity.X", typeof(float)),
178 (float)info.GetValue("m_rotationalvelocity.Y", typeof(float)),
179 (float)info.GetValue("m_rotationalvelocity.Z", typeof(float)));
180
181 m_rotation
182 = new Quaternion(
183 (float)info.GetValue("m_rotation.X", typeof(float)),
184 (float)info.GetValue("m_rotation.Y", typeof(float)),
185 (float)info.GetValue("m_rotation.Z", typeof(float)),
186 (float)info.GetValue("m_rotation.W", typeof(float)));
187
188 m_localId = (uint)info.GetValue("m_localId", typeof(uint));
189
190 //System.Console.WriteLine("EntityBase Deserialize END");
191 }
192
193 [SecurityPermission(SecurityAction.LinkDemand,
194 Flags = SecurityPermissionFlag.SerializationFormatter)]
195 public virtual void GetObjectData(
196 SerializationInfo info, StreamingContext context)
197 {
198 if (info == null)
199 {
200 throw new ArgumentNullException("info");
201 }
202
203 info.AddValue("m_uuid", m_uuid.Guid);
204 info.AddValue("m_name", m_name);
205
206 // Vector3
207 info.AddValue("m_pos.X", m_pos.X);
208 info.AddValue("m_pos.Y", m_pos.Y);
209 info.AddValue("m_pos.Z", m_pos.Z);
210
211 // Vector3
212 info.AddValue("m_velocity.X", m_velocity.X);
213 info.AddValue("m_velocity.Y", m_velocity.Y);
214 info.AddValue("m_velocity.Z", m_velocity.Z);
215
216 // Vector3
217 info.AddValue("m_rotationalvelocity.X", m_rotationalvelocity.X);
218 info.AddValue("m_rotationalvelocity.Y", m_rotationalvelocity.Y);
219 info.AddValue("m_rotationalvelocity.Z", m_rotationalvelocity.Z);
220
221 // Quaternion
222 info.AddValue("m_rotation.X", m_rotation.X);
223 info.AddValue("m_rotation.Y", m_rotation.Y);
224 info.AddValue("m_rotation.Z", m_rotation.Z);
225 info.AddValue("m_rotation.W", m_rotation.W);
226
227 info.AddValue("m_localId", m_localId);
228 }
229 }
230
231 //Nested Classes
232 public class EntityIntersection
233 {
234 public Vector3 ipoint = new Vector3(0, 0, 0);
235 public Vector3 normal = new Vector3(0, 0, 0);
236 public Vector3 AAfaceNormal = new Vector3(0, 0, 0);
237 public int face = -1;
238 public bool HitTF = false;
239 public SceneObjectPart obj;
240 public float distance = 0;
241
242 public EntityIntersection()
243 {
244 }
245
246 public EntityIntersection(Vector3 _ipoint, Vector3 _normal, bool _HitTF)
247 {
248 ipoint = _ipoint;
249 normal = _normal;
250 HitTF = _HitTF;
251 }
252 }
253}
diff --git a/OpenSim/Region/Framework/Scenes/EntityManager.cs b/OpenSim/Region/Framework/Scenes/EntityManager.cs
new file mode 100644
index 0000000..a322766
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/EntityManager.cs
@@ -0,0 +1,279 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.Reflection;
32using log4net;
33using OpenMetaverse;
34
35
36namespace OpenSim.Region.Framework.Scenes
37{
38 public class EntityManager : IEnumerable<EntityBase>
39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41 private readonly Dictionary<UUID,EntityBase> m_eb_uuid = new Dictionary<UUID, EntityBase>();
42 private readonly Dictionary<uint, EntityBase> m_eb_localID = new Dictionary<uint, EntityBase>();
43 //private readonly Dictionary<UUID, ScenePresence> m_pres_uuid = new Dictionary<UUID, ScenePresence>();
44 private readonly Object m_lock = new Object();
45
46 [Obsolete("Use Add() instead.")]
47 public void Add(UUID id, EntityBase eb)
48 {
49 Add(eb);
50 }
51
52 public void Add(EntityBase entity)
53 {
54 lock (m_lock)
55 {
56 try
57 {
58 m_eb_uuid.Add(entity.UUID, entity);
59 m_eb_localID.Add(entity.LocalId, entity);
60 }
61 catch(Exception e)
62 {
63 m_log.ErrorFormat("Add Entity failed: {0}", e.Message);
64 }
65 }
66 }
67
68 public void InsertOrReplace(EntityBase entity)
69 {
70 lock (m_lock)
71 {
72 try
73 {
74 m_eb_uuid[entity.UUID] = entity;
75 m_eb_localID[entity.LocalId] = entity;
76 }
77 catch(Exception e)
78 {
79 m_log.ErrorFormat("Insert or Replace Entity failed: {0}", e.Message);
80 }
81 }
82 }
83
84 public void Clear()
85 {
86 lock (m_lock)
87 {
88 m_eb_uuid.Clear();
89 m_eb_localID.Clear();
90 }
91 }
92
93 public int Count
94 {
95 get
96 {
97 lock (m_lock)
98 {
99 return m_eb_uuid.Count;
100 }
101 }
102 }
103
104 public bool ContainsKey(UUID id)
105 {
106 lock (m_lock)
107 {
108 try
109 {
110 return m_eb_uuid.ContainsKey(id);
111 }
112 catch
113 {
114 return false;
115 }
116 }
117 }
118
119 public bool ContainsKey(uint localID)
120 {
121 lock (m_lock)
122 {
123 try
124 {
125 return m_eb_localID.ContainsKey(localID);
126 }
127 catch
128 {
129 return false;
130 }
131 }
132 }
133
134 public bool Remove(uint localID)
135 {
136 lock (m_lock)
137 {
138 try
139 {
140 bool a = m_eb_uuid.Remove(m_eb_localID[localID].UUID);
141 bool b = m_eb_localID.Remove(localID);
142 return a && b;
143 }
144 catch (Exception e)
145 {
146 m_log.ErrorFormat("Remove Entity failed for {0}", localID, e);
147 return false;
148 }
149 }
150 }
151
152 public bool Remove(UUID id)
153 {
154 lock (m_lock)
155 {
156 try
157 {
158 bool a = m_eb_localID.Remove(m_eb_uuid[id].LocalId);
159 bool b = m_eb_uuid.Remove(id);
160 return a && b;
161 }
162 catch (Exception e)
163 {
164 m_log.ErrorFormat("Remove Entity failed for {0}", id, e);
165 return false;
166 }
167 }
168 }
169
170 public List<EntityBase> GetAllByType<T>()
171 {
172 List<EntityBase> tmp = new List<EntityBase>();
173
174 lock (m_lock)
175 {
176 try
177 {
178 foreach (KeyValuePair<UUID, EntityBase> pair in m_eb_uuid)
179 {
180 if (pair.Value is T)
181 {
182 tmp.Add(pair.Value);
183 }
184 }
185 }
186 catch (Exception e)
187 {
188 m_log.ErrorFormat("GetAllByType failed for {0}", e);
189 tmp = null;
190 }
191 }
192
193 return tmp;
194 }
195
196 public List<EntityBase> GetEntities()
197 {
198 lock (m_lock)
199 {
200 return new List<EntityBase>(m_eb_uuid.Values);
201 }
202 }
203
204 public EntityBase this[UUID id]
205 {
206 get
207 {
208 lock (m_lock)
209 {
210 try
211 {
212 return m_eb_uuid[id];
213 }
214 catch
215 {
216 return null;
217 }
218 }
219 }
220 set
221 {
222 InsertOrReplace(value);
223 }
224 }
225
226 public EntityBase this[uint localID]
227 {
228 get
229 {
230 lock (m_lock)
231 {
232 try
233 {
234 return m_eb_localID[localID];
235 }
236 catch
237 {
238 return null;
239 }
240 }
241 }
242 set
243 {
244 InsertOrReplace(value);
245 }
246 }
247
248 public bool TryGetValue(UUID key, out EntityBase obj)
249 {
250 lock (m_lock)
251 {
252 return m_eb_uuid.TryGetValue(key, out obj);
253 }
254 }
255
256 public bool TryGetValue(uint key, out EntityBase obj)
257 {
258 lock (m_lock)
259 {
260 return m_eb_localID.TryGetValue(key, out obj);
261 }
262 }
263
264 /// <summary>
265 /// This could be optimised to work on the list 'live' rather than making a safe copy and iterating that.
266 /// </summary>
267 /// <returns></returns>
268 public IEnumerator<EntityBase> GetEnumerator()
269 {
270 return GetEntities().GetEnumerator();
271 }
272
273 IEnumerator IEnumerable.GetEnumerator()
274 {
275 return GetEnumerator();
276 }
277
278 }
279}
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
new file mode 100644
index 0000000..23e1278
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -0,0 +1,981 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenMetaverse;
30using OpenSim.Framework;
31using OpenSim.Framework.Client;
32using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes;
34using Caps = OpenSim.Framework.Communications.Capabilities.Caps;
35using System.Collections.Generic;
36
37namespace OpenSim.Region.Framework.Scenes
38{
39 /// <summary>
40 /// A class for triggering remote scene events.
41 /// </summary>
42 public class EventManager
43 {
44 public delegate void OnFrameDelegate();
45
46 public event OnFrameDelegate OnFrame;
47
48 public delegate void ClientMovement(ScenePresence client);
49
50 public event ClientMovement OnClientMovement;
51
52 public delegate void OnTerrainTickDelegate();
53
54 public event OnTerrainTickDelegate OnTerrainTick;
55
56 public delegate void OnBackupDelegate(IRegionDataStore datastore, bool forceBackup);
57
58 public event OnBackupDelegate OnBackup;
59
60 public delegate void OnClientConnectCoreDelegate(IClientCore client);
61
62 public event OnClientConnectCoreDelegate OnClientConnect;
63
64 public delegate void OnNewClientDelegate(IClientAPI client);
65
66 /// <summary>
67 /// Depreciated in favour of OnClientConnect.
68 /// Will be marked Obsolete after IClientCore has 100% of IClientAPI interfaces.
69 /// </summary>
70 public event OnNewClientDelegate OnNewClient;
71
72 public delegate void OnNewPresenceDelegate(ScenePresence presence);
73
74 public event OnNewPresenceDelegate OnNewPresence;
75
76 public delegate void OnRemovePresenceDelegate(UUID agentId);
77
78 public event OnRemovePresenceDelegate OnRemovePresence;
79
80 public delegate void OnParcelPrimCountUpdateDelegate();
81
82 public event OnParcelPrimCountUpdateDelegate OnParcelPrimCountUpdate;
83
84 public delegate void OnParcelPrimCountAddDelegate(SceneObjectGroup obj);
85
86 public event OnParcelPrimCountAddDelegate OnParcelPrimCountAdd;
87
88 public delegate void OnPluginConsoleDelegate(string[] args);
89
90 public event OnPluginConsoleDelegate OnPluginConsole;
91
92 public delegate void OnShutdownDelegate();
93
94 public event OnShutdownDelegate OnShutdown;
95
96 public delegate void ObjectGrabDelegate(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs);
97 public delegate void ObjectDeGrabDelegate(uint localID, uint originalID, IClientAPI remoteClient);
98 public delegate void ScriptResetDelegate(uint localID, UUID itemID);
99
100 public delegate void OnPermissionErrorDelegate(UUID user, string reason);
101
102 public delegate void OnSetRootAgentSceneDelegate(UUID agentID, Scene scene);
103
104 public event OnSetRootAgentSceneDelegate OnSetRootAgentScene;
105
106 public event ObjectGrabDelegate OnObjectGrab;
107 public event ObjectDeGrabDelegate OnObjectDeGrab;
108 public event ScriptResetDelegate OnScriptReset;
109
110 public event OnPermissionErrorDelegate OnPermissionError;
111
112 public delegate void NewRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource);
113
114 public event NewRezScript OnRezScript;
115
116 public delegate void RemoveScript(uint localID, UUID itemID);
117
118 public event RemoveScript OnRemoveScript;
119
120 public delegate void StartScript(uint localID, UUID itemID);
121
122 public event StartScript OnStartScript;
123
124 public delegate void StopScript(uint localID, UUID itemID);
125
126 public event StopScript OnStopScript;
127
128 public delegate bool SceneGroupMoved(UUID groupID, Vector3 delta);
129
130 public event SceneGroupMoved OnSceneGroupMove;
131
132 public delegate void SceneGroupGrabed(UUID groupID, Vector3 offset, UUID userID);
133
134 public event SceneGroupGrabed OnSceneGroupGrab;
135
136 public delegate void LandObjectAdded(ILandObject newParcel);
137
138 public event LandObjectAdded OnLandObjectAdded;
139
140 public delegate void LandObjectRemoved(UUID globalID);
141
142 public event LandObjectRemoved OnLandObjectRemoved;
143
144 public delegate void AvatarEnteringNewParcel(ScenePresence avatar, int localLandID, UUID regionID);
145
146 public event AvatarEnteringNewParcel OnAvatarEnteringNewParcel;
147
148 public delegate void SignificantClientMovement(IClientAPI remote_client);
149
150 public event SignificantClientMovement OnSignificantClientMovement;
151
152 public delegate void IncomingInstantMessage(GridInstantMessage message);
153
154 public event IncomingInstantMessage OnIncomingInstantMessage;
155
156 public event IncomingInstantMessage OnUnhandledInstantMessage;
157
158 public delegate void ClientClosed(UUID clientID);
159
160 public event ClientClosed OnClientClosed;
161
162 public delegate void ScriptChangedEvent(uint localID, uint change);
163
164 public event ScriptChangedEvent OnScriptChangedEvent;
165
166 public delegate void ScriptControlEvent(uint localID, UUID item, UUID avatarID, uint held, uint changed);
167
168 public event ScriptControlEvent OnScriptControlEvent;
169
170 public delegate void ScriptAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 atpos);
171
172 public event ScriptAtTargetEvent OnScriptAtTargetEvent;
173
174 public delegate void ScriptNotAtTargetEvent(uint localID);
175
176 public event ScriptNotAtTargetEvent OnScriptNotAtTargetEvent;
177
178 public delegate void ScriptColliding(uint localID, ColliderArgs colliders);
179
180 public event ScriptColliding OnScriptColliderStart;
181 public event ScriptColliding OnScriptColliding;
182 public event ScriptColliding OnScriptCollidingEnd;
183
184 public delegate void OnMakeChildAgentDelegate(ScenePresence presence);
185 public event OnMakeChildAgentDelegate OnMakeChildAgent;
186
187 public delegate void OnMakeRootAgentDelegate(ScenePresence presence);
188 public event OnMakeRootAgentDelegate OnMakeRootAgent;
189
190 public delegate void NewInventoryItemUploadComplete(UUID avatarID, UUID assetID, string name, int userlevel);
191
192 public event NewInventoryItemUploadComplete OnNewInventoryItemUploadComplete;
193
194 public delegate void RequestChangeWaterHeight(float height);
195
196 public event RequestChangeWaterHeight OnRequestChangeWaterHeight;
197
198 public delegate void AvatarKillData(uint KillerLocalID, ScenePresence avatar);
199
200 public event AvatarKillData OnAvatarKilled;
201
202 public delegate void ScriptTimerEvent(uint localID, double timerinterval);
203
204 public event ScriptTimerEvent OnScriptTimerEvent;
205
206 public delegate void EstateToolsTimeUpdate(ulong regionHandle, bool FixedTime, bool EstateSun, float LindenHour);
207 public delegate void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID);
208
209 public event EstateToolsTimeUpdate OnEstateToolsTimeUpdate;
210
211 public delegate void ObjectBeingRemovedFromScene(SceneObjectGroup obj);
212 public event ObjectBeingRemovedFromScene OnObjectBeingRemovedFromScene;
213
214 public delegate void NoticeNoLandDataFromStorage();
215 public event NoticeNoLandDataFromStorage OnNoticeNoLandDataFromStorage;
216
217 public delegate void IncomingLandDataFromStorage(List<LandData> data);
218 public event IncomingLandDataFromStorage OnIncomingLandDataFromStorage;
219
220 public delegate void SetAllowForcefulBan(bool allow);
221 public event SetAllowForcefulBan OnSetAllowForcefulBan;
222
223 public delegate void RequestParcelPrimCountUpdate();
224 public event RequestParcelPrimCountUpdate OnRequestParcelPrimCountUpdate;
225
226 public delegate void ParcelPrimCountTainted();
227 public event ParcelPrimCountTainted OnParcelPrimCountTainted;
228 public event GetScriptRunning OnGetScriptRunning;
229
230 /// <summary>
231 /// RegisterCapsEvent is called by Scene after the Caps object
232 /// has been instantiated and before it is return to the
233 /// client and provides region modules to add their caps.
234 /// </summary>
235 public delegate void RegisterCapsEvent(UUID agentID, Caps caps);
236 public event RegisterCapsEvent OnRegisterCaps;
237
238 /// <summary>
239 /// DeregisterCapsEvent is called by Scene when the caps
240 /// handler for an agent are removed.
241 /// </summary>
242 public delegate void DeregisterCapsEvent(UUID agentID, Caps caps);
243 public event DeregisterCapsEvent OnDeregisterCaps;
244
245 /// <summary>
246 /// ChatFromWorldEvent is called via Scene when a chat message
247 /// from world comes in.
248 /// </summary>
249 public delegate void ChatFromWorldEvent(Object sender, OSChatMessage chat);
250 public event ChatFromWorldEvent OnChatFromWorld;
251
252 /// <summary>
253 /// ChatFromClientEvent is triggered via ChatModule (or
254 /// substitutes thereof) when a chat message
255 /// from the client comes in.
256 /// </summary>
257 public delegate void ChatFromClientEvent(Object sender, OSChatMessage chat);
258 public event ChatFromClientEvent OnChatFromClient;
259
260 /// <summary>
261 /// ChatBroadcastEvent is called via Scene when a broadcast chat message
262 /// from world comes in
263 /// </summary>
264 public delegate void ChatBroadcastEvent(Object sender, OSChatMessage chat);
265 public event ChatBroadcastEvent OnChatBroadcast;
266
267 public delegate float SunLindenHour();
268 public event SunLindenHour OnGetSunLindenHour;
269
270 /// <summary>
271 /// Called when oar file has finished loading, although
272 /// the scripts may not have started yet
273 /// Message is non empty string if there were problems loading the oar file
274 /// </summary>
275 public delegate void OarFileLoaded(string message);
276 public event OarFileLoaded OnOarFileLoaded;
277
278 /// <summary>
279 /// Called when an oar file has finished saving
280 /// Message is non empty string if there were problems saving the oar file
281 /// </summary>
282 public delegate void OarFileSaved(string message);
283 public event OarFileSaved OnOarFileSaved;
284
285 /// <summary>
286 /// Called when the script compile queue becomes empty
287 /// Returns the number of scripts which failed to start
288 /// </summary>
289 public delegate void EmptyScriptCompileQueue(int numScriptsFailed, string message);
290 public event EmptyScriptCompileQueue OnEmptyScriptCompileQueue;
291
292 public class MoneyTransferArgs : EventArgs
293 {
294 public UUID sender;
295 public UUID receiver;
296
297 // Always false. The SL protocol sucks.
298 public bool authenticated = false;
299
300 public int amount;
301 public int transactiontype;
302 public string description;
303
304 public MoneyTransferArgs(UUID asender, UUID areceiver, int aamount, int atransactiontype, string adescription)
305 {
306 sender = asender;
307 receiver = areceiver;
308 amount = aamount;
309 transactiontype = atransactiontype;
310 description = adescription;
311 }
312 }
313
314 public class LandBuyArgs : EventArgs
315 {
316 public UUID agentId = UUID.Zero;
317
318 public UUID groupId = UUID.Zero;
319
320 public UUID parcelOwnerID = UUID.Zero;
321
322 public bool final = false;
323 public bool groupOwned = false;
324 public bool removeContribution = false;
325 public int parcelLocalID = 0;
326 public int parcelArea = 0;
327 public int parcelPrice = 0;
328 public bool authenticated = false;
329 public bool landValidated = false;
330 public bool economyValidated = false;
331 public int transactionID = 0;
332 public int amountDebited = 0;
333
334 public LandBuyArgs(UUID pagentId, UUID pgroupId, bool pfinal, bool pgroupOwned,
335 bool premoveContribution, int pparcelLocalID, int pparcelArea, int pparcelPrice,
336 bool pauthenticated)
337 {
338 agentId = pagentId;
339 groupId = pgroupId;
340 final = pfinal;
341 groupOwned = pgroupOwned;
342 removeContribution = premoveContribution;
343 parcelLocalID = pparcelLocalID;
344 parcelArea = pparcelArea;
345 parcelPrice = pparcelPrice;
346 authenticated = pauthenticated;
347 }
348 }
349
350 public delegate void MoneyTransferEvent(Object sender, MoneyTransferArgs e);
351
352 public delegate void LandBuy(Object sender, LandBuyArgs e);
353
354 public event MoneyTransferEvent OnMoneyTransfer;
355 public event LandBuy OnLandBuy;
356 public event LandBuy OnValidateLandBuy;
357
358 /* Designated Event Deletage Instances */
359
360 private ScriptChangedEvent handlerScriptChangedEvent = null; //OnScriptChangedEvent;
361 private ScriptAtTargetEvent handlerScriptAtTargetEvent = null;
362 private ScriptNotAtTargetEvent handlerScriptNotAtTargetEvent = null;
363 private ClientMovement handlerClientMovement = null; //OnClientMovement;
364 private OnPermissionErrorDelegate handlerPermissionError = null; //OnPermissionError;
365 private OnPluginConsoleDelegate handlerPluginConsole = null; //OnPluginConsole;
366 private OnFrameDelegate handlerFrame = null; //OnFrame;
367 private OnNewClientDelegate handlerNewClient = null; //OnNewClient;
368 private OnClientConnectCoreDelegate handlerClientConnect = null; //OnClientConnect
369 private OnNewPresenceDelegate handlerNewPresence = null; //OnNewPresence;
370 private OnRemovePresenceDelegate handlerRemovePresence = null; //OnRemovePresence;
371 private OnBackupDelegate handlerBackup = null; //OnBackup;
372 private OnParcelPrimCountUpdateDelegate handlerParcelPrimCountUpdate = null; //OnParcelPrimCountUpdate;
373 private MoneyTransferEvent handlerMoneyTransfer = null; //OnMoneyTransfer;
374 private OnParcelPrimCountAddDelegate handlerParcelPrimCountAdd = null; //OnParcelPrimCountAdd;
375 private OnShutdownDelegate handlerShutdown = null; //OnShutdown;
376 private ObjectGrabDelegate handlerObjectGrab = null; //OnObjectGrab;
377 private ObjectDeGrabDelegate handlerObjectDeGrab = null; //OnObjectDeGrab;
378 private ScriptResetDelegate handlerScriptReset = null; // OnScriptReset
379 private NewRezScript handlerRezScript = null; //OnRezScript;
380 private RemoveScript handlerRemoveScript = null; //OnRemoveScript;
381 private StartScript handlerStartScript = null; //OnStartScript;
382 private StopScript handlerStopScript = null; //OnStopScript;
383 private SceneGroupMoved handlerSceneGroupMove = null; //OnSceneGroupMove;
384 private SceneGroupGrabed handlerSceneGroupGrab = null; //OnSceneGroupGrab;
385 private LandObjectAdded handlerLandObjectAdded = null; //OnLandObjectAdded;
386 private LandObjectRemoved handlerLandObjectRemoved = null; //OnLandObjectRemoved;
387 private AvatarEnteringNewParcel handlerAvatarEnteringNewParcel = null; //OnAvatarEnteringNewParcel;
388 private IncomingInstantMessage handlerIncomingInstantMessage = null; //OnIncomingInstantMessage;
389 private IncomingInstantMessage handlerUnhandledInstantMessage = null; //OnUnhandledInstantMessage;
390 private ClientClosed handlerClientClosed = null; //OnClientClosed;
391 private OnMakeChildAgentDelegate handlerMakeChildAgent = null; //OnMakeChildAgent;
392 private OnMakeRootAgentDelegate handlerMakeRootAgent = null; //OnMakeRootAgent;
393 private OnTerrainTickDelegate handlerTerrainTick = null; // OnTerainTick;
394 private RegisterCapsEvent handlerRegisterCaps = null; // OnRegisterCaps;
395 private DeregisterCapsEvent handlerDeregisterCaps = null; // OnDeregisterCaps;
396 private ChatFromWorldEvent handlerChatFromWorld = null; // OnChatFromWorld;
397 private ChatFromClientEvent handlerChatFromClient = null; // OnChatFromClient;
398 private ChatBroadcastEvent handlerChatBroadcast = null; // OnChatBroadcast;
399 private NewInventoryItemUploadComplete handlerNewInventoryItemUpdateComplete = null;
400 private RequestChangeWaterHeight handlerRequestChangeWaterHeight = null; //OnRequestChangeWaterHeight
401 private ScriptControlEvent handlerScriptControlEvent = null;
402 private SignificantClientMovement handlerSignificantClientMovement = null;
403
404 private LandBuy handlerLandBuy = null;
405 private LandBuy handlerValidateLandBuy = null;
406 private AvatarKillData handlerAvatarKill = null;
407
408 private NoticeNoLandDataFromStorage handlerNoticeNoLandDataFromStorage = null;
409 private IncomingLandDataFromStorage handlerIncomingLandDataFromStorage = null;
410 private SetAllowForcefulBan handlerSetAllowForcefulBan = null;
411 private RequestParcelPrimCountUpdate handlerRequestParcelPrimCountUpdate = null;
412 private ParcelPrimCountTainted handlerParcelPrimCountTainted = null;
413 private ObjectBeingRemovedFromScene handlerObjectBeingRemovedFromScene = null;
414 private ScriptTimerEvent handlerScriptTimerEvent = null;
415 private EstateToolsTimeUpdate handlerEstateToolsTimeUpdate = null;
416
417 private ScriptColliding handlerCollidingStart = null;
418 private ScriptColliding handlerColliding = null;
419 private ScriptColliding handlerCollidingEnd = null;
420 private GetScriptRunning handlerGetScriptRunning = null;
421
422 private SunLindenHour handlerSunGetLindenHour = null;
423 private OnSetRootAgentSceneDelegate handlerSetRootAgentScene = null;
424
425 private OarFileLoaded handlerOarFileLoaded = null;
426 private OarFileSaved handlerOarFileSaved = null;
427
428 private EmptyScriptCompileQueue handlerEmptyScriptCompileQueue = null;
429
430 public void TriggerGetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID)
431 {
432 handlerGetScriptRunning = OnGetScriptRunning;
433 if (handlerGetScriptRunning != null)
434 handlerGetScriptRunning(controllingClient, objectID, itemID);
435 }
436
437 public void TriggerOnScriptChangedEvent(uint localID, uint change)
438 {
439 handlerScriptChangedEvent = OnScriptChangedEvent;
440 if (handlerScriptChangedEvent != null)
441 handlerScriptChangedEvent(localID, change);
442 }
443
444 public void TriggerOnClientMovement(ScenePresence avatar)
445 {
446 handlerClientMovement = OnClientMovement;
447 if (handlerClientMovement != null)
448 handlerClientMovement(avatar);
449 }
450
451 public void TriggerPermissionError(UUID user, string reason)
452 {
453 handlerPermissionError = OnPermissionError;
454 if (handlerPermissionError != null)
455 handlerPermissionError(user, reason);
456 }
457
458 public void TriggerOnPluginConsole(string[] args)
459 {
460 handlerPluginConsole = OnPluginConsole;
461 if (handlerPluginConsole != null)
462 handlerPluginConsole(args);
463 }
464
465 public void TriggerOnFrame()
466 {
467 handlerFrame = OnFrame;
468 if (handlerFrame != null)
469 {
470 handlerFrame();
471 }
472 }
473
474 public void TriggerOnNewClient(IClientAPI client)
475 {
476 handlerNewClient = OnNewClient;
477 if (handlerNewClient != null)
478 handlerNewClient(client);
479
480 if (client is IClientCore)
481 {
482 handlerClientConnect = OnClientConnect;
483 handlerClientConnect((IClientCore) client);
484 }
485 }
486
487 public void TriggerOnNewPresence(ScenePresence presence)
488 {
489 handlerNewPresence = OnNewPresence;
490 if (handlerNewPresence != null)
491 handlerNewPresence(presence);
492 }
493
494 public void TriggerOnRemovePresence(UUID agentId)
495 {
496 handlerRemovePresence = OnRemovePresence;
497 if (handlerRemovePresence != null)
498 {
499 handlerRemovePresence(agentId);
500 }
501 }
502
503 public void TriggerOnBackup(IRegionDataStore dstore)
504 {
505 handlerBackup = OnBackup;
506 if (handlerBackup != null)
507 {
508 handlerBackup(dstore, false);
509 }
510 }
511
512 public void TriggerParcelPrimCountUpdate()
513 {
514 handlerParcelPrimCountUpdate = OnParcelPrimCountUpdate;
515 if (handlerParcelPrimCountUpdate != null)
516 {
517 handlerParcelPrimCountUpdate();
518 }
519 }
520
521 public void TriggerMoneyTransfer(Object sender, MoneyTransferArgs e)
522 {
523 handlerMoneyTransfer = OnMoneyTransfer;
524 if (handlerMoneyTransfer != null)
525 {
526 handlerMoneyTransfer(sender, e);
527 }
528 }
529
530 public void TriggerTerrainTick()
531 {
532 handlerTerrainTick = OnTerrainTick;
533 if (handlerTerrainTick != null)
534 {
535 handlerTerrainTick();
536 }
537 }
538
539 public void TriggerParcelPrimCountAdd(SceneObjectGroup obj)
540 {
541 handlerParcelPrimCountAdd = OnParcelPrimCountAdd;
542 if (handlerParcelPrimCountAdd != null)
543 {
544 handlerParcelPrimCountAdd(obj);
545 }
546 }
547
548 public void TriggerObjectBeingRemovedFromScene(SceneObjectGroup obj)
549 {
550 handlerObjectBeingRemovedFromScene = OnObjectBeingRemovedFromScene;
551 if (handlerObjectBeingRemovedFromScene != null)
552 {
553 handlerObjectBeingRemovedFromScene(obj);
554 }
555 }
556
557 public void TriggerShutdown()
558 {
559 handlerShutdown = OnShutdown;
560 if (handlerShutdown != null)
561 handlerShutdown();
562 }
563
564 public void TriggerObjectGrab(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs)
565 {
566 handlerObjectGrab = OnObjectGrab;
567 if (handlerObjectGrab != null)
568 {
569 handlerObjectGrab(localID, originalID, offsetPos, remoteClient, surfaceArgs);
570 }
571 }
572
573 public void TriggerObjectDeGrab(uint localID, uint originalID, IClientAPI remoteClient)
574 {
575 handlerObjectDeGrab = OnObjectDeGrab;
576 if (handlerObjectDeGrab != null)
577 {
578 handlerObjectDeGrab(localID, originalID, remoteClient);
579 }
580 }
581
582 public void TriggerScriptReset(uint localID, UUID itemID)
583 {
584 handlerScriptReset = OnScriptReset;
585 if (handlerScriptReset != null)
586 {
587 handlerScriptReset(localID, itemID);
588 }
589 }
590
591 public void TriggerRezScript(uint localID, UUID itemID, string script, int startParam, bool postOnRez, string engine, int stateSource)
592 {
593 handlerRezScript = OnRezScript;
594 if (handlerRezScript != null)
595 {
596 handlerRezScript(localID, itemID, script, startParam,
597 postOnRez, engine, stateSource);
598 }
599 }
600
601 public void TriggerStartScript(uint localID, UUID itemID)
602 {
603 handlerStartScript = OnStartScript;
604 if (handlerStartScript != null)
605 {
606 handlerStartScript(localID, itemID);
607 }
608 }
609
610 public void TriggerStopScript(uint localID, UUID itemID)
611 {
612 handlerStopScript = OnStopScript;
613 if (handlerStopScript != null)
614 {
615 handlerStopScript(localID, itemID);
616 }
617 }
618
619 public void TriggerRemoveScript(uint localID, UUID itemID)
620 {
621 handlerRemoveScript = OnRemoveScript;
622 if (handlerRemoveScript != null)
623 {
624 handlerRemoveScript(localID, itemID);
625 }
626 }
627
628 public bool TriggerGroupMove(UUID groupID, Vector3 delta)
629 {
630 handlerSceneGroupMove = OnSceneGroupMove;
631
632 if (handlerSceneGroupMove != null)
633 {
634 return handlerSceneGroupMove(groupID, delta);
635 }
636 return true;
637 }
638
639 public void TriggerGroupGrab(UUID groupID, Vector3 offset, UUID userID)
640 {
641 handlerSceneGroupGrab = OnSceneGroupGrab;
642 if (handlerSceneGroupGrab != null)
643 {
644 handlerSceneGroupGrab(groupID, offset, userID);
645 }
646 }
647
648 public void TriggerLandObjectAdded(ILandObject newParcel)
649 {
650 handlerLandObjectAdded = OnLandObjectAdded;
651
652 if (handlerLandObjectAdded != null)
653 {
654 handlerLandObjectAdded(newParcel);
655 }
656 }
657
658 public void TriggerLandObjectRemoved(UUID globalID)
659 {
660 handlerLandObjectRemoved = OnLandObjectRemoved;
661 if (handlerLandObjectRemoved != null)
662 {
663 handlerLandObjectRemoved(globalID);
664 }
665 }
666
667 public void TriggerLandObjectUpdated(uint localParcelID, ILandObject newParcel)
668 {
669 //triggerLandObjectRemoved(localParcelID);
670
671 TriggerLandObjectAdded(newParcel);
672 }
673
674 public void TriggerAvatarEnteringNewParcel(ScenePresence avatar, int localLandID, UUID regionID)
675 {
676 handlerAvatarEnteringNewParcel = OnAvatarEnteringNewParcel;
677
678 if (handlerAvatarEnteringNewParcel != null)
679 {
680 handlerAvatarEnteringNewParcel(avatar, localLandID, regionID);
681 }
682 }
683
684 public void TriggerIncomingInstantMessage(GridInstantMessage message)
685 {
686 handlerIncomingInstantMessage = OnIncomingInstantMessage;
687 if (handlerIncomingInstantMessage != null)
688 {
689 handlerIncomingInstantMessage(message);
690 }
691 }
692
693 public void TriggerUnhandledInstantMessage(GridInstantMessage message)
694 {
695 handlerUnhandledInstantMessage = OnUnhandledInstantMessage;
696 if (handlerUnhandledInstantMessage != null)
697 {
698 handlerUnhandledInstantMessage(message);
699 }
700 }
701
702 public void TriggerClientClosed(UUID ClientID)
703 {
704 handlerClientClosed = OnClientClosed;
705 if (handlerClientClosed != null)
706 {
707 handlerClientClosed(ClientID);
708 }
709 }
710
711 public void TriggerOnMakeChildAgent(ScenePresence presence)
712 {
713 handlerMakeChildAgent = OnMakeChildAgent;
714 if (handlerMakeChildAgent != null)
715 {
716 handlerMakeChildAgent(presence);
717 }
718 }
719
720 public void TriggerOnMakeRootAgent(ScenePresence presence)
721 {
722 handlerMakeRootAgent = OnMakeRootAgent;
723 if (handlerMakeRootAgent != null)
724 {
725 handlerMakeRootAgent(presence);
726 }
727 }
728
729 public void TriggerOnRegisterCaps(UUID agentID, Caps caps)
730 {
731 handlerRegisterCaps = OnRegisterCaps;
732 if (handlerRegisterCaps != null)
733 {
734 handlerRegisterCaps(agentID, caps);
735 }
736 }
737
738 public void TriggerOnDeregisterCaps(UUID agentID, Caps caps)
739 {
740 handlerDeregisterCaps = OnDeregisterCaps;
741 if (handlerDeregisterCaps != null)
742 {
743 handlerDeregisterCaps(agentID, caps);
744 }
745 }
746
747 public void TriggerOnNewInventoryItemUploadComplete(UUID agentID, UUID AssetID, String AssetName, int userlevel)
748 {
749 handlerNewInventoryItemUpdateComplete = OnNewInventoryItemUploadComplete;
750 if (handlerNewInventoryItemUpdateComplete != null)
751 {
752 handlerNewInventoryItemUpdateComplete(agentID, AssetID, AssetName, userlevel);
753 }
754 }
755
756 public void TriggerLandBuy(Object sender, LandBuyArgs e)
757 {
758 handlerLandBuy = OnLandBuy;
759 if (handlerLandBuy != null)
760 {
761 handlerLandBuy(sender, e);
762 }
763 }
764
765 public void TriggerValidateLandBuy(Object sender, LandBuyArgs e)
766 {
767 handlerValidateLandBuy = OnValidateLandBuy;
768 if (handlerValidateLandBuy != null)
769 {
770 handlerValidateLandBuy(sender, e);
771 }
772 }
773
774 public void TriggerAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 currentpos)
775 {
776 handlerScriptAtTargetEvent = OnScriptAtTargetEvent;
777 if (handlerScriptAtTargetEvent != null)
778 {
779 handlerScriptAtTargetEvent(localID, handle, targetpos, currentpos);
780 }
781 }
782
783 public void TriggerNotAtTargetEvent(uint localID)
784 {
785 handlerScriptNotAtTargetEvent = OnScriptNotAtTargetEvent;
786 if (handlerScriptNotAtTargetEvent != null)
787 {
788 handlerScriptNotAtTargetEvent(localID);
789 }
790 }
791
792 public void TriggerRequestChangeWaterHeight(float height)
793 {
794 handlerRequestChangeWaterHeight = OnRequestChangeWaterHeight;
795 if (handlerRequestChangeWaterHeight != null)
796 {
797 handlerRequestChangeWaterHeight(height);
798 }
799 }
800
801 public void TriggerAvatarKill(uint KillerObjectLocalID, ScenePresence DeadAvatar)
802 {
803 handlerAvatarKill = OnAvatarKilled;
804 if (handlerAvatarKill != null)
805 {
806 handlerAvatarKill(KillerObjectLocalID, DeadAvatar);
807 }
808 }
809
810 public void TriggerSignificantClientMovement(IClientAPI client)
811 {
812 handlerSignificantClientMovement = OnSignificantClientMovement;
813 if (handlerSignificantClientMovement != null)
814 {
815 handlerSignificantClientMovement(client);
816 }
817 }
818
819 public void TriggerOnChatFromWorld(Object sender, OSChatMessage chat)
820 {
821 handlerChatFromWorld = OnChatFromWorld;
822 if (handlerChatFromWorld != null)
823 {
824 handlerChatFromWorld(sender, chat);
825 }
826 }
827
828 public void TriggerOnChatFromClient(Object sender, OSChatMessage chat)
829 {
830 handlerChatFromClient = OnChatFromClient;
831 if (handlerChatFromClient != null)
832 {
833 handlerChatFromClient(sender, chat);
834 }
835 }
836
837 public void TriggerOnChatBroadcast(Object sender, OSChatMessage chat)
838 {
839 handlerChatBroadcast = OnChatBroadcast;
840 if (handlerChatBroadcast != null)
841 {
842 handlerChatBroadcast(sender, chat);
843 }
844 }
845
846 internal void TriggerControlEvent(uint p, UUID scriptUUID, UUID avatarID, uint held, uint _changed)
847 {
848 handlerScriptControlEvent = OnScriptControlEvent;
849 if (handlerScriptControlEvent != null)
850 {
851 handlerScriptControlEvent(p, scriptUUID, avatarID, held, _changed);
852 }
853 }
854
855 public void TriggerNoticeNoLandDataFromStorage()
856 {
857 handlerNoticeNoLandDataFromStorage = OnNoticeNoLandDataFromStorage;
858 if (handlerNoticeNoLandDataFromStorage != null)
859 {
860 handlerNoticeNoLandDataFromStorage();
861
862 }
863 }
864
865 public void TriggerIncomingLandDataFromStorage(List<LandData> landData)
866 {
867 handlerIncomingLandDataFromStorage = OnIncomingLandDataFromStorage;
868 if (handlerIncomingLandDataFromStorage != null)
869 {
870 handlerIncomingLandDataFromStorage(landData);
871
872 }
873 }
874
875 public void TriggerSetAllowForcefulBan(bool allow)
876 {
877 handlerSetAllowForcefulBan = OnSetAllowForcefulBan;
878 if (handlerSetAllowForcefulBan != null)
879 {
880 handlerSetAllowForcefulBan(allow);
881
882 }
883 }
884
885 public void TriggerRequestParcelPrimCountUpdate()
886 {
887 handlerRequestParcelPrimCountUpdate = OnRequestParcelPrimCountUpdate;
888 if (handlerRequestParcelPrimCountUpdate != null)
889 {
890 handlerRequestParcelPrimCountUpdate();
891 }
892 }
893
894 public void TriggerParcelPrimCountTainted()
895 {
896 handlerParcelPrimCountTainted = OnParcelPrimCountTainted;
897 if (handlerParcelPrimCountTainted != null)
898 {
899 handlerParcelPrimCountTainted();
900 }
901 }
902
903 // this lets us keep track of nasty script events like timer, etc.
904 public void TriggerTimerEvent(uint objLocalID, double Interval)
905 {
906 handlerScriptTimerEvent = OnScriptTimerEvent;
907 if (handlerScriptTimerEvent != null)
908 {
909 handlerScriptTimerEvent(objLocalID, Interval);
910 }
911 }
912
913 public void TriggerEstateToolsTimeUpdate(ulong regionHandle, bool FixedTime, bool useEstateTime, float LindenHour)
914 {
915 handlerEstateToolsTimeUpdate = OnEstateToolsTimeUpdate;
916 if (handlerEstateToolsTimeUpdate != null)
917 {
918 handlerEstateToolsTimeUpdate(regionHandle, FixedTime, useEstateTime, LindenHour);
919 }
920 }
921
922 public float GetSunLindenHour()
923 {
924 handlerSunGetLindenHour = OnGetSunLindenHour;
925 if (handlerSunGetLindenHour != null)
926 {
927 return handlerSunGetLindenHour();
928 }
929 return 6;
930 }
931
932 public void TriggerOarFileLoaded(string message)
933 {
934 handlerOarFileLoaded = OnOarFileLoaded;
935 if (handlerOarFileLoaded != null)
936 handlerOarFileLoaded(message);
937 }
938
939 public void TriggerOarFileSaved(string message)
940 {
941 handlerOarFileSaved = OnOarFileSaved;
942 if (handlerOarFileSaved != null)
943 handlerOarFileSaved(message);
944 }
945
946 public void TriggerEmptyScriptCompileQueue(int numScriptsFailed, string message)
947 {
948 handlerEmptyScriptCompileQueue = OnEmptyScriptCompileQueue;
949 if (handlerEmptyScriptCompileQueue != null)
950 handlerEmptyScriptCompileQueue(numScriptsFailed, message);
951 }
952
953 public void TriggerScriptCollidingStart(uint localId, ColliderArgs colliders)
954 {
955 handlerCollidingStart = OnScriptColliderStart;
956 if (handlerCollidingStart != null)
957 handlerCollidingStart(localId, colliders);
958 }
959
960 public void TriggerScriptColliding(uint localId, ColliderArgs colliders)
961 {
962 handlerColliding = OnScriptColliding;
963 if (handlerColliding != null)
964 handlerColliding(localId, colliders);
965 }
966
967 public void TriggerScriptCollidingEnd(uint localId, ColliderArgs colliders)
968 {
969 handlerCollidingEnd = OnScriptCollidingEnd;
970 if (handlerCollidingEnd != null)
971 handlerCollidingEnd(localId, colliders);
972 }
973
974 public void TriggerSetRootAgentScene(UUID agentID, Scene scene)
975 {
976 handlerSetRootAgentScene = OnSetRootAgentScene;
977 if (handlerSetRootAgentScene != null)
978 handlerSetRootAgentScene(agentID, scene);
979 }
980 }
981}
diff --git a/OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs b/OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs
new file mode 100644
index 0000000..bd9c260
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Hypergrid/HGAssetMapper.cs
@@ -0,0 +1,376 @@
1/**
2 * Copyright (c) 2008, Contributors. All rights reserved.
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the Organizations nor the names of Individual
14 * Contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
25 * OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29using System;
30using System.Collections;
31using System.Collections.Generic;
32using System.Reflection;
33using System.Threading;
34
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38
39using OpenSim.Framework;
40using OpenSim.Framework.Communications;
41using OpenSim.Framework.Communications.Cache;
42using OpenSim.Framework.Servers;
43// using OpenSim.Region.Environment;
44using OpenSim.Region.Framework.Scenes;
45
46//using HyperGrid.Framework;
47//using OpenSim.Region.Communications.Hypergrid;
48
49namespace OpenSim.Region.Framework.Scenes.Hypergrid
50{
51 public class HGAssetMapper
52 {
53 #region Fields
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 // This maps between asset server URLs and asset server clients
57 private Dictionary<string, GridAssetClient> m_assetServers = new Dictionary<string, GridAssetClient>();
58
59 // This maps between asset UUIDs and asset servers
60 private Dictionary<UUID, GridAssetClient> m_assetMap = new Dictionary<UUID, GridAssetClient>();
61
62 private Scene m_scene;
63 #endregion
64
65 #region Constructor
66
67 public HGAssetMapper(Scene scene)
68 {
69 m_scene = scene;
70 }
71
72 #endregion
73
74 #region Internal functions
75
76 private string UserAssetURL(UUID userID)
77 {
78 CachedUserInfo uinfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(userID);
79 if (uinfo != null)
80 return (uinfo.UserProfile.UserAssetURI == "") ? null : uinfo.UserProfile.UserAssetURI;
81 return null;
82 }
83
84 private bool IsLocalUser(UUID userID)
85 {
86 CachedUserInfo uinfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(userID);
87
88 if (uinfo != null)
89 {
90 if (HGNetworkServersInfo.Singleton.IsLocalUser(uinfo.UserProfile))
91 {
92 m_log.Debug("[HGScene]: Home user " + uinfo.UserProfile.FirstName + " " + uinfo.UserProfile.SurName);
93 return true;
94 }
95 }
96
97 m_log.Debug("[HGScene]: Foreign user " + uinfo.UserProfile.FirstName + " " + uinfo.UserProfile.SurName);
98 return false;
99 }
100
101 private bool IsInAssetMap(UUID uuid)
102 {
103 return m_assetMap.ContainsKey(uuid);
104 }
105
106 private bool FetchAsset(GridAssetClient asscli, UUID assetID, bool isTexture)
107 {
108 // I'm not going over 3 seconds since this will be blocking processing of all the other inbound
109 // packets from the client.
110 int pollPeriod = 200;
111 int maxPolls = 15;
112
113 AssetBase asset;
114
115 // Maybe it came late, and it's already here. Check first.
116 if (m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset))
117 {
118 m_log.Debug("[HGScene]: Asset already in asset cache. " + assetID);
119 return true;
120 }
121
122
123 asscli.RequestAsset(assetID, isTexture);
124
125 do
126 {
127 Thread.Sleep(pollPeriod);
128
129 if (m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset) && (asset != null))
130 {
131 m_log.Debug("[HGScene]: Asset made it to asset cache. " + asset.Metadata.Name + " " + assetID);
132 // I think I need to store it in the asset DB too.
133 // For now, let me just do it for textures and scripts
134 if (((AssetType)asset.Metadata.Type == AssetType.Texture) ||
135 ((AssetType)asset.Metadata.Type == AssetType.LSLBytecode) ||
136 ((AssetType)asset.Metadata.Type == AssetType.LSLText))
137 {
138 AssetBase asset1 = new AssetBase();
139 Copy(asset, asset1);
140 m_scene.AssetCache.AssetServer.StoreAsset(asset1);
141 }
142 return true;
143 }
144 } while (--maxPolls > 0);
145
146 m_log.WarnFormat("[HGScene]: {0} {1} was not received before the retrieval timeout was reached",
147 isTexture ? "texture" : "asset", assetID.ToString());
148
149 return false;
150 }
151
152 private bool PostAsset(GridAssetClient asscli, UUID assetID)
153 {
154 AssetBase asset1;
155 m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset1);
156
157 if (asset1 != null)
158 {
159 // See long comment in AssetCache.AddAsset
160 if (!asset1.Metadata.Temporary || asset1.Metadata.Local)
161 {
162 // The asset cache returns instances of subclasses of AssetBase:
163 // TextureImage or AssetInfo. So in passing them to the remote
164 // server we first need to convert this to instances of AssetBase,
165 // which is the serializable class for assets.
166 AssetBase asset = new AssetBase();
167 Copy(asset1, asset);
168
169 asscli.StoreAsset(asset);
170 }
171 return true;
172 }
173 else
174 m_log.Warn("[HGScene]: Tried to post asset to remote server, but asset not in local cache.");
175
176 return false;
177 }
178
179 private void Copy(AssetBase from, AssetBase to)
180 {
181 to.Data = from.Data;
182 to.Metadata.Description = from.Metadata.Description;
183 to.Metadata.FullID = from.Metadata.FullID;
184 to.Metadata.ID = from.Metadata.ID;
185 to.Metadata.Local = from.Metadata.Local;
186 to.Metadata.Name = from.Metadata.Name;
187 to.Metadata.Temporary = from.Metadata.Temporary;
188 to.Metadata.Type = from.Metadata.Type;
189
190 }
191
192 private void _guardedAdd(Dictionary<UUID, bool> lst, UUID obj, bool val)
193 {
194 if (!lst.ContainsKey(obj))
195 lst.Add(obj, val);
196 }
197
198 private void SniffTextureUUIDs(Dictionary<UUID, bool> uuids, SceneObjectGroup sog)
199 {
200 try
201 {
202 _guardedAdd(uuids, sog.RootPart.Shape.Textures.DefaultTexture.TextureID, true);
203 }
204 catch (Exception) { }
205
206 foreach (Primitive.TextureEntryFace tface in sog.RootPart.Shape.Textures.FaceTextures)
207 {
208 try
209 {
210 _guardedAdd(uuids, tface.TextureID, true);
211 }
212 catch (Exception) { }
213 }
214
215 foreach (SceneObjectPart sop in sog.Children.Values)
216 {
217 try
218 {
219 _guardedAdd(uuids, sop.Shape.Textures.DefaultTexture.TextureID, true);
220 }
221 catch (Exception) { }
222 foreach (Primitive.TextureEntryFace tface in sop.Shape.Textures.FaceTextures)
223 {
224 try
225 {
226 _guardedAdd(uuids, tface.TextureID, true);
227 }
228 catch (Exception) { }
229 }
230 }
231 }
232
233 private void SniffTaskInventoryUUIDs(Dictionary<UUID, bool> uuids, SceneObjectGroup sog)
234 {
235 TaskInventoryDictionary tinv = sog.RootPart.TaskInventory;
236
237 foreach (TaskInventoryItem titem in tinv.Values)
238 {
239 uuids.Add(titem.AssetID, (InventoryType)titem.Type == InventoryType.Texture);
240 }
241 }
242
243 private Dictionary<UUID, bool> SniffUUIDs(AssetBase asset)
244 {
245 Dictionary<UUID, bool> uuids = new Dictionary<UUID, bool>();
246 if ((asset != null) && ((AssetType)asset.Metadata.Type == AssetType.Object))
247 {
248 string ass_str = Utils.BytesToString(asset.Data);
249 SceneObjectGroup sog = new SceneObjectGroup(ass_str, true);
250
251 SniffTextureUUIDs(uuids, sog);
252
253 // We need to sniff further...
254 SniffTaskInventoryUUIDs(uuids, sog);
255
256 }
257
258 return uuids;
259 }
260
261 private Dictionary<UUID, bool> SniffUUIDs(UUID assetID)
262 {
263 //Dictionary<UUID, bool> uuids = new Dictionary<UUID, bool>();
264
265 AssetBase asset;
266 m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset);
267
268 return SniffUUIDs(asset);
269 }
270
271 private void Dump(Dictionary<UUID, bool> lst)
272 {
273 m_log.Debug("XXX -------- UUID DUMP ------- XXX");
274 foreach (KeyValuePair<UUID, bool> kvp in lst)
275 m_log.Debug(" >> " + kvp.Key + " (texture? " + kvp.Value + ")");
276 m_log.Debug("XXX -------- UUID DUMP ------- XXX");
277 }
278
279 #endregion
280
281
282 #region Public interface
283
284 public void Get(UUID itemID, UUID ownerID)
285 {
286 if (!IsInAssetMap(itemID) && !IsLocalUser(ownerID))
287 {
288 // Get the item from the remote asset server onto the local AssetCache
289 // and place an entry in m_assetMap
290
291 GridAssetClient asscli = null;
292 string userAssetURL = UserAssetURL(ownerID);
293 if (userAssetURL != null)
294 {
295 m_assetServers.TryGetValue(userAssetURL, out asscli);
296 if (asscli == null)
297 {
298 m_log.Debug("[HGScene]: Starting new GridAssetClient for " + userAssetURL);
299 asscli = new GridAssetClient(userAssetURL);
300 asscli.SetReceiver(m_scene.CommsManager.AssetCache); // Straight to the asset cache!
301 m_assetServers.Add(userAssetURL, asscli);
302 }
303
304 m_log.Debug("[HGScene]: Fetching object " + itemID + " to asset server " + userAssetURL);
305 bool success = FetchAsset(asscli, itemID, false); // asscli.RequestAsset(item.ItemID, false);
306
307 // OK, now fetch the inside.
308 Dictionary<UUID, bool> ids = SniffUUIDs(itemID);
309 Dump(ids);
310 foreach (KeyValuePair<UUID, bool> kvp in ids)
311 FetchAsset(asscli, kvp.Key, kvp.Value);
312
313
314 if (success)
315 {
316 m_log.Debug("[HGScene]: Successfully fetched item from remote asset server " + userAssetURL);
317 m_assetMap.Add(itemID, asscli);
318 }
319 else
320 m_log.Warn("[HGScene]: Could not fetch asset from remote asset server " + userAssetURL);
321 }
322 else
323 m_log.Warn("[HGScene]: Unable to locate foreign user's asset server");
324 }
325 }
326
327 public void Post(UUID itemID, UUID ownerID)
328 {
329 if (!IsLocalUser(ownerID))
330 {
331 // Post the item from the local AssetCache ontp the remote asset server
332 // and place an entry in m_assetMap
333
334 GridAssetClient asscli = null;
335 string userAssetURL = UserAssetURL(ownerID);
336 if (userAssetURL != null)
337 {
338 m_assetServers.TryGetValue(userAssetURL, out asscli);
339 if (asscli == null)
340 {
341 m_log.Debug("[HGScene]: Starting new GridAssetClient for " + userAssetURL);
342 asscli = new GridAssetClient(userAssetURL);
343 asscli.SetReceiver(m_scene.CommsManager.AssetCache); // Straight to the asset cache!
344 m_assetServers.Add(userAssetURL, asscli);
345 }
346 m_log.Debug("[HGScene]: Posting object " + itemID + " to asset server " + userAssetURL);
347 bool success = PostAsset(asscli, itemID);
348
349 // Now the inside
350 Dictionary<UUID, bool> ids = SniffUUIDs(itemID);
351 Dump(ids);
352 foreach (KeyValuePair<UUID, bool> kvp in ids)
353 PostAsset(asscli, kvp.Key);
354
355 if (success)
356 {
357 m_log.Debug("[HGScene]: Successfully posted item to remote asset server " + userAssetURL);
358 if (!m_assetMap.ContainsKey(itemID))
359 m_assetMap.Add(itemID, asscli);
360 }
361 else
362 m_log.Warn("[HGScene]: Could not post asset to remote asset server " + userAssetURL);
363
364 //if (!m_assetMap.ContainsKey(itemID))
365 // m_assetMap.Add(itemID, asscli);
366 }
367 else
368 m_log.Warn("[HGScene]: Unable to locate foreign user's asset server");
369
370 }
371 }
372
373 #endregion
374
375 }
376}
diff --git a/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs
new file mode 100644
index 0000000..f36075e
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.Inventory.cs
@@ -0,0 +1,152 @@
1/**
2 * Copyright (c) 2008, Contributors. All rights reserved.
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the Organizations nor the names of Individual
14 * Contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
25 * OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29using System;
30using System.Collections;
31using System.Collections.Generic;
32using System.Reflection;
33using System.Threading;
34
35using log4net;
36using Nini.Config;
37using OpenMetaverse;
38
39using OpenSim.Framework;
40using OpenSim.Framework.Communications;
41using OpenSim.Framework.Communications.Cache;
42using OpenSim.Framework.Servers;
43// using OpenSim.Region.Environment;
44using OpenSim.Region.Framework.Scenes;
45
46namespace OpenSim.Region.Framework.Scenes.Hypergrid
47{
48 public partial class HGScene : Scene
49 {
50 #region Fields
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52
53 private HGAssetMapper m_assMapper;
54
55 #endregion
56
57 #region Constructors
58
59 public HGScene(RegionInfo regInfo, AgentCircuitManager authen,
60 CommunicationsManager commsMan, SceneCommunicationService sceneGridService,
61 AssetCache assetCach, StorageManager storeManager,
62 ModuleLoader moduleLoader, bool dumpAssetsToFile, bool physicalPrim,
63 bool SeeIntoRegionFromNeighbor, IConfigSource config, string simulatorVersion)
64 : base(regInfo, authen, commsMan, sceneGridService, assetCach, storeManager, moduleLoader,
65 dumpAssetsToFile, physicalPrim, SeeIntoRegionFromNeighbor, config, simulatorVersion)
66 {
67 m_log.Info("[HGScene]: Starting HGScene.");
68 m_assMapper = new HGAssetMapper(this);
69
70 EventManager.OnNewInventoryItemUploadComplete += UploadInventoryItem;
71 }
72
73 #endregion
74
75 #region Event handlers
76
77 public void UploadInventoryItem(UUID avatarID, UUID assetID, string name, int userlevel)
78 {
79 CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(avatarID);
80 if (userInfo != null)
81 {
82 m_assMapper.Post(assetID, avatarID);
83 }
84 }
85
86 #endregion
87
88 #region Overrides of Scene.Inventory methods
89
90 ///
91 /// CapsUpdateInventoryItemAsset
92 ///
93 public override UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data)
94 {
95 UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data);
96
97 UploadInventoryItem(remoteClient.AgentId, newAssetID, "", 0);
98
99 return newAssetID;
100 }
101
102 ///
103 /// DeleteToInventory
104 ///
105 public override UUID DeleteToInventory(DeRezAction action, UUID folderID, SceneObjectGroup objectGroup, IClientAPI remoteClient)
106 {
107 UUID assetID = base.DeleteToInventory(action, folderID, objectGroup, remoteClient);
108
109 if (!assetID.Equals(UUID.Zero))
110 {
111 UploadInventoryItem(remoteClient.AgentId, assetID, "", 0);
112 }
113 else
114 m_log.Debug("[HGScene]: Scene.Inventory did not create asset");
115
116 return assetID;
117 }
118
119 ///
120 /// RezObject
121 ///
122 public override SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart,
123 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
124 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
125 {
126 CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
127 if (userInfo != null)
128 {
129 if (userInfo.RootFolder != null)
130 {
131 InventoryItemBase item = userInfo.RootFolder.FindItem(itemID);
132
133 if (item != null)
134 {
135 m_assMapper.Get(item.AssetID, remoteClient.AgentId);
136
137 }
138 }
139 }
140
141 // OK, we're done fetching. Pass it up to the default RezObject
142 return base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
143 RezSelected, RemoveItem, fromTaskID, attachment);
144
145 }
146
147
148 #endregion
149
150 }
151
152}
diff --git a/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.cs b/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.cs
new file mode 100644
index 0000000..a52fdc6
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Hypergrid/HGScene.cs
@@ -0,0 +1,84 @@
1/**
2 * Copyright (c) 2008, Contributors. All rights reserved.
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the Organizations nor the names of Individual
14 * Contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
25 * OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29using System;
30using System.Collections.Generic;
31
32using OpenMetaverse;
33
34using OpenSim.Framework;
35
36using OpenSim.Framework.Communications.Cache;
37// using OpenSim.Region.Environment;
38using OpenSim.Region.Framework.Scenes;
39using TPFlags = OpenSim.Framework.Constants.TeleportFlags;
40
41namespace OpenSim.Region.Framework.Scenes.Hypergrid
42{
43 public partial class HGScene : Scene
44 {
45 /// <summary>
46 /// Teleport an avatar to their home region
47 /// </summary>
48 /// <param name="agentId"></param>
49 /// <param name="client"></param>
50 public override void TeleportClientHome(UUID agentId, IClientAPI client)
51 {
52 m_log.Debug("[HGScene]: TeleportClientHome " + client.FirstName + " " + client.LastName);
53
54 CachedUserInfo uinfo = CommsManager.UserProfileCacheService.GetUserDetails(agentId);
55 if (uinfo != null)
56 {
57 UserProfileData UserProfile = uinfo.UserProfile;
58
59 if (UserProfile != null)
60 {
61 RegionInfo regionInfo = CommsManager.GridService.RequestNeighbourInfo(UserProfile.HomeRegion);
62 //if (regionInfo != null)
63 //{
64 // UserProfile.HomeRegionID = regionInfo.RegionID;
65 // //CommsManager.UserService.UpdateUserProfile(UserProfile);
66 //}
67 if (regionInfo == null)
68 {
69 // can't find the Home region: Tell viewer and abort
70 client.SendTeleportFailed("Your home-region could not be found.");
71 return;
72 }
73 RequestTeleportLocation(
74 client, regionInfo.RegionHandle, UserProfile.HomeLocation, UserProfile.HomeLookAt,
75 (uint)(TPFlags.SetLastToTarget | TPFlags.ViaHome));
76 }
77 }
78 else
79 client.SendTeleportFailed("Sorry! I lost your home-region information.");
80
81 }
82
83 }
84}
diff --git a/OpenSim/Region/Framework/Scenes/Hypergrid/HGSceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/Hypergrid/HGSceneCommunicationService.cs
new file mode 100644
index 0000000..d0dc4f7
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Hypergrid/HGSceneCommunicationService.cs
@@ -0,0 +1,360 @@
1/**
2 * Copyright (c) 2008, Contributors. All rights reserved.
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * * Neither the name of the Organizations nor the names of Individual
14 * Contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20 * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
25 * OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29using System;
30using System.Collections.Generic;
31using System.Net;
32using System.Reflection;
33using System.Threading;
34using log4net;
35using OpenMetaverse;
36using OSD = OpenMetaverse.StructuredData.OSD;
37using OpenSim.Framework;
38using OpenSim.Framework.Communications;
39using OpenSim.Framework.Communications.Cache;
40using OpenSim.Framework.Communications.Capabilities;
41using OpenSim.Region.Framework.Scenes;
42// using OpenSim.Region.Environment;
43using OpenSim.Region.Framework.Interfaces;
44
45namespace OpenSim.Region.Framework.Scenes.Hypergrid
46{
47 public class HGSceneCommunicationService : SceneCommunicationService
48 {
49 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50
51 public readonly IHyperlink m_hg;
52
53 public HGSceneCommunicationService(CommunicationsManager commsMan, IHyperlink hg) : base(commsMan)
54 {
55 m_hg = hg;
56 }
57
58
59 /// <summary>
60 /// Try to teleport an agent to a new region.
61 /// </summary>
62 /// <param name="remoteClient"></param>
63 /// <param name="RegionHandle"></param>
64 /// <param name="position"></param>
65 /// <param name="lookAt"></param>
66 /// <param name="flags"></param>
67 public override void RequestTeleportToLocation(ScenePresence avatar, ulong regionHandle, Vector3 position,
68 Vector3 lookAt, uint teleportFlags)
69 {
70 if (!avatar.Scene.Permissions.CanTeleport(avatar.UUID))
71 return;
72
73 bool destRegionUp = true;
74
75 IEventQueue eq = avatar.Scene.RequestModuleInterface<IEventQueue>();
76
77 if (regionHandle == m_regionInfo.RegionHandle)
78 {
79 // Teleport within the same region
80 if (position.X < 0 || position.X > Constants.RegionSize || position.Y < 0 || position.Y > Constants.RegionSize || position.Z < 0)
81 {
82 Vector3 emergencyPos = new Vector3(128, 128, 128);
83
84 m_log.WarnFormat(
85 "[HGSceneCommService]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}",
86 position, avatar.Name, avatar.UUID, emergencyPos);
87 position = emergencyPos;
88 }
89 // TODO: Get proper AVG Height
90 float localAVHeight = 1.56f;
91 float posZLimit = (float)avatar.Scene.GetLandHeight((int)position.X, (int)position.Y);
92 float newPosZ = posZLimit + localAVHeight;
93 if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
94 {
95 position.Z = newPosZ;
96 }
97
98 // Only send this if the event queue is null
99 if (eq == null)
100 avatar.ControllingClient.SendTeleportLocationStart();
101
102
103 avatar.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags);
104 avatar.Teleport(position);
105 }
106 else
107 {
108 RegionInfo reg = RequestNeighbouringRegionInfo(regionHandle);
109 if (reg != null)
110 {
111
112 uint newRegionX = (uint)(reg.RegionHandle >> 40);
113 uint newRegionY = (((uint)(reg.RegionHandle)) >> 8);
114 uint oldRegionX = (uint)(m_regionInfo.RegionHandle >> 40);
115 uint oldRegionY = (((uint)(m_regionInfo.RegionHandle)) >> 8);
116
117 ///
118 /// Hypergrid mod start
119 ///
120 ///
121 bool isHyperLink = m_hg.IsHyperlinkRegion(reg.RegionHandle);
122 bool isHomeUser = true;
123 ulong realHandle = regionHandle;
124 CachedUserInfo uinfo = m_commsProvider.UserProfileCacheService.GetUserDetails(avatar.UUID);
125 if (uinfo != null)
126 {
127 isHomeUser = HGNetworkServersInfo.Singleton.IsLocalUser(uinfo.UserProfile);
128 realHandle = m_hg.FindRegionHandle(regionHandle);
129 Console.WriteLine("XXX ---- home user? " + isHomeUser + " --- hyperlink? " + isHyperLink + " --- real handle: " + realHandle.ToString());
130 }
131 ///
132 /// Hypergrid mod stop
133 ///
134 ///
135
136 if (eq == null)
137 avatar.ControllingClient.SendTeleportLocationStart();
138
139
140 // Let's do DNS resolution only once in this process, please!
141 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
142 // it's actually doing a lot of work.
143 IPEndPoint endPoint = reg.ExternalEndPoint;
144 if (endPoint.Address == null)
145 {
146 // Couldn't resolve the name. Can't TP, because the viewer wants IP addresses.
147 destRegionUp = false;
148 }
149
150 if (destRegionUp)
151 {
152 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
153 // both regions
154 if (avatar.ParentID != (uint)0)
155 avatar.StandUp();
156
157 if (!avatar.ValidateAttachments())
158 {
159 avatar.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
160 return;
161 }
162
163 // the avatar.Close below will clear the child region list. We need this below for (possibly)
164 // closing the child agents, so save it here (we need a copy as it is Clear()-ed).
165 //List<ulong> childRegions = new List<ulong>(avatar.GetKnownRegionList());
166 // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport
167 // failure at this point (unlike a border crossing failure). So perhaps this can never fail
168 // once we reach here...
169 //avatar.Scene.RemoveCapsHandler(avatar.UUID);
170
171 string capsPath = String.Empty;
172 AgentCircuitData agentCircuit = avatar.ControllingClient.RequestClientInfo();
173 agentCircuit.BaseFolder = UUID.Zero;
174 agentCircuit.InventoryFolder = UUID.Zero;
175 agentCircuit.startpos = position;
176 agentCircuit.child = true;
177 if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY))
178 {
179 // brand new agent, let's create a new caps seed
180 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
181 }
182
183 //if (!m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, agentCircuit))
184 if (!m_interregionCommsOut.SendCreateChildAgent(reg.RegionHandle, agentCircuit))
185 {
186 avatar.ControllingClient.SendTeleportFailed("Destination is not accepting teleports.");
187 return;
188 }
189
190 // Let's close some agents
191 if (isHyperLink) // close them all except this one
192 {
193 List<ulong> regions = new List<ulong>(avatar.KnownChildRegionHandles);
194 regions.Remove(avatar.Scene.RegionInfo.RegionHandle);
195 SendCloseChildAgentConnections(avatar.UUID, regions);
196 }
197 else // close just a few
198 avatar.CloseChildAgents(newRegionX, newRegionY);
199
200 if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY) || isHyperLink)
201 {
202 capsPath
203 = "http://"
204 + reg.ExternalHostName
205 + ":"
206 + reg.HttpPort
207 + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
208
209 if (eq != null)
210 {
211 eq.EnableSimulator(realHandle, endPoint, avatar.UUID);
212
213 // ES makes the client send a UseCircuitCode message to the destination,
214 // which triggers a bunch of things there.
215 // So let's wait
216 Thread.Sleep(2000);
217
218 eq.EstablishAgentCommunication(avatar.UUID, endPoint, capsPath);
219 }
220 else
221 {
222 avatar.ControllingClient.InformClientOfNeighbour(realHandle, endPoint);
223 // TODO: make Event Queue disablable!
224 }
225 }
226 else
227 {
228 // child agent already there
229 agentCircuit.CapsPath = avatar.Scene.CapsModule.GetChildSeed(avatar.UUID, reg.RegionHandle);
230 capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort
231 + "/CAPS/" + agentCircuit.CapsPath + "0000/";
232 }
233
234 //m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId,
235 // position, false);
236
237 //if (!m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId,
238 // position, false))
239 //{
240 // avatar.ControllingClient.SendTeleportFailed("Problem with destination.");
241 // // We should close that agent we just created over at destination...
242 // List<ulong> lst = new List<ulong>();
243 // lst.Add(realHandle);
244 // SendCloseChildAgentAsync(avatar.UUID, lst);
245 // return;
246 //}
247
248 SetInTransit(avatar.UUID);
249 // Let's send a full update of the agent. This is a synchronous call.
250 AgentData agent = new AgentData();
251 avatar.CopyTo(agent);
252 agent.Position = position;
253 agent.CallbackURI = "http://" + m_regionInfo.ExternalHostName + ":" + m_regionInfo.HttpPort +
254 "/agent/" + avatar.UUID.ToString() + "/" + avatar.Scene.RegionInfo.RegionHandle.ToString() + "/release/";
255
256 m_interregionCommsOut.SendChildAgentUpdate(reg.RegionHandle, agent);
257
258 m_log.DebugFormat(
259 "[CAPS]: Sending new CAPS seed url {0} to client {1}", agentCircuit.CapsPath, avatar.UUID);
260
261
262 ///
263 /// Hypergrid mod: realHandle instead of reg.RegionHandle
264 ///
265 ///
266 if (eq != null)
267 {
268 eq.TeleportFinishEvent(realHandle, 13, endPoint,
269 4, teleportFlags, capsPath, avatar.UUID);
270 }
271 else
272 {
273 avatar.ControllingClient.SendRegionTeleport(realHandle, 13, endPoint, 4,
274 teleportFlags, capsPath);
275 }
276 ///
277 /// Hypergrid mod stop
278 ///
279
280
281 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
282 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
283 // that the client contacted the destination before we send the attachments and close things here.
284 if (!WaitForCallback(avatar.UUID))
285 {
286 // Client never contacted destination. Let's restore everything back
287 avatar.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
288
289 ResetFromTransit(avatar.UUID);
290 // Yikes! We should just have a ref to scene here.
291 avatar.Scene.InformClientOfNeighbours(avatar);
292
293 // Finally, kill the agent we just created at the destination.
294 m_interregionCommsOut.SendCloseAgent(reg.RegionHandle, avatar.UUID);
295
296 return;
297 }
298
299 // Can't go back from here
300 if (KiPrimitive != null)
301 {
302 KiPrimitive(avatar.LocalId);
303 }
304
305 avatar.MakeChildAgent();
306
307 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
308 avatar.CrossAttachmentsIntoNewRegion(reg.RegionHandle, true);
309
310
311 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
312 ///
313 /// Hypergrid mod: extra check for isHyperLink
314 ///
315 if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY) || isHyperLink)
316 {
317 Thread.Sleep(5000);
318 avatar.Close();
319 CloseConnection(avatar.UUID);
320 }
321 // if (teleport success) // seems to be always success here
322 // the user may change their profile information in other region,
323 // so the userinfo in UserProfileCache is not reliable any more, delete it
324 if (avatar.Scene.NeedSceneCacheClear(avatar.UUID) || isHyperLink)
325 {
326 m_commsProvider.UserProfileCacheService.RemoveUser(avatar.UUID);
327 m_log.DebugFormat(
328 "[HGSceneCommService]: User {0} is going to another region, profile cache removed",
329 avatar.UUID);
330 }
331 }
332 else
333 {
334 avatar.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
335 }
336 }
337 else
338 {
339 // TP to a place that doesn't exist (anymore)
340 // Inform the viewer about that
341 avatar.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore");
342
343 // and set the map-tile to '(Offline)'
344 uint regX, regY;
345 Utils.LongToUInts(regionHandle, out regX, out regY);
346
347 MapBlockData block = new MapBlockData();
348 block.X = (ushort)(regX / Constants.RegionSize);
349 block.Y = (ushort)(regY / Constants.RegionSize);
350 block.Access = 254; // == not there
351
352 List<MapBlockData> blocks = new List<MapBlockData>();
353 blocks.Add(block);
354 avatar.ControllingClient.SendMapBlock(blocks, 0);
355 }
356 }
357 }
358
359 }
360}
diff --git a/OpenSim/Region/Framework/Scenes/IScenePresenceBody.cs b/OpenSim/Region/Framework/Scenes/IScenePresenceBody.cs
new file mode 100644
index 0000000..bd5ad33
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/IScenePresenceBody.cs
@@ -0,0 +1,37 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenMetaverse;
29using OpenSim.Framework;
30
31namespace OpenSim.Region.Framework.Scenes
32{
33 public interface IScenePresenceBody
34 {
35 void processMovement(IClientAPI remoteClient, uint flags, Quaternion bodyRotation);
36 }
37}
diff --git a/OpenSim/Region/Framework/Scenes/ReturnInfo.cs b/OpenSim/Region/Framework/Scenes/ReturnInfo.cs
new file mode 100644
index 0000000..43d07f5
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/ReturnInfo.cs
@@ -0,0 +1,39 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenMetaverse;
29
30namespace OpenSim.Region.Framework.Scenes
31{
32 public struct ReturnInfo
33 {
34 public int count;
35 public Vector3 location;
36 public string objectName;
37 public string reason;
38 }
39}
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
new file mode 100644
index 0000000..e366c79
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -0,0 +1,2665 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Text;
32using System.Timers;
33using OpenMetaverse;
34using log4net;
35using OpenSim.Framework;
36using OpenSim.Framework.Communications.Cache;
37using OpenSim.Region.Framework;
38using OpenSim.Region.Framework.Interfaces;
39
40namespace OpenSim.Region.Framework.Scenes
41{
42 public partial class Scene
43 {
44 private static readonly ILog m_log
45 = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46
47 /// <summary>
48 /// Allows asynchronous derezzing of objects from the scene into a client's inventory.
49 /// </summary>
50 protected AsyncSceneObjectGroupDeleter m_asyncSceneObjectDeleter;
51
52 /// <summary>
53 /// Start all the scripts in the scene which should be started.
54 /// </summary>
55 public void CreateScriptInstances()
56 {
57 m_log.Info("[PRIM INVENTORY]: Starting scripts in scene");
58
59 foreach (EntityBase group in Entities)
60 {
61 if (group is SceneObjectGroup)
62 {
63 ((SceneObjectGroup) group).CreateScriptInstances(0, false, DefaultScriptEngine, 0);
64 }
65 }
66 }
67
68 public void AddUploadedInventoryItem(UUID agentID, InventoryItemBase item)
69 {
70 IMoneyModule money=RequestModuleInterface<IMoneyModule>();
71 if (money != null)
72 {
73 money.ApplyUploadCharge(agentID);
74 }
75
76 AddInventoryItem(agentID, item);
77 }
78
79 public bool AddInventoryItemReturned(UUID AgentId, InventoryItemBase item)
80 {
81 CachedUserInfo userInfo
82 = CommsManager.UserProfileCacheService.GetUserDetails(AgentId);
83 if (userInfo != null)
84 {
85 userInfo.AddItem(item);
86 return true;
87 }
88 else
89 {
90 m_log.ErrorFormat(
91 "[AGENT INVENTORY]: Agent was not found for add of item {1} {2}", item.Name, item.ID);
92
93 return false;
94 }
95 }
96
97 public void AddInventoryItem(UUID AgentID, InventoryItemBase item)
98 {
99 CachedUserInfo userInfo
100 = CommsManager.UserProfileCacheService.GetUserDetails(AgentID);
101
102 if (userInfo != null)
103 {
104 userInfo.AddItem(item);
105
106 int userlevel = 0;
107 if (Permissions.IsGod(AgentID))
108 {
109 userlevel = 1;
110 }
111 // TODO: remove this cruft once MasterAvatar is fully deprecated
112 //
113 if (m_regInfo.MasterAvatarAssignedUUID == AgentID)
114 {
115 userlevel = 2;
116 }
117 EventManager.TriggerOnNewInventoryItemUploadComplete(AgentID, item.AssetID, item.Name, userlevel);
118 }
119 else
120 {
121 m_log.ErrorFormat(
122 "[AGENT INVENTORY]: Agent {1} was not found for add of item {2} {3}",
123 AgentID, item.Name, item.ID);
124
125 return;
126 }
127 }
128
129 /// <summary>
130 /// Add an inventory item to an avatar's inventory.
131 /// </summary>
132 /// <param name="remoteClient">The remote client controlling the avatar</param>
133 /// <param name="item">The item. This structure contains all the item metadata, including the folder
134 /// in which the item is to be placed.</param>
135 public void AddInventoryItem(IClientAPI remoteClient, InventoryItemBase item)
136 {
137 CachedUserInfo userInfo
138 = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
139
140 if (userInfo != null)
141 {
142 AddInventoryItem(remoteClient.AgentId, item);
143 remoteClient.SendInventoryItemCreateUpdate(item);
144 }
145 else
146 {
147 m_log.ErrorFormat(
148 "[AGENT INVENTORY]: Could not resolve user {0} for adding an inventory item",
149 remoteClient.AgentId);
150 }
151 }
152
153 /// <summary>
154 /// Capability originating call to update the asset of an item in an agent's inventory
155 /// </summary>
156 /// <param name="remoteClient"></param>
157 /// <param name="itemID"></param>
158 /// <param name="data"></param>
159 /// <returns></returns>
160 public virtual UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data)
161 {
162 CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
163 if (userInfo != null)
164 {
165 if (userInfo.RootFolder != null)
166 {
167 InventoryItemBase item = userInfo.RootFolder.FindItem(itemID);
168
169 if (item != null)
170 {
171 if ((InventoryType)item.InvType == InventoryType.Notecard)
172 {
173 if (!Permissions.CanEditNotecard(itemID, UUID.Zero, remoteClient.AgentId))
174 {
175 remoteClient.SendAgentAlertMessage("Insufficient permissions to edit notecard", false);
176 return UUID.Zero;
177 }
178
179 remoteClient.SendAgentAlertMessage("Notecard saved", false);
180 }
181 else if ((InventoryType)item.InvType == InventoryType.LSL)
182 {
183 if (!Permissions.CanEditScript(itemID, UUID.Zero, remoteClient.AgentId))
184 {
185 remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false);
186 return UUID.Zero;
187 }
188
189 remoteClient.SendAgentAlertMessage("Script saved", false);
190 }
191
192 AssetBase asset =
193 CreateAsset(item.Name, item.Description, (sbyte)item.AssetType, data);
194 AssetCache.AddAsset(asset);
195
196 item.AssetID = asset.Metadata.FullID;
197 userInfo.UpdateItem(item);
198
199 // remoteClient.SendInventoryItemCreateUpdate(item);
200 return (asset.Metadata.FullID);
201 }
202 }
203 }
204 else
205 {
206 m_log.ErrorFormat(
207 "[AGENT INVENTORY]: Could not resolve user {0} for caps inventory update",
208 remoteClient.AgentId);
209 }
210
211 return UUID.Zero;
212 }
213
214 /// <summary>
215 /// <see>CapsUpdatedInventoryItemAsset(IClientAPI, UUID, byte[])</see>
216 /// </summary>
217 public UUID CapsUpdateInventoryItemAsset(UUID avatarId, UUID itemID, byte[] data)
218 {
219 ScenePresence avatar;
220
221 if (TryGetAvatar(avatarId, out avatar))
222 {
223 return CapsUpdateInventoryItemAsset(avatar.ControllingClient, itemID, data);
224 }
225 else
226 {
227 m_log.ErrorFormat(
228 "[AGENT INVENTORY]: " +
229 "Avatar {0} cannot be found to update its inventory item asset",
230 avatarId);
231 }
232
233 return UUID.Zero;
234 }
235
236 /// <summary>
237 /// Capability originating call to update the asset of a script in a prim's (task's) inventory
238 /// </summary>
239 /// <param name="remoteClient"></param>
240 /// <param name="itemID"></param>
241 /// <param name="primID">The prim which contains the item to update</param>
242 /// <param name="isScriptRunning">Indicates whether the script to update is currently running</param>
243 /// <param name="data"></param>
244 public void CapsUpdateTaskInventoryScriptAsset(IClientAPI remoteClient, UUID itemId,
245 UUID primId, bool isScriptRunning, byte[] data)
246 {
247 if (!Permissions.CanEditScript(itemId, primId, remoteClient.AgentId))
248 {
249 remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false);
250 return;
251 }
252
253 // Retrieve group
254 SceneObjectPart part = GetSceneObjectPart(primId);
255 SceneObjectGroup group = part.ParentGroup;
256 if (null == group)
257 {
258 m_log.ErrorFormat(
259 "[PRIM INVENTORY]: " +
260 "Prim inventory update requested for item ID {0} in prim ID {1} but this prim does not exist",
261 itemId, primId);
262
263 return;
264 }
265
266 // Retrieve item
267 TaskInventoryItem item = group.GetInventoryItem(part.LocalId, itemId);
268
269 if (null == item)
270 {
271 m_log.ErrorFormat(
272 "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for caps script update "
273 + " but the item does not exist in this inventory",
274 itemId, part.Name, part.UUID);
275
276 return;
277 }
278
279 AssetBase asset = CreateAsset(item.Name, item.Description, (sbyte)AssetType.LSLText, data);
280 AssetCache.AddAsset(asset);
281
282 if (isScriptRunning)
283 {
284 part.Inventory.RemoveScriptInstance(item.ItemID);
285 }
286
287 // Update item with new asset
288 item.AssetID = asset.Metadata.FullID;
289 group.UpdateInventoryItem(item);
290 part.GetProperties(remoteClient);
291
292 // Trigger rerunning of script (use TriggerRezScript event, see RezScript)
293 if (isScriptRunning)
294 {
295 // Needs to determine which engine was running it and use that
296 //
297 part.Inventory.CreateScriptInstance(item.ItemID, 0, false, DefaultScriptEngine, 0);
298 }
299 else
300 {
301 remoteClient.SendAgentAlertMessage("Script saved", false);
302 }
303 }
304
305 /// <summary>
306 /// <see>CapsUpdateTaskInventoryScriptAsset(IClientAPI, UUID, UUID, bool, byte[])</see>
307 /// </summary>
308 public void CapsUpdateTaskInventoryScriptAsset(UUID avatarId, UUID itemId,
309 UUID primId, bool isScriptRunning, byte[] data)
310 {
311 ScenePresence avatar;
312
313 if (TryGetAvatar(avatarId, out avatar))
314 {
315 CapsUpdateTaskInventoryScriptAsset(
316 avatar.ControllingClient, itemId, primId, isScriptRunning, data);
317 }
318 else
319 {
320 m_log.ErrorFormat(
321 "[PRIM INVENTORY]: " +
322 "Avatar {0} cannot be found to update its prim item asset",
323 avatarId);
324 }
325 }
326
327 /// <summary>
328 /// Update an item which is either already in the client's inventory or is within
329 /// a transaction
330 /// </summary>
331 /// <param name="remoteClient"></param>
332 /// <param name="transactionID">The transaction ID. If this is UUID.Zero we will
333 /// assume that we are not in a transaction</param>
334 /// <param name="itemID">The ID of the updated item</param>
335 /// <param name="name">The name of the updated item</param>
336 /// <param name="description">The description of the updated item</param>
337 /// <param name="nextOwnerMask">The permissions of the updated item</param>
338/* public void UpdateInventoryItemAsset(IClientAPI remoteClient, UUID transactionID,
339 UUID itemID, string name, string description,
340 uint nextOwnerMask)*/
341 public void UpdateInventoryItemAsset(IClientAPI remoteClient, UUID transactionID,
342 UUID itemID, InventoryItemBase itemUpd)
343 {
344 CachedUserInfo userInfo
345 = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
346
347 if (userInfo != null && userInfo.RootFolder != null)
348 {
349 InventoryItemBase item = userInfo.RootFolder.FindItem(itemID);
350
351 if (item != null)
352 {
353 if (UUID.Zero == transactionID)
354 {
355 item.Name = itemUpd.Name;
356 item.Description = itemUpd.Description;
357 item.NextPermissions = itemUpd.NextPermissions;
358 item.CurrentPermissions |= 8; // Slam!
359 item.EveryOnePermissions = itemUpd.EveryOnePermissions;
360 item.GroupPermissions = itemUpd.GroupPermissions;
361
362 item.GroupID = itemUpd.GroupID;
363 item.GroupOwned = itemUpd.GroupOwned;
364 item.CreationDate = itemUpd.CreationDate;
365 // The client sends zero if its newly created?
366
367 if (itemUpd.CreationDate == 0)
368 item.CreationDate = Util.UnixTimeSinceEpoch();
369 else
370 item.CreationDate = itemUpd.CreationDate;
371
372 // TODO: Check if folder changed and move item
373 //item.NextPermissions = itemUpd.Folder;
374 item.InvType = itemUpd.InvType;
375 item.SalePrice = itemUpd.SalePrice;
376 item.SaleType = itemUpd.SaleType;
377 item.Flags = itemUpd.Flags;
378
379 userInfo.UpdateItem(item);
380 }
381 else
382 {
383 IAgentAssetTransactions agentTransactions = this.RequestModuleInterface<IAgentAssetTransactions>();
384 if (agentTransactions != null)
385 {
386 agentTransactions.HandleItemUpdateFromTransaction(
387 remoteClient, transactionID, item);
388 }
389 }
390 }
391 else
392 {
393 m_log.Error(
394 "[AGENTINVENTORY]: Item ID " + itemID + " not found for an inventory item update.");
395 }
396 }
397 else
398 {
399 m_log.Error(
400 "[AGENT INVENTORY]: Agent ID " + remoteClient.AgentId + " not found for an inventory item update.");
401 }
402 }
403
404 /// <summary>
405 /// Give an inventory item from one user to another
406 /// </summary>
407 /// <param name="recipientClient"></param>
408 /// <param name="senderId">ID of the sender of the item</param>
409 /// <param name="itemId"></param>
410 public virtual void GiveInventoryItem(IClientAPI recipientClient, UUID senderId, UUID itemId)
411 {
412 InventoryItemBase itemCopy = GiveInventoryItem(recipientClient.AgentId, senderId, itemId);
413
414 if (itemCopy != null)
415 recipientClient.SendBulkUpdateInventory(itemCopy);
416 }
417
418 /// <summary>
419 /// Give an inventory item from one user to another
420 /// </summary>
421 /// <param name="recipient"></param>
422 /// <param name="senderId">ID of the sender of the item</param>
423 /// <param name="itemId"></param>
424 /// <returns>The inventory item copy given, null if the give was unsuccessful</returns>
425 public virtual InventoryItemBase GiveInventoryItem(UUID recipient, UUID senderId, UUID itemId)
426 {
427 return GiveInventoryItem(recipient, senderId, itemId, UUID.Zero);
428 }
429
430 /// <summary>
431 /// Give an inventory item from one user to another
432 /// </summary>
433 /// <param name="recipient"></param>
434 /// <param name="senderId">ID of the sender of the item</param>
435 /// <param name="itemId"></param>
436 /// <param name="recipientFolderId">
437 /// The id of the folder in which the copy item should go. If UUID.Zero then the item is placed in the most
438 /// appropriate default folder.
439 /// </param>
440 /// <returns>
441 /// The inventory item copy given, null if the give was unsuccessful
442 /// </returns>
443 public virtual InventoryItemBase GiveInventoryItem(
444 UUID recipient, UUID senderId, UUID itemId, UUID recipientFolderId)
445 {
446 // Retrieve the item from the sender
447 CachedUserInfo senderUserInfo = CommsManager.UserProfileCacheService.GetUserDetails(senderId);
448
449 if (senderUserInfo == null)
450 {
451 m_log.ErrorFormat(
452 "[AGENT INVENTORY]: Failed to find sending user {0} for item {1}", senderId, itemId);
453
454 return null;
455 }
456
457 if (senderUserInfo.RootFolder != null)
458 {
459 InventoryItemBase item = senderUserInfo.RootFolder.FindItem(itemId);
460
461 if (item != null)
462 {
463 if (!Permissions.BypassPermissions())
464 {
465 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
466 return null;
467 }
468
469 CachedUserInfo recipientUserInfo
470 = CommsManager.UserProfileCacheService.GetUserDetails(recipient);
471
472 if (recipientUserInfo != null)
473 {
474 if (!recipientUserInfo.HasReceivedInventory)
475 CommsManager.UserProfileCacheService.RequestInventoryForUser(recipient);
476
477 // Insert a copy of the item into the recipient
478 InventoryItemBase itemCopy = new InventoryItemBase();
479 itemCopy.Owner = recipient;
480 itemCopy.Creator = item.Creator;
481 itemCopy.ID = UUID.Random();
482 itemCopy.AssetID = item.AssetID;
483 itemCopy.Description = item.Description;
484 itemCopy.Name = item.Name;
485 itemCopy.AssetType = item.AssetType;
486 itemCopy.InvType = item.InvType;
487 itemCopy.Folder = recipientFolderId;
488
489 if (Permissions.PropagatePermissions())
490 {
491 if (item.InvType == 6)
492 {
493 itemCopy.BasePermissions &= ~(uint)(PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer);
494 itemCopy.BasePermissions |= (item.CurrentPermissions & 7) << 13;
495 }
496 else
497 {
498 itemCopy.BasePermissions = item.BasePermissions & item.NextPermissions;
499 }
500
501 itemCopy.CurrentPermissions = itemCopy.BasePermissions;
502 if ((item.CurrentPermissions & 8) != 0) // Propagate slam bit
503 {
504 itemCopy.BasePermissions &= item.NextPermissions;
505 itemCopy.CurrentPermissions = itemCopy.BasePermissions;
506 itemCopy.CurrentPermissions |= 8;
507 }
508
509 itemCopy.NextPermissions = item.NextPermissions;
510 itemCopy.EveryOnePermissions = item.EveryOnePermissions & item.NextPermissions;
511 itemCopy.GroupPermissions = item.GroupPermissions & item.NextPermissions;
512 }
513 else
514 {
515 itemCopy.CurrentPermissions = item.CurrentPermissions;
516 itemCopy.NextPermissions = item.NextPermissions;
517 itemCopy.EveryOnePermissions = item.EveryOnePermissions & item.NextPermissions;
518 itemCopy.GroupPermissions = item.GroupPermissions & item.NextPermissions;
519 itemCopy.BasePermissions = item.BasePermissions;
520 }
521 itemCopy.GroupID = UUID.Zero;
522 itemCopy.GroupOwned = false;
523 itemCopy.Flags = item.Flags;
524 itemCopy.SalePrice = item.SalePrice;
525 itemCopy.SaleType = item.SaleType;
526
527 itemCopy.CreationDate = item.CreationDate;
528
529 recipientUserInfo.AddItem(itemCopy);
530
531 if (!Permissions.BypassPermissions())
532 {
533 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
534 senderUserInfo.DeleteItem(itemId);
535 }
536
537 return itemCopy;
538 }
539 else
540 {
541 m_log.ErrorFormat(
542 "[AGENT INVENTORY]: Could not find userinfo for recipient user {0} of item {1}, {2} from {3}",
543 recipient, item.Name,
544 item.ID, senderId);
545 }
546 }
547 else
548 {
549 m_log.ErrorFormat(
550 "[AGENT INVENTORY]: Failed to find item {0} to give to {1}", itemId, senderId);
551
552 return null;
553 }
554 }
555 else
556 {
557 m_log.Error("[AGENT INVENTORY]: Failed to find item " + itemId.ToString() + ", no root folder");
558 return null;
559 }
560
561 return null;
562 }
563
564 /// <summary>
565 /// Give an entire inventory folder from one user to another. The entire contents (including all descendent
566 /// folders) is given.
567 /// </summary>
568 /// <param name="recipientId"></param>
569 /// <param name="senderId">ID of the sender of the item</param>
570 /// <param name="folderId"></param>
571 /// <param name="recipientParentFolderId">
572 /// The id of the receipient folder in which the send folder should be placed. If UUID.Zero then the
573 /// recipient folder is the root folder
574 /// </param>
575 /// <returns>
576 /// The inventory folder copy given, null if the copy was unsuccessful
577 /// </returns>
578 public virtual InventoryFolderImpl GiveInventoryFolder(
579 UUID recipientId, UUID senderId, UUID folderId, UUID recipientParentFolderId)
580 {
581 // Retrieve the folder from the sender
582 CachedUserInfo senderUserInfo = CommsManager.UserProfileCacheService.GetUserDetails(senderId);
583
584 if (null == senderUserInfo)
585 {
586 m_log.ErrorFormat(
587 "[AGENT INVENTORY]: Failed to find sending user {0} for folder {1}", senderId, folderId);
588
589 return null;
590 }
591
592 if (!senderUserInfo.HasReceivedInventory)
593 {
594 m_log.DebugFormat(
595 "[AGENT INVENTORY]: Could not give inventory folder - have not yet received inventory for {0}",
596 senderId);
597
598 return null;
599 }
600
601 InventoryFolderImpl folder = senderUserInfo.RootFolder.FindFolder(folderId);
602
603 if (null == folder)
604 {
605 m_log.ErrorFormat(
606 "[AGENT INVENTORY]: Could not find inventory folder {0} to give", folderId);
607
608 return null;
609 }
610
611 CachedUserInfo recipientUserInfo
612 = CommsManager.UserProfileCacheService.GetUserDetails(recipientId);
613
614 if (null == recipientUserInfo)
615 {
616 m_log.ErrorFormat(
617 "[AGENT INVENTORY]: Failed to find receiving user {0} for folder {1}", recipientId, folderId);
618
619 return null;
620 }
621
622 if (recipientParentFolderId == UUID.Zero)
623 recipientParentFolderId = recipientUserInfo.RootFolder.ID;
624
625 UUID newFolderId = UUID.Random();
626 recipientUserInfo.CreateFolder(folder.Name, newFolderId, (ushort)folder.Type, recipientParentFolderId);
627
628 // XXX: Messy - we should really get this back in the CreateFolder call
629 InventoryFolderImpl copiedFolder = recipientUserInfo.RootFolder.FindFolder(newFolderId);
630
631 // Give all the subfolders
632 List<InventoryFolderImpl> subFolders = folder.RequestListOfFolderImpls();
633 foreach (InventoryFolderImpl childFolder in subFolders)
634 {
635 GiveInventoryFolder(recipientId, senderId, childFolder.ID, copiedFolder.ID);
636 }
637
638 // Give all the items
639 List<InventoryItemBase> items = folder.RequestListOfItems();
640 foreach (InventoryItemBase item in items)
641 {
642 GiveInventoryItem(recipientId, senderId, item.ID, copiedFolder.ID);
643 }
644
645 return copiedFolder;
646 }
647
648 public void CopyInventoryItem(IClientAPI remoteClient, uint callbackID, UUID oldAgentID, UUID oldItemID,
649 UUID newFolderID, string newName)
650 {
651 m_log.DebugFormat(
652 "[AGENT INVENTORY]: CopyInventoryItem received by {0} with oldAgentID {1}, oldItemID {2}, new FolderID {3}, newName {4}",
653 remoteClient.AgentId, oldAgentID, oldItemID, newFolderID, newName);
654
655 InventoryItemBase item = CommsManager.UserProfileCacheService.LibraryRoot.FindItem(oldItemID);
656
657 if (item == null)
658 {
659 CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(oldAgentID);
660 if (userInfo == null)
661 {
662 m_log.Error("[AGENT INVENTORY]: Failed to find user " + oldAgentID.ToString());
663 return;
664 }
665
666 if (userInfo.RootFolder != null)
667 {
668 item = userInfo.RootFolder.FindItem(oldItemID);
669
670 if (item == null)
671 {
672 m_log.Error("[AGENT INVENTORY]: Failed to find item " + oldItemID.ToString());
673 return;
674 }
675 }
676 else
677 {
678 m_log.Error("[AGENT INVENTORY]: Failed to find item " + oldItemID.ToString());
679 return;
680 }
681 }
682
683 AssetBase asset
684 = AssetCache.GetAsset(
685 item.AssetID, (item.AssetType == (int)AssetType.Texture ? true : false));
686
687 if (asset != null)
688 {
689 if (newName != String.Empty)
690 {
691 asset.Metadata.Name = newName;
692 }
693 else
694 {
695 newName = item.Name;
696 }
697
698 if (remoteClient.AgentId == oldAgentID)
699 {
700 CreateNewInventoryItem(
701 remoteClient, newFolderID, newName, item.Flags, callbackID, asset, (sbyte)item.InvType,
702 item.BasePermissions, item.CurrentPermissions, item.EveryOnePermissions, item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
703 }
704 else
705 {
706 CreateNewInventoryItem(
707 remoteClient, newFolderID, newName, item.Flags, callbackID, asset, (sbyte)item.InvType,
708 item.NextPermissions, item.NextPermissions, item.EveryOnePermissions & item.NextPermissions, item.NextPermissions, item.GroupPermissions, Util.UnixTimeSinceEpoch());
709 }
710 }
711 else
712 {
713 m_log.ErrorFormat(
714 "[AGENT INVENTORY]: Could not copy item {0} since asset {1} could not be found",
715 item.Name, item.AssetID);
716 }
717 }
718
719 /// <summary>
720 /// Create a new asset data structure.
721 /// </summary>
722 /// <param name="name"></param>
723 /// <param name="description"></param>
724 /// <param name="invType"></param>
725 /// <param name="assetType"></param>
726 /// <param name="data"></param>
727 /// <returns></returns>
728 private AssetBase CreateAsset(string name, string description, sbyte assetType, byte[] data)
729 {
730 AssetBase asset = new AssetBase();
731 asset.Metadata.Name = name;
732 asset.Metadata.Description = description;
733 asset.Metadata.Type = assetType;
734 asset.Metadata.FullID = UUID.Random();
735 asset.Data = (data == null) ? new byte[1] : data;
736
737 return asset;
738 }
739
740 /// <summary>
741 /// Move an item within the agent's inventory.
742 /// </summary>
743 /// <param name="remoteClient"></param>
744 /// <param name="folderID"></param>
745 /// <param name="itemID"></param>
746 /// <param name="length"></param>
747 /// <param name="newName"></param>
748 public void MoveInventoryItem(IClientAPI remoteClient, UUID folderID, UUID itemID, int length,
749 string newName)
750 {
751 m_log.DebugFormat(
752 "[AGENT INVENTORY]: Moving item {0} to {1} for {2}", itemID, folderID, remoteClient.AgentId);
753
754 CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
755
756 if (userInfo == null)
757 {
758 m_log.Error("[AGENT INVENTORY]: Failed to find user " + remoteClient.AgentId.ToString());
759
760 return;
761 }
762
763 if (userInfo.RootFolder != null)
764 {
765 InventoryItemBase item = userInfo.RootFolder.FindItem(itemID);
766
767 if (item != null)
768 {
769 if (newName != String.Empty)
770 {
771 item.Name = newName;
772 }
773 item.Folder = folderID;
774
775 userInfo.DeleteItem(item.ID);
776
777 AddInventoryItem(remoteClient, item);
778 }
779 else
780 {
781 m_log.Error("[AGENT INVENTORY]: Failed to find item " + itemID.ToString());
782
783 return;
784 }
785 }
786 else
787 {
788 m_log.Error("[AGENT INVENTORY]: Failed to find item " + itemID.ToString() + ", no root folder");
789
790 return;
791 }
792 }
793
794 /// <summary>
795 /// Create a new inventory item.
796 /// </summary>
797 /// <param name="remoteClient"></param>
798 /// <param name="folderID"></param>
799 /// <param name="callbackID"></param>
800 /// <param name="asset"></param>
801 /// <param name="invType"></param>
802 /// <param name="nextOwnerMask"></param>
803 private void CreateNewInventoryItem(IClientAPI remoteClient, UUID folderID, string name, uint flags, uint callbackID,
804 AssetBase asset, sbyte invType, uint nextOwnerMask, int creationDate)
805 {
806 CreateNewInventoryItem(
807 remoteClient, folderID, name, flags, callbackID, asset, invType,
808 (uint)PermissionMask.All, (uint)PermissionMask.All, 0, nextOwnerMask, 0, creationDate);
809 }
810
811 /// <summary>
812 /// Create a new Inventory Item
813 /// </summary>
814 /// <param name="remoteClient"></param>
815 /// <param name="folderID"></param>
816 /// <param name="callbackID"></param>
817 /// <param name="asset"></param>
818 /// <param name="invType"></param>
819 /// <param name="nextOwnerMask"></param>
820 /// <param name="creationDate"></param>
821 private void CreateNewInventoryItem(
822 IClientAPI remoteClient, UUID folderID, string name, uint flags, uint callbackID, AssetBase asset, sbyte invType,
823 uint baseMask, uint currentMask, uint everyoneMask, uint nextOwnerMask, uint groupMask, int creationDate)
824 {
825 CachedUserInfo userInfo
826 = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
827
828 if (userInfo != null)
829 {
830 InventoryItemBase item = new InventoryItemBase();
831 item.Owner = remoteClient.AgentId;
832 item.Creator = remoteClient.AgentId;
833 item.ID = UUID.Random();
834 item.AssetID = asset.Metadata.FullID;
835 item.Description = asset.Metadata.Description;
836 item.Name = name;
837 item.Flags = flags;
838 item.AssetType = asset.Metadata.Type;
839 item.InvType = invType;
840 item.Folder = folderID;
841 item.CurrentPermissions = currentMask;
842 item.NextPermissions = nextOwnerMask;
843 item.EveryOnePermissions = everyoneMask;
844 item.GroupPermissions = groupMask;
845 item.BasePermissions = baseMask;
846 item.CreationDate = creationDate;
847
848 userInfo.AddItem(item);
849 remoteClient.SendInventoryItemCreateUpdate(item);
850 }
851 else
852 {
853 m_log.WarnFormat(
854 "No user details associated with client {0} uuid {1} in CreateNewInventoryItem!",
855 remoteClient.Name, remoteClient.AgentId);
856 }
857 }
858
859 /// <summary>
860 /// Create a new inventory item. Called when the client creates a new item directly within their
861 /// inventory (e.g. by selecting a context inventory menu option).
862 /// </summary>
863 /// <param name="remoteClient"></param>
864 /// <param name="transactionID"></param>
865 /// <param name="folderID"></param>
866 /// <param name="callbackID"></param>
867 /// <param name="description"></param>
868 /// <param name="name"></param>
869 /// <param name="invType"></param>
870 /// <param name="type"></param>
871 /// <param name="wearableType"></param>
872 /// <param name="nextOwnerMask"></param>
873 public void CreateNewInventoryItem(IClientAPI remoteClient, UUID transactionID, UUID folderID,
874 uint callbackID, string description, string name, sbyte invType,
875 sbyte assetType,
876 byte wearableType, uint nextOwnerMask, int creationDate)
877 {
878 m_log.DebugFormat("[AGENT INVENTORY]: Received request to create inventory item {0} in folder {1}", name, folderID);
879
880 if (!Permissions.CanCreateUserInventory(invType, remoteClient.AgentId))
881 return;
882
883 if (transactionID == UUID.Zero)
884 {
885 CachedUserInfo userInfo
886 = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
887
888 if (userInfo != null)
889 {
890 ScenePresence presence;
891 TryGetAvatar(remoteClient.AgentId, out presence);
892 byte[] data = null;
893
894 if (invType == 3 && presence != null) // OpenMetaverse.asset.assettype.landmark = 3 - needs to be turned into an enum
895 {
896 Vector3 pos = presence.AbsolutePosition;
897 string strdata = String.Format(
898 "Landmark version 2\nregion_id {0}\nlocal_pos {1} {2} {3}\nregion_handle {4}\n",
899 presence.Scene.RegionInfo.RegionID,
900 pos.X, pos.Y, pos.Z,
901 presence.RegionHandle);
902 data = Encoding.ASCII.GetBytes(strdata);
903 }
904
905 AssetBase asset = CreateAsset(name, description, assetType, data);
906 AssetCache.AddAsset(asset);
907
908 CreateNewInventoryItem(remoteClient, folderID, asset.Metadata.Name, 0, callbackID, asset, invType, nextOwnerMask, creationDate);
909 }
910 else
911 {
912 m_log.ErrorFormat(
913 "userInfo for agent uuid {0} unexpectedly null in CreateNewInventoryItem",
914 remoteClient.AgentId);
915 }
916 }
917 else
918 {
919 IAgentAssetTransactions agentTransactions = this.RequestModuleInterface<IAgentAssetTransactions>();
920 if (agentTransactions != null)
921 {
922 agentTransactions.HandleItemCreationFromTransaction(
923 remoteClient, transactionID, folderID, callbackID, description,
924 name, invType, assetType, wearableType, nextOwnerMask);
925 }
926 }
927 }
928
929 /// <summary>
930 /// Remove an inventory item for the client's inventory
931 /// </summary>
932 /// <param name="remoteClient"></param>
933 /// <param name="itemID"></param>
934 private void RemoveInventoryItem(IClientAPI remoteClient, UUID itemID)
935 {
936 CachedUserInfo userInfo
937 = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
938
939 if (userInfo == null)
940 {
941 m_log.WarnFormat(
942 "[AGENT INVENTORY]: Failed to find user {0} {1} to delete inventory item {2}",
943 remoteClient.Name, remoteClient.AgentId, itemID);
944
945 return;
946 }
947
948 userInfo.DeleteItem(itemID);
949 }
950
951 /// <summary>
952 /// Removes an inventory folder. Although there is a packet in the Linden protocol for this, it may be
953 /// legacy and not currently used (purge folder is used to remove folders from trash instead).
954 /// </summary>
955 /// <param name="remoteClient"></param>
956 /// <param name="folderID"></param>
957 private void RemoveInventoryFolder(IClientAPI remoteClient, UUID folderID)
958 {
959 CachedUserInfo userInfo
960 = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
961
962 if (userInfo == null)
963 {
964 m_log.Warn("[AGENT INVENTORY]: Failed to find user " + remoteClient.AgentId.ToString());
965 return;
966 }
967
968 if (userInfo.RootFolder != null)
969 {
970 InventoryItemBase folder = userInfo.RootFolder.FindItem(folderID);
971
972 if (folder != null)
973 {
974 m_log.WarnFormat(
975 "[AGENT INVENTORY]: Remove folder not implemented in request by {0} {1} for {2}",
976 remoteClient.Name, remoteClient.AgentId, folderID);
977
978 // doesn't work just yet, commented out. will fix in next patch.
979 // userInfo.DeleteItem(folder);
980 }
981 }
982 }
983
984 private SceneObjectGroup GetGroupByPrim(uint localID)
985 {
986 List<EntityBase> EntityList = GetEntities();
987
988 foreach (EntityBase ent in EntityList)
989 {
990 if (ent is SceneObjectGroup)
991 {
992 if (((SceneObjectGroup) ent).HasChildPrim(localID))
993 return (SceneObjectGroup) ent;
994 }
995 }
996 return null;
997 }
998
999 /// <summary>
1000 /// Send the details of a prim's inventory to the client.
1001 /// </summary>
1002 /// <param name="remoteClient"></param>
1003 /// <param name="primLocalID"></param>
1004 public void RequestTaskInventory(IClientAPI remoteClient, uint primLocalID)
1005 {
1006 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1007 if (group != null)
1008 {
1009 bool fileChange = group.GetPartInventoryFileName(remoteClient, primLocalID);
1010 if (fileChange)
1011 {
1012 if (XferManager != null)
1013 {
1014 group.RequestInventoryFile(remoteClient, primLocalID, XferManager);
1015 }
1016 }
1017 }
1018 else
1019 {
1020 m_log.ErrorFormat(
1021 "[PRIM INVENTORY]: Inventory requested of prim {0} which doesn't exist", primLocalID);
1022 }
1023 }
1024
1025 /// <summary>
1026 /// Remove an item from a prim (task) inventory
1027 /// </summary>
1028 /// <param name="remoteClient">Unused at the moment but retained since the avatar ID might
1029 /// be necessary for a permissions check at some stage.</param>
1030 /// <param name="itemID"></param>
1031 /// <param name="localID"></param>
1032 public void RemoveTaskInventory(IClientAPI remoteClient, UUID itemID, uint localID)
1033 {
1034 SceneObjectPart part = GetSceneObjectPart(localID);
1035 SceneObjectGroup group = part.ParentGroup;
1036 if (group != null)
1037 {
1038 TaskInventoryItem item = group.GetInventoryItem(localID, itemID);
1039 if (item == null)
1040 return;
1041
1042 if (item.Type == 10)
1043 {
1044 EventManager.TriggerRemoveScript(localID, itemID);
1045 }
1046 group.RemoveInventoryItem(localID, itemID);
1047 part.GetProperties(remoteClient);
1048 }
1049 else
1050 {
1051 m_log.ErrorFormat(
1052 "[PRIM INVENTORY]: " +
1053 "Removal of item {0} requested of prim {1} but this prim does not exist",
1054 itemID,
1055 localID);
1056 }
1057 }
1058
1059 private InventoryItemBase CreateAgentInventoryItemFromTask(UUID destAgent, SceneObjectPart part, UUID itemId)
1060 {
1061 TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId);
1062
1063 if (null == taskItem)
1064 {
1065 m_log.ErrorFormat(
1066 "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for creating an avatar"
1067 + " inventory item from a prim's inventory item "
1068 + " but the required item does not exist in the prim's inventory",
1069 itemId, part.Name, part.UUID);
1070
1071 return null;
1072 }
1073
1074 if ((destAgent != taskItem.OwnerID) && ((taskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0))
1075 {
1076 return null;
1077 }
1078
1079 InventoryItemBase agentItem = new InventoryItemBase();
1080
1081 agentItem.ID = UUID.Random();
1082 agentItem.Creator = taskItem.CreatorID;
1083 agentItem.Owner = destAgent;
1084 agentItem.AssetID = taskItem.AssetID;
1085 agentItem.Description = taskItem.Description;
1086 agentItem.Name = taskItem.Name;
1087 agentItem.AssetType = taskItem.Type;
1088 agentItem.InvType = taskItem.InvType;
1089 agentItem.Flags = taskItem.Flags;
1090
1091 if ((part.OwnerID != destAgent) && Permissions.PropagatePermissions())
1092 {
1093 if (taskItem.InvType == 6)
1094 agentItem.BasePermissions = taskItem.BasePermissions & ((taskItem.CurrentPermissions & 7) << 13);
1095 else
1096 agentItem.BasePermissions = taskItem.BasePermissions;
1097 agentItem.BasePermissions &= taskItem.NextPermissions;
1098 agentItem.CurrentPermissions = agentItem.BasePermissions | 8;
1099 agentItem.NextPermissions = taskItem.NextPermissions;
1100 agentItem.EveryOnePermissions = taskItem.EveryonePermissions & taskItem.NextPermissions;
1101 agentItem.GroupPermissions = taskItem.GroupPermissions & taskItem.NextPermissions;
1102 }
1103 else
1104 {
1105 agentItem.BasePermissions = taskItem.BasePermissions;
1106 agentItem.CurrentPermissions = taskItem.CurrentPermissions;
1107 agentItem.NextPermissions = taskItem.NextPermissions;
1108 agentItem.EveryOnePermissions = taskItem.EveryonePermissions;
1109 agentItem.GroupPermissions = taskItem.GroupPermissions;
1110 }
1111
1112 if (!Permissions.BypassPermissions())
1113 {
1114 if ((taskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1115 part.Inventory.RemoveInventoryItem(itemId);
1116 }
1117
1118 return agentItem;
1119 }
1120
1121 /// <summary>
1122 /// Move the given item in the given prim to a folder in the client's inventory
1123 /// </summary>
1124 /// <param name="remoteClient"></param>
1125 /// <param name="folderID"></param>
1126 /// <param name="part"></param>
1127 /// <param name="itemID"></param>
1128 public InventoryItemBase MoveTaskInventoryItem(IClientAPI remoteClient, UUID folderId, SceneObjectPart part, UUID itemId)
1129 {
1130 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(remoteClient.AgentId, part, itemId);
1131
1132 if (agentItem == null)
1133 return null;
1134
1135 agentItem.Folder = folderId;
1136 AddInventoryItem(remoteClient, agentItem);
1137 return agentItem;
1138 }
1139
1140 /// <summary>
1141 /// <see>ClientMoveTaskInventoryItem</see>
1142 /// </summary>
1143 /// <param name="remoteClient"></param>
1144 /// <param name="folderID"></param>
1145 /// <param name="primLocalID"></param>
1146 /// <param name="itemID"></param>
1147 public void ClientMoveTaskInventoryItem(IClientAPI remoteClient, UUID folderId, uint primLocalId, UUID itemId)
1148 {
1149 SceneObjectPart part = GetSceneObjectPart(primLocalId);
1150
1151 if (null == part)
1152 {
1153 m_log.WarnFormat(
1154 "[PRIM INVENTORY]: " +
1155 "Move of inventory item {0} from prim with local id {1} failed because the prim could not be found",
1156 itemId, primLocalId);
1157
1158 return;
1159 }
1160
1161 TaskInventoryItem taskItem = part.Inventory.GetInventoryItem(itemId);
1162
1163 if (null == taskItem)
1164 {
1165 m_log.WarnFormat("[PRIM INVENTORY]: Move of inventory item {0} from prim with local id {1} failed"
1166 + " because the inventory item could not be found",
1167 itemId, primLocalId);
1168
1169 return;
1170 }
1171
1172 // Only owner can copy
1173 if (remoteClient.AgentId != taskItem.OwnerID)
1174 return;
1175
1176 MoveTaskInventoryItem(remoteClient, folderId, part, itemId);
1177 }
1178
1179 /// <summary>
1180 /// <see>MoveTaskInventoryItem</see>
1181 /// </summary>
1182 /// <param name="remoteClient"></param>
1183 /// <param name="folderID"></param>
1184 /// <param name="part"></param>
1185 /// <param name="itemID"></param>
1186 public InventoryItemBase MoveTaskInventoryItem(UUID avatarId, UUID folderId, SceneObjectPart part, UUID itemId)
1187 {
1188 ScenePresence avatar;
1189
1190 if (TryGetAvatar(avatarId, out avatar))
1191 {
1192 return MoveTaskInventoryItem(avatar.ControllingClient, folderId, part, itemId);
1193 }
1194 else
1195 {
1196 CachedUserInfo profile = CommsManager.UserProfileCacheService.GetUserDetails(avatarId);
1197 if (profile == null || profile.RootFolder == null)
1198 {
1199 m_log.ErrorFormat(
1200 "[PRIM INVENTORY]: " +
1201 "Avatar {0} cannot be found to add item",
1202 avatarId);
1203 }
1204 if (!profile.HasReceivedInventory)
1205 CommsManager.UserProfileCacheService.RequestInventoryForUser(avatarId);
1206 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(avatarId, part, itemId);
1207
1208 if (agentItem == null)
1209 return null;
1210
1211 agentItem.Folder = folderId;
1212
1213 AddInventoryItem(avatarId, agentItem);
1214
1215 return agentItem;
1216 }
1217 }
1218
1219 /// <summary>
1220 /// Copy a task (prim) inventory item to another task (prim)
1221 /// </summary>
1222 /// <param name="destId"></param>
1223 /// <param name="part"></param>
1224 /// <param name="itemId"></param>
1225 public void MoveTaskInventoryItem(UUID destId, SceneObjectPart part, UUID itemId)
1226 {
1227 TaskInventoryItem srcTaskItem = part.Inventory.GetInventoryItem(itemId);
1228
1229 if (srcTaskItem == null)
1230 {
1231 m_log.ErrorFormat(
1232 "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for moving"
1233 + " but the item does not exist in this inventory",
1234 itemId, part.Name, part.UUID);
1235
1236 return;
1237 }
1238
1239 SceneObjectPart destPart = GetSceneObjectPart(destId);
1240
1241 if (destPart == null)
1242 {
1243 m_log.ErrorFormat(
1244 "[PRIM INVENTORY]: " +
1245 "Could not find prim for ID {0}",
1246 destId);
1247 return;
1248 }
1249
1250 // Can't transfer this
1251 //
1252 if ((part.OwnerID != destPart.OwnerID) && ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Transfer) == 0))
1253 return;
1254
1255 if (part.OwnerID != destPart.OwnerID && (part.GetEffectiveObjectFlags() & (uint)PrimFlags.AllowInventoryDrop) == 0)
1256 {
1257 // object cannot copy items to an object owned by a different owner
1258 // unless llAllowInventoryDrop has been called
1259
1260 return;
1261 }
1262
1263 // must have both move and modify permission to put an item in an object
1264 if ((part.OwnerMask & ((uint)PermissionMask.Move | (uint)PermissionMask.Modify)) == 0)
1265 {
1266 return;
1267 }
1268
1269 TaskInventoryItem destTaskItem = new TaskInventoryItem();
1270
1271 destTaskItem.ItemID = UUID.Random();
1272 destTaskItem.CreatorID = srcTaskItem.CreatorID;
1273 destTaskItem.AssetID = srcTaskItem.AssetID;
1274 destTaskItem.GroupID = destPart.GroupID;
1275 destTaskItem.OwnerID = destPart.OwnerID;
1276 destTaskItem.ParentID = destPart.UUID;
1277 destTaskItem.ParentPartID = destPart.UUID;
1278
1279 destTaskItem.BasePermissions = srcTaskItem.BasePermissions;
1280 destTaskItem.EveryonePermissions = srcTaskItem.EveryonePermissions;
1281 destTaskItem.GroupPermissions = srcTaskItem.GroupPermissions;
1282 destTaskItem.CurrentPermissions = srcTaskItem.CurrentPermissions;
1283 destTaskItem.NextPermissions = srcTaskItem.NextPermissions;
1284 destTaskItem.Flags = srcTaskItem.Flags;
1285
1286 if (destPart.OwnerID != part.OwnerID)
1287 {
1288 if (Permissions.PropagatePermissions())
1289 {
1290 destTaskItem.CurrentPermissions = srcTaskItem.CurrentPermissions &
1291 srcTaskItem.NextPermissions;
1292 destTaskItem.GroupPermissions = srcTaskItem.GroupPermissions &
1293 srcTaskItem.NextPermissions;
1294 destTaskItem.EveryonePermissions = srcTaskItem.EveryonePermissions &
1295 srcTaskItem.NextPermissions;
1296 destTaskItem.BasePermissions = srcTaskItem.BasePermissions &
1297 srcTaskItem.NextPermissions;
1298 destTaskItem.CurrentPermissions |= 8; // Slam!
1299 }
1300 }
1301
1302 destTaskItem.Description = srcTaskItem.Description;
1303 destTaskItem.Name = srcTaskItem.Name;
1304 destTaskItem.InvType = srcTaskItem.InvType;
1305 destTaskItem.Type = srcTaskItem.Type;
1306
1307 destPart.Inventory.AddInventoryItem(destTaskItem, part.OwnerID != destPart.OwnerID);
1308
1309 if ((srcTaskItem.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1310 part.Inventory.RemoveInventoryItem(itemId);
1311
1312 ScenePresence avatar;
1313
1314 if (TryGetAvatar(srcTaskItem.OwnerID, out avatar))
1315 {
1316 destPart.GetProperties(avatar.ControllingClient);
1317 }
1318 }
1319
1320 public UUID MoveTaskInventoryItems(UUID destID, string category, SceneObjectPart host, List<UUID> items)
1321 {
1322 CachedUserInfo profile = CommsManager.UserProfileCacheService.GetUserDetails(destID);
1323 if (profile == null || profile.RootFolder == null)
1324 {
1325 m_log.ErrorFormat(
1326 "[PRIM INVENTORY]: " +
1327 "Avatar {0} cannot be found to add items",
1328 destID);
1329 return UUID.Zero;
1330 }
1331
1332 UUID newFolderID = UUID.Random();
1333
1334 profile.CreateFolder(category, newFolderID, 0xffff, profile.RootFolder.ID);
1335
1336 foreach (UUID itemID in items)
1337 {
1338 InventoryItemBase agentItem = CreateAgentInventoryItemFromTask(destID, host, itemID);
1339
1340 if (agentItem != null)
1341 {
1342 agentItem.Folder = newFolderID;
1343
1344 AddInventoryItem(destID, agentItem);
1345 }
1346 }
1347
1348 ScenePresence avatar;
1349
1350 if (TryGetAvatar(destID, out avatar))
1351 {
1352 profile.SendInventoryDecendents(avatar.ControllingClient,
1353 profile.RootFolder.ID, true, false);
1354 profile.SendInventoryDecendents(avatar.ControllingClient,
1355 newFolderID, false, true);
1356 }
1357
1358 return newFolderID;
1359 }
1360
1361 /// <summary>
1362 /// Update an item in a prim (task) inventory.
1363 /// This method does not handle scripts, <see>RezScript(IClientAPI, UUID, unit)</see>
1364 /// </summary>
1365 /// <param name="remoteClient"></param>
1366 /// <param name="transactionID"></param>
1367 /// <param name="itemInfo"></param>
1368 /// <param name="primLocalID"></param>
1369 public void UpdateTaskInventory(IClientAPI remoteClient, UUID transactionID, TaskInventoryItem itemInfo,
1370 uint primLocalID)
1371 {
1372 UUID itemID = itemInfo.ItemID;
1373
1374 // Find the prim we're dealing with
1375 SceneObjectPart part = GetSceneObjectPart(primLocalID);
1376
1377 if (part != null)
1378 {
1379 TaskInventoryItem currentItem = part.Inventory.GetInventoryItem(itemID);
1380 bool allowInventoryDrop = (part.GetEffectiveObjectFlags()
1381 & (uint)PrimFlags.AllowInventoryDrop) != 0;
1382
1383 // Explicity allow anyone to add to the inventory if the
1384 // AllowInventoryDrop flag has been set. Don't however let
1385 // them update an item unless they pass the external checks
1386 //
1387 if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId)
1388 && (currentItem != null || !allowInventoryDrop))
1389 return;
1390
1391 if (currentItem == null)
1392 {
1393 UUID copyID = UUID.Random();
1394 if (itemID != UUID.Zero)
1395 {
1396 CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
1397
1398 if (userInfo != null && userInfo.RootFolder != null)
1399 {
1400 InventoryItemBase item = userInfo.RootFolder.FindItem(itemID);
1401
1402 // Try library
1403 // XXX clumsy, possibly should be one call
1404 if (null == item)
1405 {
1406 item = CommsManager.UserProfileCacheService.LibraryRoot.FindItem(itemID);
1407 }
1408
1409 if (item != null)
1410 {
1411 part.ParentGroup.AddInventoryItem(remoteClient, primLocalID, item, copyID);
1412 m_log.InfoFormat(
1413 "[PRIM INVENTORY]: Update with item {0} requested of prim {1} for {2}",
1414 item.Name, primLocalID, remoteClient.Name);
1415 part.GetProperties(remoteClient);
1416 if (!Permissions.BypassPermissions())
1417 {
1418 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
1419 RemoveInventoryItem(remoteClient, itemID);
1420 }
1421 }
1422 else
1423 {
1424 m_log.ErrorFormat(
1425 "[PRIM INVENTORY]: Could not find inventory item {0} to update for {1}!",
1426 itemID, remoteClient.Name);
1427 }
1428 }
1429 }
1430 }
1431 else // Updating existing item with new perms etc
1432 {
1433 IAgentAssetTransactions agentTransactions = this.RequestModuleInterface<IAgentAssetTransactions>();
1434 if (agentTransactions != null)
1435 {
1436 agentTransactions.HandleTaskItemUpdateFromTransaction(
1437 remoteClient, part, transactionID, currentItem);
1438 }
1439 if (part.Inventory.UpdateInventoryItem(itemInfo))
1440 part.GetProperties(remoteClient);
1441 }
1442 }
1443 else
1444 {
1445 m_log.WarnFormat(
1446 "[PRIM INVENTORY]: " +
1447 "Update with item {0} requested of prim {1} for {2} but this prim does not exist",
1448 itemID, primLocalID, remoteClient.Name);
1449 }
1450 }
1451
1452 /// <summary>
1453 /// Rez a script into a prim's inventory, either ex nihilo or from an existing avatar inventory
1454 /// </summary>
1455 /// <param name="remoteClient"></param>
1456 /// <param name="itemID"> </param>
1457 /// <param name="localID"></param>
1458 public void RezScript(IClientAPI remoteClient, InventoryItemBase itemBase, UUID transactionID, uint localID)
1459 {
1460 UUID itemID = itemBase.ID;
1461 UUID copyID = UUID.Random();
1462
1463 if (itemID != UUID.Zero) // transferred from an avatar inventory to the prim's inventory
1464 {
1465 CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
1466
1467 if (userInfo != null && userInfo.RootFolder != null)
1468 {
1469 InventoryItemBase item = userInfo.RootFolder.FindItem(itemID);
1470
1471 // Try library
1472 // XXX clumsy, possibly should be one call
1473 if (null == item)
1474 {
1475 item = CommsManager.UserProfileCacheService.LibraryRoot.FindItem(itemID);
1476 }
1477
1478 if (item != null)
1479 {
1480 SceneObjectPart part = GetSceneObjectPart(localID);
1481 if (part != null)
1482 {
1483 if (!Permissions.CanEditObjectInventory(part.UUID, remoteClient.AgentId))
1484 return;
1485
1486 part.ParentGroup.AddInventoryItem(remoteClient, localID, item, copyID);
1487 // TODO: switch to posting on_rez here when scripts
1488 // have state in inventory
1489 part.Inventory.CreateScriptInstance(copyID, 0, false, DefaultScriptEngine, 0);
1490
1491 // m_log.InfoFormat("[PRIMINVENTORY]: " +
1492 // "Rezzed script {0} into prim local ID {1} for user {2}",
1493 // item.inventoryName, localID, remoteClient.Name);
1494 part.GetProperties(remoteClient);
1495 }
1496 else
1497 {
1498 m_log.ErrorFormat(
1499 "[PRIM INVENTORY]: " +
1500 "Could not rez script {0} into prim local ID {1} for user {2}"
1501 + " because the prim could not be found in the region!",
1502 item.Name, localID, remoteClient.Name);
1503 }
1504 }
1505 else
1506 {
1507 m_log.ErrorFormat(
1508 "[PRIM INVENTORY]: Could not find script inventory item {0} to rez for {1}!",
1509 itemID, remoteClient.Name);
1510 }
1511 }
1512 }
1513 else // script has been rezzed directly into a prim's inventory
1514 {
1515 SceneObjectPart part = GetSceneObjectPart(itemBase.Folder);
1516 if (part == null)
1517 return;
1518
1519 if (part.OwnerID != remoteClient.AgentId)
1520 return;
1521
1522 if ((part.OwnerMask & (uint)PermissionMask.Modify) == 0)
1523 return;
1524
1525 if (!Permissions.CanCreateObjectInventory(
1526 itemBase.InvType, part.UUID, remoteClient.AgentId))
1527 return;
1528
1529 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}"));
1530 AssetCache.AddAsset(asset);
1531
1532 TaskInventoryItem taskItem = new TaskInventoryItem();
1533
1534 taskItem.ResetIDs(itemBase.Folder);
1535 taskItem.ParentID = itemBase.Folder;
1536 taskItem.CreationDate = (uint)itemBase.CreationDate;
1537 taskItem.Name = itemBase.Name;
1538 taskItem.Description = itemBase.Description;
1539 taskItem.Type = itemBase.AssetType;
1540 taskItem.InvType = itemBase.InvType;
1541 taskItem.OwnerID = itemBase.Owner;
1542 taskItem.CreatorID = itemBase.Creator;
1543 taskItem.BasePermissions = itemBase.BasePermissions;
1544 taskItem.CurrentPermissions = itemBase.CurrentPermissions;
1545 taskItem.EveryonePermissions = itemBase.EveryOnePermissions;
1546 taskItem.GroupPermissions = itemBase.GroupPermissions;
1547 taskItem.NextPermissions = itemBase.NextPermissions;
1548 taskItem.GroupID = itemBase.GroupID;
1549 taskItem.GroupPermissions = 0;
1550 taskItem.Flags = itemBase.Flags;
1551 taskItem.PermsGranter = UUID.Zero;
1552 taskItem.PermsMask = 0;
1553 taskItem.AssetID = asset.Metadata.FullID;
1554
1555 part.Inventory.AddInventoryItem(taskItem, false);
1556 part.GetProperties(remoteClient);
1557
1558 part.Inventory.CreateScriptInstance(taskItem, 0, false, DefaultScriptEngine, 0);
1559 }
1560 }
1561
1562 /// <summary>
1563 /// Rez a script into a prim's inventory from another prim
1564 /// </summary>
1565 /// <param name="remoteClient"></param>
1566 /// <param name="itemID"> </param>
1567 /// <param name="localID"></param>
1568 public void RezScript(UUID srcId, SceneObjectPart srcPart, UUID destId, int pin, int running, int start_param)
1569 {
1570 TaskInventoryItem srcTaskItem = srcPart.Inventory.GetInventoryItem(srcId);
1571
1572 if (srcTaskItem == null)
1573 {
1574 m_log.ErrorFormat(
1575 "[PRIM INVENTORY]: Tried to retrieve item ID {0} from prim {1}, {2} for rezzing a script but the "
1576 + " item does not exist in this inventory",
1577 srcId, srcPart.Name, srcPart.UUID);
1578
1579 return;
1580 }
1581
1582 SceneObjectPart destPart = GetSceneObjectPart(destId);
1583
1584 if (destPart == null)
1585 {
1586 m_log.ErrorFormat(
1587 "[PRIM INVENTORY]: " +
1588 "Could not find script for ID {0}",
1589 destId);
1590 return;
1591 }
1592
1593 // Must own the object, and have modify rights
1594 if (srcPart.OwnerID != destPart.OwnerID)
1595 return;
1596
1597 if ((destPart.OwnerMask & (uint)PermissionMask.Modify) == 0)
1598 return;
1599
1600 if (destPart.ScriptAccessPin != pin)
1601 {
1602 m_log.WarnFormat(
1603 "[PRIM INVENTORY]: " +
1604 "Script in object {0} : {1}, attempted to load script {2} : {3} into object {4} : {5} with invalid pin {6}",
1605 srcPart.Name, srcId, srcTaskItem.Name, srcTaskItem.ItemID, destPart.Name, destId, pin);
1606 // the LSL Wiki says we are supposed to shout on the DEBUG_CHANNEL -
1607 // "Object: Task Object trying to illegally load script onto task Other_Object!"
1608 // How do we shout from in here?
1609 return;
1610 }
1611
1612 TaskInventoryItem destTaskItem = new TaskInventoryItem();
1613
1614 destTaskItem.ItemID = UUID.Random();
1615 destTaskItem.CreatorID = srcTaskItem.CreatorID;
1616 destTaskItem.AssetID = srcTaskItem.AssetID;
1617 destTaskItem.GroupID = destPart.GroupID;
1618 destTaskItem.OwnerID = destPart.OwnerID;
1619 destTaskItem.ParentID = destPart.UUID;
1620 destTaskItem.ParentPartID = destPart.UUID;
1621
1622 destTaskItem.BasePermissions = srcTaskItem.BasePermissions;
1623 destTaskItem.EveryonePermissions = srcTaskItem.EveryonePermissions;
1624 destTaskItem.GroupPermissions = srcTaskItem.GroupPermissions;
1625 destTaskItem.CurrentPermissions = srcTaskItem.CurrentPermissions;
1626 destTaskItem.NextPermissions = srcTaskItem.NextPermissions;
1627 destTaskItem.Flags = srcTaskItem.Flags;
1628
1629 if (destPart.OwnerID != srcPart.OwnerID)
1630 {
1631 if (Permissions.PropagatePermissions())
1632 {
1633 destTaskItem.CurrentPermissions = srcTaskItem.CurrentPermissions &
1634 srcTaskItem.NextPermissions;
1635 destTaskItem.GroupPermissions = srcTaskItem.GroupPermissions &
1636 srcTaskItem.NextPermissions;
1637 destTaskItem.EveryonePermissions = srcTaskItem.EveryonePermissions &
1638 srcTaskItem.NextPermissions;
1639 destTaskItem.BasePermissions = srcTaskItem.BasePermissions &
1640 srcTaskItem.NextPermissions;
1641 destTaskItem.CurrentPermissions |= 8; // Slam!
1642 }
1643 }
1644
1645 destTaskItem.Description = srcTaskItem.Description;
1646 destTaskItem.Name = srcTaskItem.Name;
1647 destTaskItem.InvType = srcTaskItem.InvType;
1648 destTaskItem.Type = srcTaskItem.Type;
1649
1650 destPart.Inventory.AddInventoryItemExclusive(destTaskItem, false);
1651
1652 if (running > 0)
1653 {
1654 destPart.Inventory.CreateScriptInstance(destTaskItem, 0, false, DefaultScriptEngine, 0);
1655 }
1656
1657 ScenePresence avatar;
1658
1659 if (TryGetAvatar(srcTaskItem.OwnerID, out avatar))
1660 {
1661 destPart.GetProperties(avatar.ControllingClient);
1662 }
1663 }
1664
1665 /// <summary>
1666 /// Called when an object is removed from the environment into inventory.
1667 /// </summary>
1668 /// <param name="remoteClient"></param>
1669 /// <param name="localID"></param>
1670 /// <param name="groupID"></param>
1671 /// <param name="action"></param>
1672 /// <param name="destinationID"></param>
1673 public virtual void DeRezObject(IClientAPI remoteClient, uint localID,
1674 UUID groupID, DeRezAction action, UUID destinationID)
1675 {
1676 SceneObjectPart part = GetSceneObjectPart(localID);
1677 if (part == null)
1678 return;
1679
1680 if (part.ParentGroup == null || part.ParentGroup.IsDeleted)
1681 return;
1682
1683 // Can't delete child prims
1684 if (part != part.ParentGroup.RootPart)
1685 return;
1686
1687 SceneObjectGroup grp = part.ParentGroup;
1688
1689 //force a database backup/update on this SceneObjectGroup
1690 //So that we know the database is upto date, for when deleting the object from it
1691 ForceSceneObjectBackup(grp);
1692
1693 bool permissionToTake = false;
1694 bool permissionToDelete = false;
1695
1696 if (action == DeRezAction.SaveToExistingUserInventoryItem)
1697 {
1698 if (grp.OwnerID == remoteClient.AgentId && grp.RootPart.FromUserInventoryItemID != UUID.Zero)
1699 {
1700 permissionToTake = true;
1701 permissionToDelete = false;
1702 }
1703 }
1704 else if (action == DeRezAction.TakeCopy)
1705 {
1706 permissionToTake =
1707 Permissions.CanTakeCopyObject(
1708 grp.UUID,
1709 remoteClient.AgentId);
1710 }
1711 else if (action == DeRezAction.GodTakeCopy)
1712 {
1713 permissionToTake =
1714 Permissions.IsGod(
1715 remoteClient.AgentId);
1716 }
1717 else if (action == DeRezAction.Take)
1718 {
1719 permissionToTake =
1720 Permissions.CanTakeObject(
1721 grp.UUID,
1722 remoteClient.AgentId);
1723
1724 //If they can take, they can delete!
1725 permissionToDelete = permissionToTake;
1726 }
1727 else if (action == DeRezAction.Delete)
1728 {
1729 permissionToTake =
1730 Permissions.CanDeleteObject(
1731 grp.UUID,
1732 remoteClient.AgentId);
1733 permissionToDelete = permissionToTake;
1734 }
1735 else if (action == DeRezAction.Return)
1736 {
1737 if (remoteClient != null)
1738 {
1739 permissionToTake =
1740 Permissions.CanReturnObject(
1741 grp.UUID,
1742 remoteClient.AgentId);
1743 permissionToDelete = permissionToTake;
1744
1745 if (permissionToDelete)
1746 {
1747 AddReturn(grp.OwnerID, grp.Name, grp.AbsolutePosition, "parcel owner return");
1748 }
1749 }
1750 else // Auto return passes through here with null agent
1751 {
1752 permissionToTake = true;
1753 permissionToDelete = true;
1754 }
1755 }
1756 else
1757 {
1758 m_log.DebugFormat(
1759 "[AGENT INVENTORY]: Ignoring unexpected derez action {0} for {1}", action, remoteClient.Name);
1760 return;
1761 }
1762
1763 if (permissionToTake)
1764 {
1765 m_asyncSceneObjectDeleter.DeleteToInventory(
1766 action, destinationID, grp, remoteClient,
1767 permissionToDelete);
1768 }
1769 else if (permissionToDelete)
1770 {
1771 DeleteSceneObject(grp, false);
1772 }
1773 }
1774
1775 private bool WaitForInventory(CachedUserInfo info)
1776 {
1777 // 200 Seconds wait. This is called in the context of the
1778 // background delete thread, so we can afford to waste time
1779 // here.
1780 //
1781 int count = 200;
1782
1783 while (count > 0)
1784 {
1785 System.Threading.Thread.Sleep(100);
1786 count--;
1787 if (info.HasReceivedInventory)
1788 return true;
1789 }
1790 m_log.DebugFormat("Timed out waiting for inventory of user {0}",
1791 info.UserProfile.ID.ToString());
1792 return false;
1793 }
1794
1795 /// <summary>
1796 /// Delete a scene object from a scene and place in the given avatar's inventory.
1797 /// Returns the UUID of the newly created asset.
1798 /// </summary>
1799 /// <param name="action"></param>
1800 /// <param name="folderID"></param>
1801 /// <param name="objectGroup"></param>
1802 /// <param name="remoteClient"> </param>
1803 public virtual UUID DeleteToInventory(DeRezAction action, UUID folderID,
1804 SceneObjectGroup objectGroup, IClientAPI remoteClient)
1805 {
1806 UUID assetID = UUID.Zero;
1807
1808 string sceneObjectXml = objectGroup.ToXmlString();
1809
1810 // Get the user info of the item destination
1811 //
1812 CachedUserInfo userInfo;
1813
1814 if (action == DeRezAction.Take || action == DeRezAction.TakeCopy ||
1815 action == DeRezAction.SaveToExistingUserInventoryItem)
1816 {
1817 // Take or take copy require a taker
1818 // Saving changes requires a local user
1819 //
1820 if (remoteClient == null)
1821 return UUID.Zero;
1822
1823 userInfo = CommsManager.UserProfileCacheService.GetUserDetails(
1824 remoteClient.AgentId);
1825 }
1826 else
1827 {
1828 // All returns / deletes go to the object owner
1829 //
1830 userInfo = CommsManager.UserProfileCacheService.GetUserDetails(
1831 objectGroup.RootPart.OwnerID);
1832 }
1833
1834 if (userInfo == null) // Can't proceed
1835 {
1836 return UUID.Zero;
1837 }
1838
1839 if (!userInfo.HasReceivedInventory)
1840 {
1841 // Async inventory requests will queue, but they will never
1842 // execute unless inventory is actually fetched
1843 //
1844 CommsManager.UserProfileCacheService.RequestInventoryForUser(
1845 userInfo.UserProfile.ID);
1846 }
1847
1848 if (userInfo != null)
1849 {
1850 // If we're returning someone's item, it goes back to the
1851 // owner's Lost And Found folder.
1852 // Delete is treated like return in this case
1853 // Deleting your own items makes them go to trash
1854 //
1855
1856 InventoryFolderBase folder = null;
1857 InventoryItemBase item = null;
1858
1859 if (DeRezAction.SaveToExistingUserInventoryItem == action)
1860 {
1861 item = userInfo.RootFolder.FindItem(
1862 objectGroup.RootPart.FromUserInventoryItemID);
1863
1864 if (null == item)
1865 {
1866 m_log.DebugFormat(
1867 "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.",
1868 objectGroup.Name, objectGroup.UUID);
1869 return UUID.Zero;
1870 }
1871 }
1872 else
1873 {
1874 // Folder magic
1875 //
1876 if (action == DeRezAction.Delete)
1877 {
1878 // Deleting someone else's item
1879 //
1880 if (remoteClient == null ||
1881 objectGroup.OwnerID != remoteClient.AgentId)
1882 {
1883 // Folder skeleton may not be loaded and we
1884 // have to wait for the inventory to find
1885 // the destination folder
1886 //
1887 if (!WaitForInventory(userInfo))
1888 return UUID.Zero;
1889 folder = userInfo.FindFolderForType(
1890 (int)AssetType.LostAndFoundFolder);
1891 }
1892 else
1893 {
1894 // Assume inventory skeleton was loaded during login
1895 // and all folders can be found
1896 //
1897 folder = userInfo.FindFolderForType(
1898 (int)AssetType.TrashFolder);
1899 }
1900 }
1901 else if (action == DeRezAction.Return)
1902 {
1903 // Wait if needed
1904 //
1905 if (!userInfo.HasReceivedInventory)
1906 {
1907 if (!WaitForInventory(userInfo))
1908 return UUID.Zero;
1909 }
1910
1911 // Dump to lost + found unconditionally
1912 //
1913 folder = userInfo.FindFolderForType(
1914 (int)AssetType.LostAndFoundFolder);
1915 }
1916
1917 if (folderID == UUID.Zero && folder == null)
1918 {
1919 // Catch all. Use lost & found
1920 //
1921 if (!userInfo.HasReceivedInventory)
1922 {
1923 if (!WaitForInventory(userInfo))
1924 return UUID.Zero;
1925 }
1926
1927 folder = userInfo.FindFolderForType(
1928 (int)AssetType.LostAndFoundFolder);
1929 }
1930
1931 if (folder == null) // None of the above
1932 {
1933 folder = userInfo.RootFolder.FindFolder(folderID);
1934
1935 if (folder == null) // Nowhere to put it
1936 {
1937 return UUID.Zero;
1938 }
1939 }
1940
1941 item = new InventoryItemBase();
1942 item.Creator = objectGroup.RootPart.CreatorID;
1943 item.ID = UUID.Random();
1944 item.InvType = (int)InventoryType.Object;
1945 item.Folder = folder.ID;
1946 item.Owner = userInfo.UserProfile.ID;
1947
1948 }
1949
1950 AssetBase asset = CreateAsset(
1951 objectGroup.GetPartName(objectGroup.RootPart.LocalId),
1952 objectGroup.GetPartDescription(objectGroup.RootPart.LocalId),
1953 (sbyte)AssetType.Object,
1954 Utils.StringToBytes(sceneObjectXml));
1955 AssetCache.AddAsset(asset);
1956 assetID = asset.Metadata.FullID;
1957
1958 if (DeRezAction.SaveToExistingUserInventoryItem == action)
1959 {
1960 item.AssetID = asset.Metadata.FullID;
1961 userInfo.UpdateItem(item);
1962 }
1963 else
1964 {
1965 item.AssetID = asset.Metadata.FullID;
1966
1967 if (remoteClient != null && (remoteClient.AgentId != objectGroup.RootPart.OwnerID) && Permissions.PropagatePermissions())
1968 {
1969 uint perms=objectGroup.GetEffectivePermissions();
1970 uint nextPerms=(perms & 7) << 13;
1971 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
1972 perms &= ~(uint)PermissionMask.Copy;
1973 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
1974 perms &= ~(uint)PermissionMask.Transfer;
1975 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
1976 perms &= ~(uint)PermissionMask.Modify;
1977
1978 item.BasePermissions = perms & objectGroup.RootPart.NextOwnerMask;
1979 item.CurrentPermissions = item.BasePermissions;
1980 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
1981 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask & objectGroup.RootPart.NextOwnerMask;
1982 item.GroupPermissions = objectGroup.RootPart.GroupMask & objectGroup.RootPart.NextOwnerMask;
1983 item.CurrentPermissions |= 8; // Slam!
1984 }
1985 else
1986 {
1987 item.BasePermissions = objectGroup.GetEffectivePermissions();
1988 item.CurrentPermissions = objectGroup.GetEffectivePermissions();
1989 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
1990 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask;
1991 item.GroupPermissions = objectGroup.RootPart.GroupMask;
1992
1993 item.CurrentPermissions |= 8; // Slam!
1994 }
1995
1996 // TODO: add the new fields (Flags, Sale info, etc)
1997 item.CreationDate = Util.UnixTimeSinceEpoch();
1998 item.Description = asset.Metadata.Description;
1999 item.Name = asset.Metadata.Name;
2000 item.AssetType = asset.Metadata.Type;
2001
2002 userInfo.AddItem(item);
2003
2004 if (remoteClient != null && item.Owner == remoteClient.AgentId)
2005 {
2006 remoteClient.SendInventoryItemCreateUpdate(item);
2007 }
2008 else
2009 {
2010 ScenePresence notifyUser = GetScenePresence(item.Owner);
2011 if (notifyUser != null)
2012 {
2013 notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item);
2014 }
2015 }
2016 }
2017 }
2018
2019 return assetID;
2020 }
2021
2022 public void updateKnownAsset(IClientAPI remoteClient, SceneObjectGroup grp, UUID assetID, UUID agentID)
2023 {
2024 SceneObjectGroup objectGroup = grp;
2025 if (objectGroup != null)
2026 {
2027 if (!grp.HasGroupChanged)
2028 {
2029 m_log.InfoFormat("[ATTACHMENT]: Save request for {0} which is unchanged", grp.UUID);
2030 return;
2031 }
2032
2033 m_log.InfoFormat(
2034 "[ATTACHMENT]: Updating asset for attachment {0}, attachpoint {1}",
2035 grp.UUID, grp.GetAttachmentPoint());
2036
2037 string sceneObjectXml = objectGroup.ToXmlString();
2038
2039 CachedUserInfo userInfo =
2040 CommsManager.UserProfileCacheService.GetUserDetails(agentID);
2041 if (userInfo != null && userInfo.RootFolder != null)
2042 {
2043 Queue<InventoryFolderImpl> searchfolders = new Queue<InventoryFolderImpl>();
2044 searchfolders.Enqueue(userInfo.RootFolder);
2045
2046 UUID foundFolder = UUID.Zero;
2047 InventoryItemBase item = null;
2048
2049 // search through folders to find the asset.
2050 while (searchfolders.Count > 0)
2051 {
2052 InventoryFolderImpl fld = searchfolders.Dequeue();
2053 lock (fld)
2054 {
2055 if (fld != null)
2056 {
2057 if (fld.Items.ContainsKey(assetID))
2058 {
2059 item = fld.Items[assetID];
2060 foundFolder = fld.ID;
2061 searchfolders.Clear();
2062 break;
2063 }
2064 else
2065 {
2066 foreach (InventoryFolderImpl subfld in fld.RequestListOfFolderImpls())
2067 {
2068 searchfolders.Enqueue(subfld);
2069 }
2070 }
2071 }
2072 }
2073 }
2074
2075 if (foundFolder != UUID.Zero && item != null)
2076 {
2077 AssetBase asset = CreateAsset(
2078 objectGroup.GetPartName(objectGroup.LocalId),
2079 objectGroup.GetPartDescription(objectGroup.LocalId),
2080 (sbyte)AssetType.Object,
2081 Utils.StringToBytes(sceneObjectXml));
2082 AssetCache.AddAsset(asset);
2083
2084 item.AssetID = asset.Metadata.FullID;
2085 item.Description = asset.Metadata.Description;
2086 item.Name = asset.Metadata.Name;
2087 item.AssetType = asset.Metadata.Type;
2088 item.InvType = (int)InventoryType.Object;
2089 item.Folder = foundFolder;
2090
2091 userInfo.UpdateItem(item);
2092
2093 // this gets called when the agent loggs off!
2094 if (remoteClient != null)
2095 {
2096 remoteClient.SendInventoryItemCreateUpdate(item);
2097 }
2098 }
2099 }
2100 }
2101 }
2102
2103 public UUID attachObjectAssetStore(IClientAPI remoteClient, SceneObjectGroup grp, UUID AgentId, out UUID itemID)
2104 {
2105 itemID = UUID.Zero;
2106 if (grp != null)
2107 {
2108 string sceneObjectXml = grp.ToXmlString();
2109
2110 CachedUserInfo userInfo =
2111 CommsManager.UserProfileCacheService.GetUserDetails(AgentId);
2112 if (userInfo != null)
2113 {
2114 AssetBase asset = CreateAsset(
2115 grp.GetPartName(grp.LocalId),
2116 grp.GetPartDescription(grp.LocalId),
2117 (sbyte)AssetType.Object,
2118 Utils.StringToBytes(sceneObjectXml));
2119 AssetCache.AddAsset(asset);
2120
2121 InventoryItemBase item = new InventoryItemBase();
2122 item.Creator = grp.RootPart.CreatorID;
2123 item.Owner = remoteClient.AgentId;
2124 item.ID = UUID.Random();
2125 item.AssetID = asset.Metadata.FullID;
2126 item.Description = asset.Metadata.Description;
2127 item.Name = asset.Metadata.Name;
2128 item.AssetType = asset.Metadata.Type;
2129 item.InvType = (int)InventoryType.Object;
2130
2131 item.Folder = UUID.Zero; // Objects folder!
2132
2133 if ((remoteClient.AgentId != grp.RootPart.OwnerID) && Permissions.PropagatePermissions())
2134 {
2135 item.BasePermissions = grp.RootPart.NextOwnerMask;
2136 item.CurrentPermissions = grp.RootPart.NextOwnerMask;
2137 item.NextPermissions = grp.RootPart.NextOwnerMask;
2138 item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask;
2139 item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask;
2140 }
2141 else
2142 {
2143 item.BasePermissions = grp.RootPart.BaseMask;
2144 item.CurrentPermissions = grp.RootPart.OwnerMask;
2145 item.NextPermissions = grp.RootPart.NextOwnerMask;
2146 item.EveryOnePermissions = grp.RootPart.EveryoneMask;
2147 item.GroupPermissions = grp.RootPart.GroupMask;
2148 }
2149 item.CreationDate = Util.UnixTimeSinceEpoch();
2150
2151 // sets assetID so client can show asset as 'attached' in inventory
2152 grp.SetFromAssetID(item.ID);
2153
2154 userInfo.AddItem(item);
2155 remoteClient.SendInventoryItemCreateUpdate(item);
2156
2157 itemID = item.ID;
2158 return item.AssetID;
2159 }
2160 return UUID.Zero;
2161 }
2162 return UUID.Zero;
2163 }
2164
2165 /// <summary>
2166 /// Event Handler Rez an object into a scene
2167 /// Calls the non-void event handler
2168 /// </summary>
2169 /// <param name="remoteClient"></param>
2170 /// <param name="itemID"></param>
2171 /// <param name="RayEnd"></param>
2172 /// <param name="RayStart"></param>
2173 /// <param name="RayTargetID"></param>
2174 /// <param name="BypassRayCast"></param>
2175 /// <param name="RayEndIsIntersection"></param>
2176 /// <param name="EveryoneMask"></param>
2177 /// <param name="GroupMask"></param>
2178 /// <param name="RezSelected"></param>
2179 /// <param name="RemoveItem"></param>
2180 /// <param name="fromTaskID"></param>
2181 public virtual void RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart,
2182 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
2183 bool RezSelected, bool RemoveItem, UUID fromTaskID)
2184 {
2185 RezObject(
2186 remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
2187 RezSelected, RemoveItem, fromTaskID, false);
2188 }
2189
2190 /// <summary>
2191 /// Rez an object into the scene from the user's inventory
2192 /// </summary>
2193 /// <param name="remoteClient"></param>
2194 /// <param name="itemID"></param>
2195 /// <param name="RayEnd"></param>
2196 /// <param name="RayStart"></param>
2197 /// <param name="RayTargetID"></param>
2198 /// <param name="BypassRayCast"></param>
2199 /// <param name="RayEndIsIntersection"></param>
2200 /// <param name="RezSelected"></param>
2201 /// <param name="RemoveItem"></param>
2202 /// <param name="fromTaskID"></param>
2203 /// <param name="attachment"></param>
2204 /// <returns>The SceneObjectGroup rezzed or null if rez was unsuccessful.</returns>
2205 public virtual SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart,
2206 UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection,
2207 bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment)
2208 {
2209 // Work out position details
2210 byte bRayEndIsIntersection = (byte)0;
2211
2212 if (RayEndIsIntersection)
2213 {
2214 bRayEndIsIntersection = (byte)1;
2215 }
2216 else
2217 {
2218 bRayEndIsIntersection = (byte)0;
2219 }
2220
2221 Vector3 scale = new Vector3(0.5f, 0.5f, 0.5f);
2222
2223
2224 Vector3 pos = GetNewRezLocation(
2225 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
2226 BypassRayCast, bRayEndIsIntersection,true,scale, false);
2227
2228 // Rez object
2229 CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
2230 if (userInfo != null)
2231 {
2232 // Do NOT use HasReceivedInventory here, this is called
2233 // from within ItemReceive during login for attachments.
2234 // Using HasReceivedInventory here will break attachment
2235 // persistence!
2236 //
2237 if (userInfo.RootFolder != null)
2238 {
2239 InventoryItemBase item = userInfo.RootFolder.FindItem(itemID);
2240
2241 if (item != null)
2242 {
2243 AssetBase rezAsset = AssetCache.GetAsset(item.AssetID, false);
2244
2245 if (rezAsset != null)
2246 {
2247 UUID itemId = UUID.Zero;
2248
2249 // If we have permission to copy then link the rezzed object back to the user inventory
2250 // item that it came from. This allows us to enable 'save object to inventory'
2251 if (!Permissions.BypassPermissions())
2252 {
2253 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == (uint)PermissionMask.Copy)
2254 {
2255 itemId = item.ID;
2256 }
2257 }
2258
2259 string xmlData = Utils.BytesToString(rezAsset.Data);
2260 SceneObjectGroup group = new SceneObjectGroup(itemId, xmlData, true);
2261
2262 if (!Permissions.CanRezObject(
2263 group.Children.Count, remoteClient.AgentId, pos)
2264 && !attachment)
2265 {
2266 return null;
2267 }
2268
2269 group.ResetIDs();
2270
2271 AddNewSceneObject(group, true);
2272
2273 // if attachment we set it's asset id so object updates can reflect that
2274 // if not, we set it's position in world.
2275 if (!attachment)
2276 {
2277 pos = GetNewRezLocation(
2278 RayStart, RayEnd, RayTargetID, Quaternion.Identity,
2279 BypassRayCast, bRayEndIsIntersection, true, group.GroupScale(), false);
2280 group.AbsolutePosition = pos;
2281 }
2282 else
2283 {
2284 group.SetFromAssetID(itemID);
2285 }
2286
2287 SceneObjectPart rootPart = null;
2288 try
2289 {
2290 rootPart = group.GetChildPart(group.UUID);
2291 }
2292 catch (NullReferenceException)
2293 {
2294 string isAttachment = "";
2295
2296 if (attachment)
2297 isAttachment = " Object was an attachment";
2298
2299 m_log.Error("[AGENT INVENTORY]: Error rezzing ItemID: " + itemID + " object has no rootpart." + isAttachment);
2300 }
2301
2302 // Since renaming the item in the inventory does not affect the name stored
2303 // in the serialization, transfer the correct name from the inventory to the
2304 // object itself before we rez.
2305 rootPart.Name = item.Name;
2306 rootPart.Description = item.Description;
2307
2308 List<SceneObjectPart> partList = new List<SceneObjectPart>(group.Children.Values);
2309
2310 group.SetGroup(remoteClient.ActiveGroupId, remoteClient);
2311 if (rootPart.OwnerID != item.Owner)
2312 {
2313 //Need to kill the for sale here
2314 rootPart.ObjectSaleType = 0;
2315 rootPart.SalePrice = 10;
2316
2317 if (Permissions.PropagatePermissions())
2318 {
2319 if ((item.CurrentPermissions & 8) != 0)
2320 {
2321 foreach (SceneObjectPart part in partList)
2322 {
2323 part.EveryoneMask = item.EveryOnePermissions;
2324 part.NextOwnerMask = item.NextPermissions;
2325 part.GroupMask = 0; // DO NOT propagate here
2326 }
2327 }
2328 group.ApplyNextOwnerPermissions();
2329 }
2330 }
2331
2332 foreach (SceneObjectPart part in partList)
2333 {
2334 if (part.OwnerID != item.Owner)
2335 {
2336 part.LastOwnerID = part.OwnerID;
2337 part.OwnerID = item.Owner;
2338 part.Inventory.ChangeInventoryOwner(item.Owner);
2339 }
2340 else if (((item.CurrentPermissions & 8) != 0) && (!attachment)) // Slam!
2341 {
2342 part.EveryoneMask = item.EveryOnePermissions;
2343 part.NextOwnerMask = item.NextPermissions;
2344
2345 part.GroupMask = 0; // DO NOT propagate here
2346 }
2347 }
2348
2349 rootPart.TrimPermissions();
2350
2351 if (!attachment)
2352 {
2353 if (group.RootPart.Shape.PCode == (byte)PCode.Prim)
2354 {
2355 group.ClearPartAttachmentData();
2356 }
2357 }
2358
2359 if (!attachment)
2360 {
2361 // Fire on_rez
2362 group.CreateScriptInstances(0, true, DefaultScriptEngine, 0);
2363
2364 rootPart.ScheduleFullUpdate();
2365 }
2366
2367 if (!Permissions.BypassPermissions())
2368 {
2369 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
2370 {
2371 // If this is done on attachments, no
2372 // copy ones will be lost, so avoid it
2373 //
2374 if (!attachment)
2375 userInfo.DeleteItem(item.ID);
2376 }
2377 }
2378
2379 return rootPart.ParentGroup;
2380 }
2381 }
2382 }
2383 else
2384 m_log.WarnFormat("[AGENT INVENTORY]: Root folder not found in {0}", RegionInfo.RegionName);
2385 }
2386 else
2387 m_log.WarnFormat("[AGENT INVENTORY]: User profile not found in {0}", RegionInfo.RegionName);
2388
2389 return null;
2390 }
2391
2392 /// <summary>
2393 /// Rez an object into the scene from a prim's inventory.
2394 /// </summary>
2395 /// <param name="sourcePart"></param>
2396 /// <param name="item"></param>
2397 /// <param name="pos"></param>
2398 /// <param name="rot"></param>
2399 /// <param name="vel"></param>
2400 /// <param name="param"></param>
2401 /// <returns>The SceneObjectGroup rezzed or null if rez was unsuccessful</returns>
2402 public virtual SceneObjectGroup RezObject(
2403 SceneObjectPart sourcePart, TaskInventoryItem item,
2404 Vector3 pos, Quaternion rot, Vector3 vel, int param)
2405 {
2406 // Rez object
2407 if (item != null)
2408 {
2409 UUID ownerID = item.OwnerID;
2410
2411 AssetBase rezAsset = AssetCache.GetAsset(item.AssetID, false);
2412
2413 if (rezAsset != null)
2414 {
2415 string xmlData = Utils.BytesToString(rezAsset.Data);
2416 SceneObjectGroup group = new SceneObjectGroup(xmlData, true);
2417
2418 if (!Permissions.CanRezObject(group.Children.Count, ownerID, pos))
2419 {
2420 return null;
2421 }
2422 group.ResetIDs();
2423
2424 AddNewSceneObject(group, true);
2425
2426 // we set it's position in world.
2427 group.AbsolutePosition = pos;
2428
2429 SceneObjectPart rootPart = group.GetChildPart(group.UUID);
2430
2431 // Since renaming the item in the inventory does not affect the name stored
2432 // in the serialization, transfer the correct name from the inventory to the
2433 // object itself before we rez.
2434 rootPart.Name = item.Name;
2435 rootPart.Description = item.Description;
2436
2437 List<SceneObjectPart> partList = new List<SceneObjectPart>(group.Children.Values);
2438
2439 group.SetGroup(sourcePart.GroupID, null);
2440
2441 if (rootPart.OwnerID != item.OwnerID)
2442 {
2443 if (Permissions.PropagatePermissions())
2444 {
2445 if ((item.CurrentPermissions & 8) != 0)
2446 {
2447 foreach (SceneObjectPart part in partList)
2448 {
2449 part.EveryoneMask = item.EveryonePermissions;
2450 part.NextOwnerMask = item.NextPermissions;
2451 }
2452 }
2453 group.ApplyNextOwnerPermissions();
2454 }
2455 }
2456
2457 foreach (SceneObjectPart part in partList)
2458 {
2459 if (part.OwnerID != item.OwnerID)
2460 {
2461 part.LastOwnerID = part.OwnerID;
2462 part.OwnerID = item.OwnerID;
2463 part.Inventory.ChangeInventoryOwner(item.OwnerID);
2464 }
2465 else if ((item.CurrentPermissions & 8) != 0) // Slam!
2466 {
2467 part.EveryoneMask = item.EveryonePermissions;
2468 part.NextOwnerMask = item.NextPermissions;
2469 }
2470 }
2471 rootPart.TrimPermissions();
2472 if (group.RootPart.Shape.PCode == (byte)PCode.Prim)
2473 {
2474 group.ClearPartAttachmentData();
2475 }
2476 group.UpdateGroupRotation(rot);
2477 //group.ApplyPhysics(m_physicalPrim);
2478 if (group.RootPart.PhysActor != null && group.RootPart.PhysActor.IsPhysical && vel != Vector3.Zero)
2479 {
2480 group.RootPart.ApplyImpulse((vel * group.GetMass()), false);
2481 group.Velocity = vel;
2482 rootPart.ScheduleFullUpdate();
2483 }
2484 group.CreateScriptInstances(param, true, DefaultScriptEngine, 2);
2485 rootPart.ScheduleFullUpdate();
2486
2487 if (!Permissions.BypassPermissions())
2488 {
2489 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
2490 sourcePart.Inventory.RemoveInventoryItem(item.ItemID);
2491 }
2492 return rootPart.ParentGroup;
2493 }
2494 }
2495
2496 return null;
2497 }
2498
2499 public virtual bool returnObjects(SceneObjectGroup[] returnobjects, UUID AgentId)
2500 {
2501 foreach (SceneObjectGroup grp in returnobjects)
2502 {
2503 AddReturn(grp.OwnerID, grp.Name, grp.AbsolutePosition, "parcel owner return");
2504 DeRezObject(null, grp.RootPart.LocalId,
2505 grp.RootPart.GroupID, DeRezAction.Return, UUID.Zero);
2506 }
2507
2508 return true;
2509 }
2510
2511 public void SetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID, bool running)
2512 {
2513 SceneObjectPart part = GetSceneObjectPart(objectID);
2514 if (part == null)
2515 return;
2516
2517 if (running)
2518 EventManager.TriggerStartScript(part.LocalId, itemID);
2519 else
2520 EventManager.TriggerStopScript(part.LocalId, itemID);
2521 }
2522
2523 public UUID RezSingleAttachment(IClientAPI remoteClient, UUID itemID,
2524 uint AttachmentPt)
2525 {
2526 SceneObjectGroup att = m_sceneGraph.RezSingleAttachment(remoteClient, itemID, AttachmentPt);
2527
2528 if (att == null)
2529 {
2530 DetachSingleAttachmentToInv(itemID, remoteClient);
2531 return UUID.Zero;
2532 }
2533
2534 return RezSingleAttachment(att, remoteClient, itemID, AttachmentPt);
2535 }
2536
2537 public UUID RezSingleAttachment(SceneObjectGroup att,
2538 IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
2539 {
2540 if (!att.IsDeleted)
2541 AttachmentPt = att.RootPart.AttachmentPoint;
2542
2543 ScenePresence presence;
2544 if (TryGetAvatar(remoteClient.AgentId, out presence))
2545 {
2546 presence.Appearance.SetAttachment((int)AttachmentPt, itemID, att.UUID);
2547 IAvatarFactory ava = RequestModuleInterface<IAvatarFactory>();
2548 if (ava != null)
2549 {
2550 ava.UpdateDatabase(remoteClient.AgentId, presence.Appearance);
2551 }
2552
2553 }
2554 return att.UUID;
2555 }
2556
2557 public void AttachObject(IClientAPI controllingClient, uint localID, uint attachPoint, Quaternion rot, Vector3 pos, bool silent)
2558 {
2559 m_sceneGraph.AttachObject(controllingClient, localID, attachPoint, rot, pos, silent);
2560 }
2561
2562 public void AttachObject(IClientAPI remoteClient, uint AttachmentPt, UUID itemID, SceneObjectGroup att)
2563 {
2564 if (UUID.Zero == itemID)
2565 {
2566 m_log.Error("[SCENE INVENTORY]: Unable to save attachment. Error inventory item ID.");
2567 return;
2568 }
2569
2570 if (0 == AttachmentPt)
2571 {
2572 m_log.Error("[SCENE INVENTORY]: Unable to save attachment. Error attachment point.");
2573 return;
2574 }
2575
2576 if (null == att.RootPart)
2577 {
2578 m_log.Error("[SCENE INVENTORY]: Unable to save attachment for a prim without the rootpart!");
2579 return;
2580 }
2581
2582 ScenePresence presence;
2583 if (TryGetAvatar(remoteClient.AgentId, out presence))
2584 {
2585 presence.Appearance.SetAttachment((int)AttachmentPt, itemID, att.UUID);
2586 IAvatarFactory ava = RequestModuleInterface<IAvatarFactory>();
2587 if (ava != null)
2588 {
2589 m_log.InfoFormat("[SCENE INVENTORY]: Saving avatar attachment. AgentID:{0} ItemID:{1} AttachmentPoint:{2}", remoteClient.AgentId, itemID, AttachmentPt);
2590 ava.UpdateDatabase(remoteClient.AgentId, presence.Appearance);
2591 }
2592 }
2593 }
2594
2595 public void DetachSingleAttachmentToGround(UUID itemID, IClientAPI remoteClient)
2596 {
2597 SceneObjectPart part = GetSceneObjectPart(itemID);
2598 if (part == null || part.ParentGroup == null)
2599 return;
2600
2601 UUID inventoryID = part.ParentGroup.GetFromAssetID();
2602
2603 ScenePresence presence;
2604 if (TryGetAvatar(remoteClient.AgentId, out presence))
2605 {
2606 if (!Permissions.CanRezObject(part.ParentGroup.Children.Count, remoteClient.AgentId, presence.AbsolutePosition))
2607 return;
2608
2609 presence.Appearance.DetachAttachment(itemID);
2610 IAvatarFactory ava = RequestModuleInterface<IAvatarFactory>();
2611 if (ava != null)
2612 {
2613 ava.UpdateDatabase(remoteClient.AgentId, presence.Appearance);
2614 }
2615 part.ParentGroup.DetachToGround();
2616 CachedUserInfo userInfo =
2617 CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
2618 if (userInfo != null)
2619 {
2620 userInfo.DeleteItem(inventoryID);
2621 remoteClient.SendRemoveInventoryItem(inventoryID);
2622 }
2623 }
2624 }
2625
2626 public void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient)
2627 {
2628 ScenePresence presence;
2629 if (TryGetAvatar(remoteClient.AgentId, out presence))
2630 {
2631 presence.Appearance.DetachAttachment(itemID);
2632 IAvatarFactory ava = RequestModuleInterface<IAvatarFactory>();
2633 if (ava != null)
2634 {
2635 ava.UpdateDatabase(remoteClient.AgentId, presence.Appearance);
2636 }
2637
2638 }
2639
2640 m_sceneGraph.DetachSingleAttachmentToInv(itemID, remoteClient);
2641 }
2642
2643 public void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID)
2644 {
2645 EventManager.TriggerGetScriptRunning(controllingClient, objectID, itemID);
2646 }
2647
2648 void ObjectOwner(IClientAPI remoteClient, UUID ownerID, UUID groupID, List<uint> localIDs)
2649 {
2650 if (!Permissions.IsGod(remoteClient.AgentId))
2651 return;
2652
2653 foreach (uint localID in localIDs)
2654 {
2655 SceneObjectPart part = GetSceneObjectPart(localID);
2656 if (part != null && part.ParentGroup != null)
2657 {
2658 part.ParentGroup.SetOwnerId(ownerID);
2659 part.Inventory.ChangeInventoryOwner(ownerID);
2660 part.ParentGroup.SetGroup(groupID, remoteClient);
2661 }
2662 }
2663 }
2664 }
2665}
diff --git a/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
new file mode 100644
index 0000000..039b81b
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scene.PacketHandlers.cs
@@ -0,0 +1,632 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29using System.Threading;
30using OpenMetaverse;
31using OpenMetaverse.Packets;
32using OpenSim.Framework;
33using OpenSim.Framework.Communications;
34using OpenSim.Framework.Communications.Cache;
35
36namespace OpenSim.Region.Framework.Scenes
37{
38 public partial class Scene
39 {
40 protected void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
41 UUID fromID, bool fromAgent, bool broadcast)
42 {
43 OSChatMessage args = new OSChatMessage();
44
45 args.Message = Utils.BytesToString(message);
46 args.Channel = channel;
47 args.Type = type;
48 args.Position = fromPos;
49 args.SenderUUID = fromID;
50 args.Scene = this;
51
52 if (fromAgent)
53 {
54 ScenePresence user = GetScenePresence(fromID);
55 if (user != null)
56 args.Sender = user.ControllingClient;
57 }
58 else
59 {
60 SceneObjectPart obj = GetSceneObjectPart(fromID);
61 args.SenderObject = obj;
62 }
63
64 args.From = fromName;
65 //args.
66
67 if (broadcast)
68 EventManager.TriggerOnChatBroadcast(this, args);
69 else
70 EventManager.TriggerOnChatFromWorld(this, args);
71
72 }
73 /// <summary>
74 ///
75 /// </summary>
76 /// <param name="message"></param>
77 /// <param name="type"></param>
78 /// <param name="fromPos"></param>
79 /// <param name="fromName"></param>
80 /// <param name="fromAgentID"></param>
81 public void SimChat(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
82 UUID fromID, bool fromAgent)
83 {
84 SimChat(message, type, channel, fromPos, fromName, fromID, fromAgent, false);
85 }
86
87 /// <summary>
88 ///
89 /// </summary>
90 /// <param name="message"></param>
91 /// <param name="type"></param>
92 /// <param name="fromPos"></param>
93 /// <param name="fromName"></param>
94 /// <param name="fromAgentID"></param>
95 public void SimChatBroadcast(byte[] message, ChatTypeEnum type, int channel, Vector3 fromPos, string fromName,
96 UUID fromID, bool fromAgent)
97 {
98 SimChat(message, type, channel, fromPos, fromName, fromID, fromAgent, true);
99 }
100
101 /// <summary>
102 /// Invoked when the client selects a prim.
103 /// </summary>
104 /// <param name="primLocalID"></param>
105 /// <param name="remoteClient"></param>
106 public void SelectPrim(uint primLocalID, IClientAPI remoteClient)
107 {
108 List<EntityBase> EntityList = GetEntities();
109
110 foreach (EntityBase ent in EntityList)
111 {
112 if (ent is SceneObjectGroup)
113 {
114 if (((SceneObjectGroup) ent).LocalId == primLocalID)
115 {
116 ((SceneObjectGroup) ent).GetProperties(remoteClient);
117 ((SceneObjectGroup) ent).IsSelected = true;
118 // A prim is only tainted if it's allowed to be edited by the person clicking it.
119 if (Permissions.CanEditObject(((SceneObjectGroup)ent).UUID, remoteClient.AgentId)
120 || Permissions.CanMoveObject(((SceneObjectGroup)ent).UUID, remoteClient.AgentId))
121 {
122 EventManager.TriggerParcelPrimCountTainted();
123 }
124 break;
125 }
126 else
127 {
128 // We also need to check the children of this prim as they
129 // can be selected as well and send property information
130 bool foundPrim = false;
131 foreach (KeyValuePair<UUID, SceneObjectPart> child in ((SceneObjectGroup) ent).Children)
132 {
133 if (child.Value.LocalId == primLocalID)
134 {
135 child.Value.GetProperties(remoteClient);
136 foundPrim = true;
137 break;
138 }
139 }
140 if (foundPrim) break;
141 }
142 }
143 }
144 }
145
146 /// <summary>
147 /// Handle the deselection of a prim from the client.
148 /// </summary>
149 /// <param name="primLocalID"></param>
150 /// <param name="remoteClient"></param>
151 public void DeselectPrim(uint primLocalID, IClientAPI remoteClient)
152 {
153 SceneObjectPart part = GetSceneObjectPart(primLocalID);
154 if (part == null)
155 return;
156
157 // The prim is in the process of being deleted.
158 if (null == part.ParentGroup.RootPart)
159 return;
160
161 // A deselect packet contains all the local prims being deselected. However, since selection is still
162 // group based we only want the root prim to trigger a full update - otherwise on objects with many prims
163 // we end up sending many duplicate ObjectUpdates
164 if (part.ParentGroup.RootPart.LocalId != part.LocalId)
165 return;
166
167 bool isAttachment = false;
168
169 // This is wrong, wrong, wrong. Selection should not be
170 // handled by group, but by prim. Legacy cruft.
171 // TODO: Make selection flagging per prim!
172 //
173 part.ParentGroup.IsSelected = false;
174
175 if (part.ParentGroup.IsAttachment)
176 isAttachment = true;
177 else
178 part.ParentGroup.ScheduleGroupForFullUpdate();
179
180 // If it's not an attachment, and we are allowed to move it,
181 // then we might have done so. If we moved across a parcel
182 // boundary, we will need to recount prims on the parcels.
183 // For attachments, that makes no sense.
184 //
185 if (!isAttachment)
186 {
187 if (Permissions.CanEditObject(
188 part.UUID, remoteClient.AgentId)
189 || Permissions.CanMoveObject(
190 part.UUID, remoteClient.AgentId))
191 EventManager.TriggerParcelPrimCountTainted();
192 }
193 }
194
195 public virtual void ProcessMoneyTransferRequest(UUID source, UUID destination, int amount,
196 int transactiontype, string description)
197 {
198 EventManager.MoneyTransferArgs args = new EventManager.MoneyTransferArgs(source, destination, amount,
199 transactiontype, description);
200
201 EventManager.TriggerMoneyTransfer(this, args);
202 }
203
204 public virtual void ProcessParcelBuy(UUID agentId, UUID groupId, bool final, bool groupOwned,
205 bool removeContribution, int parcelLocalID, int parcelArea, int parcelPrice, bool authenticated)
206 {
207 EventManager.LandBuyArgs args = new EventManager.LandBuyArgs(agentId, groupId, final, groupOwned,
208 removeContribution, parcelLocalID, parcelArea,
209 parcelPrice, authenticated);
210
211 // First, allow all validators a stab at it
212 m_eventManager.TriggerValidateLandBuy(this, args);
213
214 // Then, check validation and transfer
215 m_eventManager.TriggerLandBuy(this, args);
216 }
217
218 public virtual void ProcessObjectGrab(uint localID, Vector3 offsetPos, IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs)
219 {
220 List<EntityBase> EntityList = GetEntities();
221
222 SurfaceTouchEventArgs surfaceArg = null;
223 if (surfaceArgs != null && surfaceArgs.Count > 0)
224 surfaceArg = surfaceArgs[0];
225
226 foreach (EntityBase ent in EntityList)
227 {
228 if (ent is SceneObjectGroup)
229 {
230 SceneObjectGroup obj = ent as SceneObjectGroup;
231 if (obj != null)
232 {
233 // Is this prim part of the group
234 if (obj.HasChildPrim(localID))
235 {
236 // Currently only grab/touch for the single prim
237 // the client handles rez correctly
238 obj.ObjectGrabHandler(localID, offsetPos, remoteClient);
239
240 SceneObjectPart part = obj.GetChildPart(localID);
241
242 // If the touched prim handles touches, deliver it
243 // If not, deliver to root prim
244 if ((part.ScriptEvents & scriptEvents.touch_start) != 0)
245 EventManager.TriggerObjectGrab(part.LocalId, 0, part.OffsetPosition, remoteClient, surfaceArg);
246 else
247 EventManager.TriggerObjectGrab(obj.RootPart.LocalId, part.LocalId, part.OffsetPosition, remoteClient, surfaceArg);
248
249 return;
250 }
251 }
252 }
253 }
254 }
255
256 public virtual void ProcessObjectDeGrab(uint localID, IClientAPI remoteClient)
257 {
258 List<EntityBase> EntityList = GetEntities();
259
260 foreach (EntityBase ent in EntityList)
261 {
262 if (ent is SceneObjectGroup)
263 {
264 SceneObjectGroup obj = ent as SceneObjectGroup;
265
266 // Is this prim part of the group
267 if (obj.HasChildPrim(localID))
268 {
269 SceneObjectPart part=obj.GetChildPart(localID);
270 if (part != null)
271 {
272 // If the touched prim handles touches, deliver it
273 // If not, deliver to root prim
274 if ((part.ScriptEvents & scriptEvents.touch_end) != 0)
275 EventManager.TriggerObjectDeGrab(part.LocalId, 0, remoteClient);
276 else
277 EventManager.TriggerObjectDeGrab(obj.RootPart.LocalId, part.LocalId, remoteClient);
278
279 return;
280 }
281 return;
282 }
283 }
284 }
285 }
286
287 public void ProcessAvatarPickerRequest(IClientAPI client, UUID avatarID, UUID RequestID, string query)
288 {
289 //EventManager.TriggerAvatarPickerRequest();
290
291 List<AvatarPickerAvatar> AvatarResponses = new List<AvatarPickerAvatar>();
292 AvatarResponses = m_sceneGridService.GenerateAgentPickerRequestResponse(RequestID, query);
293
294 AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket) PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply);
295 // TODO: don't create new blocks if recycling an old packet
296
297 AvatarPickerReplyPacket.DataBlock[] searchData =
298 new AvatarPickerReplyPacket.DataBlock[AvatarResponses.Count];
299 AvatarPickerReplyPacket.AgentDataBlock agentData = new AvatarPickerReplyPacket.AgentDataBlock();
300
301 agentData.AgentID = avatarID;
302 agentData.QueryID = RequestID;
303 replyPacket.AgentData = agentData;
304 //byte[] bytes = new byte[AvatarResponses.Count*32];
305
306 int i = 0;
307 foreach (AvatarPickerAvatar item in AvatarResponses)
308 {
309 UUID translatedIDtem = item.AvatarID;
310 searchData[i] = new AvatarPickerReplyPacket.DataBlock();
311 searchData[i].AvatarID = translatedIDtem;
312 searchData[i].FirstName = Utils.StringToBytes((string) item.firstName);
313 searchData[i].LastName = Utils.StringToBytes((string) item.lastName);
314 i++;
315 }
316 if (AvatarResponses.Count == 0)
317 {
318 searchData = new AvatarPickerReplyPacket.DataBlock[0];
319 }
320 replyPacket.Data = searchData;
321
322 AvatarPickerReplyAgentDataArgs agent_data = new AvatarPickerReplyAgentDataArgs();
323 agent_data.AgentID = replyPacket.AgentData.AgentID;
324 agent_data.QueryID = replyPacket.AgentData.QueryID;
325
326 List<AvatarPickerReplyDataArgs> data_args = new List<AvatarPickerReplyDataArgs>();
327 for (i = 0; i < replyPacket.Data.Length; i++)
328 {
329 AvatarPickerReplyDataArgs data_arg = new AvatarPickerReplyDataArgs();
330 data_arg.AvatarID = replyPacket.Data[i].AvatarID;
331 data_arg.FirstName = replyPacket.Data[i].FirstName;
332 data_arg.LastName = replyPacket.Data[i].LastName;
333 data_args.Add(data_arg);
334 }
335 client.SendAvatarPickerReply(agent_data, data_args);
336 }
337
338 public void ProcessScriptReset(IClientAPI remoteClient, UUID objectID,
339 UUID itemID)
340 {
341 SceneObjectPart part=GetSceneObjectPart(objectID);
342 if (part == null)
343 return;
344
345 if (Permissions.CanResetScript(objectID, itemID, remoteClient.AgentId))
346 {
347 EventManager.TriggerScriptReset(part.LocalId, itemID);
348 }
349 }
350
351 /// <summary>
352 /// Handle a fetch inventory request from the client
353 /// </summary>
354 /// <param name="remoteClient"></param>
355 /// <param name="itemID"></param>
356 /// <param name="ownerID"></param>
357 public void HandleFetchInventory(IClientAPI remoteClient, UUID itemID, UUID ownerID)
358 {
359 if (ownerID == CommsManager.UserProfileCacheService.LibraryRoot.Owner)
360 {
361 //Console.WriteLine("request info for library item");
362 return;
363 }
364
365 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
366
367 if (null == userProfile)
368 {
369 m_log.ErrorFormat(
370 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
371 remoteClient.Name, remoteClient.AgentId);
372 return;
373 }
374
375 if (userProfile.HasReceivedInventory)
376 {
377 InventoryItemBase item = null;
378 if (userProfile.RootFolder == null)
379 m_log.ErrorFormat(
380 "[AGENT INVENTORY]: User {0} {1} does not have a root folder.",
381 remoteClient.Name, remoteClient.AgentId);
382 else
383 item = userProfile.RootFolder.FindItem(itemID);
384
385 if (item != null)
386 {
387 remoteClient.SendInventoryItemDetails(ownerID, item);
388 }
389 }
390 }
391
392 /// <summary>
393 /// Tell the client about the various child items and folders contained in the requested folder.
394 /// </summary>
395 /// <param name="remoteClient"></param>
396 /// <param name="folderID"></param>
397 /// <param name="ownerID"></param>
398 /// <param name="fetchFolders"></param>
399 /// <param name="fetchItems"></param>
400 /// <param name="sortOrder"></param>
401 public void HandleFetchInventoryDescendents(IClientAPI remoteClient, UUID folderID, UUID ownerID,
402 bool fetchFolders, bool fetchItems, int sortOrder)
403 {
404 // FIXME MAYBE: We're not handling sortOrder!
405
406 // TODO: This code for looking in the folder for the library should be folded back into the
407 // CachedUserInfo so that this class doesn't have to know the details (and so that multiple libraries, etc.
408 // can be handled transparently).
409 InventoryFolderImpl fold = null;
410 if ((fold = CommsManager.UserProfileCacheService.LibraryRoot.FindFolder(folderID)) != null)
411 {
412 remoteClient.SendInventoryFolderDetails(
413 fold.Owner, folderID, fold.RequestListOfItems(),
414 fold.RequestListOfFolders(), fetchFolders, fetchItems);
415 return;
416 }
417
418 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
419
420 if (null == userProfile)
421 {
422 m_log.ErrorFormat(
423 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
424 remoteClient.Name, remoteClient.AgentId);
425 return;
426 }
427
428 userProfile.SendInventoryDecendents(remoteClient, folderID, fetchFolders, fetchItems);
429 }
430
431 /// <summary>
432 /// Handle the caps inventory descendents fetch.
433 ///
434 /// Since the folder structure is sent to the client on login, I believe we only need to handle items.
435 /// </summary>
436 /// <param name="agentID"></param>
437 /// <param name="folderID"></param>
438 /// <param name="ownerID"></param>
439 /// <param name="fetchFolders"></param>
440 /// <param name="fetchItems"></param>
441 /// <param name="sortOrder"></param>
442 /// <returns>null if the inventory look up failed</returns>
443 public List<InventoryItemBase> HandleFetchInventoryDescendentsCAPS(UUID agentID, UUID folderID, UUID ownerID,
444 bool fetchFolders, bool fetchItems, int sortOrder)
445 {
446// m_log.DebugFormat(
447// "[INVENTORY CACHE]: Fetching folders ({0}), items ({1}) from {2} for agent {3}",
448// fetchFolders, fetchItems, folderID, agentID);
449
450 // FIXME MAYBE: We're not handling sortOrder!
451
452 // TODO: This code for looking in the folder for the library should be folded back into the
453 // CachedUserInfo so that this class doesn't have to know the details (and so that multiple libraries, etc.
454 // can be handled transparently).
455 InventoryFolderImpl fold;
456 if ((fold = CommsManager.UserProfileCacheService.LibraryRoot.FindFolder(folderID)) != null)
457 {
458 return fold.RequestListOfItems();
459 }
460
461 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(agentID);
462
463 if (null == userProfile)
464 {
465 m_log.ErrorFormat("[AGENT INVENTORY]: Could not find user profile for {0}", agentID);
466 return null;
467 }
468
469 // XXX: When a client crosses into a scene, their entire inventory is fetched
470 // asynchronously. If the client makes a request before the inventory is received, we need
471 // to give the inventory a chance to come in.
472 //
473 // This is a crude way of dealing with that by retrying the lookup. It's not quite as bad
474 // in CAPS as doing this with the udp request, since here it won't hold up other packets.
475 // In fact, here we'll be generous and try for longer.
476 if (!userProfile.HasReceivedInventory)
477 {
478 int attempts = 0;
479 while (attempts++ < 30)
480 {
481 m_log.DebugFormat(
482 "[INVENTORY CACHE]: Poll number {0} for inventory items in folder {1} for user {2}",
483 attempts, folderID, agentID);
484
485 Thread.Sleep(2000);
486
487 if (userProfile.HasReceivedInventory)
488 {
489 break;
490 }
491 }
492 }
493
494 if (userProfile.HasReceivedInventory)
495 {
496 if ((fold = userProfile.RootFolder.FindFolder(folderID)) != null)
497 {
498 return fold.RequestListOfItems();
499 }
500 else
501 {
502 m_log.WarnFormat(
503 "[AGENT INVENTORY]: Could not find folder {0} requested by user {1}",
504 folderID, agentID);
505 return null;
506 }
507 }
508 else
509 {
510 m_log.ErrorFormat("[INVENTORY CACHE]: Could not find root folder for user {0}", agentID);
511 return null;
512 }
513 }
514
515 /// <summary>
516 /// Handle an inventory folder creation request from the client.
517 /// </summary>
518 /// <param name="remoteClient"></param>
519 /// <param name="folderID"></param>
520 /// <param name="folderType"></param>
521 /// <param name="folderName"></param>
522 /// <param name="parentID"></param>
523 public void HandleCreateInventoryFolder(IClientAPI remoteClient, UUID folderID, ushort folderType,
524 string folderName, UUID parentID)
525 {
526 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
527
528 if (null == userProfile)
529 {
530 m_log.ErrorFormat(
531 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
532 remoteClient.Name, remoteClient.AgentId);
533 return;
534 }
535
536 if (!userProfile.CreateFolder(folderName, folderID, folderType, parentID))
537 {
538 m_log.ErrorFormat(
539 "[AGENT INVENTORY]: Failed to move create folder for user {0} {1}",
540 remoteClient.Name, remoteClient.AgentId);
541 }
542 }
543
544 /// <summary>
545 /// Handle a client request to update the inventory folder
546 /// </summary>
547 ///
548 /// FIXME: We call add new inventory folder because in the data layer, we happen to use an SQL REPLACE
549 /// so this will work to rename an existing folder. Needless to say, to rely on this is very confusing,
550 /// and needs to be changed.
551 ///
552 /// <param name="remoteClient"></param>
553 /// <param name="folderID"></param>
554 /// <param name="type"></param>
555 /// <param name="name"></param>
556 /// <param name="parentID"></param>
557 public void HandleUpdateInventoryFolder(IClientAPI remoteClient, UUID folderID, ushort type, string name,
558 UUID parentID)
559 {
560// m_log.DebugFormat(
561// "[AGENT INVENTORY]: Updating inventory folder {0} {1} for {2} {3}", folderID, name, remoteClient.Name, remoteClient.AgentId);
562
563 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
564
565 if (null == userProfile)
566 {
567 m_log.ErrorFormat(
568 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
569 remoteClient.Name, remoteClient.AgentId);
570 return;
571 }
572
573 if (!userProfile.UpdateFolder(name, folderID, type, parentID))
574 {
575 m_log.ErrorFormat(
576 "[AGENT INVENTORY]: Failed to update folder for user {0} {1}",
577 remoteClient.Name, remoteClient.AgentId);
578 }
579 }
580
581 /// <summary>
582 /// Handle an inventory folder move request from the client.
583 /// </summary>
584 /// <param name="remoteClient"></param>
585 /// <param name="folderID"></param>
586 /// <param name="parentID"></param>
587 public void HandleMoveInventoryFolder(IClientAPI remoteClient, UUID folderID, UUID parentID)
588 {
589 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
590
591 if (null == userProfile)
592 {
593 m_log.ErrorFormat(
594 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
595 remoteClient.Name, remoteClient.AgentId);
596 return;
597 }
598
599 if (!userProfile.MoveFolder(folderID, parentID))
600 {
601 m_log.ErrorFormat(
602 "[AGENT INVENTORY]: Failed to move folder {0} to {1} for user {2}",
603 folderID, parentID, remoteClient.Name);
604 }
605 }
606
607 /// <summary>
608 /// This should delete all the items and folders in the given directory.
609 /// </summary>
610 /// <param name="remoteClient"></param>
611 /// <param name="folderID"></param>
612 public void HandlePurgeInventoryDescendents(IClientAPI remoteClient, UUID folderID)
613 {
614 CachedUserInfo userProfile = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
615
616 if (null == userProfile)
617 {
618 m_log.ErrorFormat(
619 "[AGENT INVENTORY]: Could not find user profile for {0} {1}",
620 remoteClient.Name, remoteClient.AgentId);
621 return;
622 }
623
624 if (!userProfile.PurgeFolder(folderID))
625 {
626 m_log.ErrorFormat(
627 "[AGENT INVENTORY]: Failed to purge folder for user {0} {1}",
628 remoteClient.Name, remoteClient.AgentId);
629 }
630 }
631 }
632}
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs b/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs
new file mode 100644
index 0000000..6aa617f
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs
@@ -0,0 +1,1334 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Text;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Framework.Interfaces;
34
35namespace OpenSim.Region.Framework.Scenes
36{
37 public class ScenePermissions
38 {
39 private Scene m_scene;
40
41 public ScenePermissions(Scene scene)
42 {
43 m_scene = scene;
44 }
45
46 #region Object Permission Checks
47
48 public delegate uint GenerateClientFlagsHandler(UUID userID, UUID objectIDID);
49 private List<GenerateClientFlagsHandler> GenerateClientFlagsCheckFunctions = new List<GenerateClientFlagsHandler>();
50
51 public void AddGenerateClientFlagsHandler(GenerateClientFlagsHandler delegateFunc)
52 {
53 if (!GenerateClientFlagsCheckFunctions.Contains(delegateFunc))
54 GenerateClientFlagsCheckFunctions.Add(delegateFunc);
55 }
56
57 public void RemoveGenerateClientFlagsHandler(GenerateClientFlagsHandler delegateFunc)
58 {
59 if (GenerateClientFlagsCheckFunctions.Contains(delegateFunc))
60 GenerateClientFlagsCheckFunctions.Remove(delegateFunc);
61 }
62
63 public uint GenerateClientFlags(UUID userID, UUID objectID)
64 {
65 SceneObjectPart part=m_scene.GetSceneObjectPart(objectID);
66
67 if (part == null)
68 return 0;
69
70 // libomv will moan about PrimFlags.ObjectYouOfficer being
71 // obsolete...
72 #pragma warning disable 0612
73 uint perms=part.GetEffectiveObjectFlags() |
74 (uint)PrimFlags.ObjectModify |
75 (uint)PrimFlags.ObjectCopy |
76 (uint)PrimFlags.ObjectMove |
77 (uint)PrimFlags.ObjectTransfer |
78 (uint)PrimFlags.ObjectYouOwner |
79 (uint)PrimFlags.ObjectAnyOwner |
80 (uint)PrimFlags.ObjectOwnerModify |
81 (uint)PrimFlags.ObjectYouOfficer;
82 #pragma warning restore 0612
83
84 foreach (GenerateClientFlagsHandler check in GenerateClientFlagsCheckFunctions)
85 {
86 perms &= check(userID, objectID);
87 }
88 return perms;
89 }
90
91 public delegate void SetBypassPermissionsHandler(bool value);
92 private List<SetBypassPermissionsHandler> SetBypassPermissionsCheckFunctions = new List<SetBypassPermissionsHandler>();
93
94 public void AddSetBypassPermissionsHandler(SetBypassPermissionsHandler delegateFunc)
95 {
96 if (!SetBypassPermissionsCheckFunctions.Contains(delegateFunc))
97 SetBypassPermissionsCheckFunctions.Add(delegateFunc);
98 }
99
100 public void RemoveSetBypassPermissionsHandler(SetBypassPermissionsHandler delegateFunc)
101 {
102 if (SetBypassPermissionsCheckFunctions.Contains(delegateFunc))
103 SetBypassPermissionsCheckFunctions.Remove(delegateFunc);
104 }
105
106 public void SetBypassPermissions(bool value)
107 {
108 foreach (SetBypassPermissionsHandler check in SetBypassPermissionsCheckFunctions)
109 {
110 check(value);
111 }
112 }
113
114 public delegate bool BypassPermissionsHandler();
115 private List<BypassPermissionsHandler> BypassPermissionsCheckFunctions = new List<BypassPermissionsHandler>();
116
117 public void AddBypassPermissionsHandler(BypassPermissionsHandler delegateFunc)
118 {
119 if (!BypassPermissionsCheckFunctions.Contains(delegateFunc))
120 BypassPermissionsCheckFunctions.Add(delegateFunc);
121 }
122
123 public void RemoveBypassPermissionsHandler(BypassPermissionsHandler delegateFunc)
124 {
125 if (BypassPermissionsCheckFunctions.Contains(delegateFunc))
126 BypassPermissionsCheckFunctions.Remove(delegateFunc);
127 }
128
129 public bool BypassPermissions()
130 {
131 foreach (BypassPermissionsHandler check in BypassPermissionsCheckFunctions)
132 {
133 if (check() == false)
134 {
135 return false;
136 }
137 }
138 return true;
139 }
140
141 public delegate bool PropagatePermissionsHandler();
142 private List<PropagatePermissionsHandler> PropagatePermissionsCheckFunctions = new List<PropagatePermissionsHandler>();
143
144 public void AddPropagatePermissionsHandler(PropagatePermissionsHandler delegateFunc)
145 {
146 if (!PropagatePermissionsCheckFunctions.Contains(delegateFunc))
147 PropagatePermissionsCheckFunctions.Add(delegateFunc);
148 }
149
150 public void RemovePropagatePermissionsHandler(PropagatePermissionsHandler delegateFunc)
151 {
152 if (PropagatePermissionsCheckFunctions.Contains(delegateFunc))
153 PropagatePermissionsCheckFunctions.Remove(delegateFunc);
154 }
155
156 public bool PropagatePermissions()
157 {
158 foreach (PropagatePermissionsHandler check in PropagatePermissionsCheckFunctions)
159 {
160 if (check() == false)
161 {
162 return false;
163 }
164 }
165 return true;
166 }
167
168 #region REZ OBJECT
169 public delegate bool CanRezObjectHandler(int objectCount, UUID owner, Vector3 objectPosition, Scene scene);
170 private List<CanRezObjectHandler> CanRezObjectCheckFunctions = new List<CanRezObjectHandler>();
171
172 public void AddRezObjectHandler(CanRezObjectHandler delegateFunc)
173 {
174 if (!CanRezObjectCheckFunctions.Contains(delegateFunc))
175 CanRezObjectCheckFunctions.Add(delegateFunc);
176 }
177
178 public void RemoveRezObjectHandler(CanRezObjectHandler delegateFunc)
179 {
180 if (CanRezObjectCheckFunctions.Contains(delegateFunc))
181 CanRezObjectCheckFunctions.Remove(delegateFunc);
182 }
183
184 public bool CanRezObject(int objectCount, UUID owner, Vector3 objectPosition)
185 {
186 foreach (CanRezObjectHandler check in CanRezObjectCheckFunctions)
187 {
188 if (check(objectCount, owner,objectPosition, m_scene) == false)
189 {
190 return false;
191 }
192 }
193 return true;
194 }
195
196 #endregion
197
198 #region DELETE OBJECT
199 public delegate bool CanDeleteObjectHandler(UUID objectID, UUID deleter, Scene scene);
200 private List<CanDeleteObjectHandler> CanDeleteObjectCheckFunctions = new List<CanDeleteObjectHandler>();
201
202 public void AddDeleteObjectHandler(CanDeleteObjectHandler delegateFunc)
203 {
204 if (!CanDeleteObjectCheckFunctions.Contains(delegateFunc))
205 CanDeleteObjectCheckFunctions.Add(delegateFunc);
206 }
207
208 public void RemoveDeleteObjectHandler(CanDeleteObjectHandler delegateFunc)
209 {
210 if (CanDeleteObjectCheckFunctions.Contains(delegateFunc))
211 CanDeleteObjectCheckFunctions.Remove(delegateFunc);
212 }
213
214 public bool CanDeleteObject(UUID objectID, UUID deleter)
215 {
216 foreach (CanDeleteObjectHandler check in CanDeleteObjectCheckFunctions)
217 {
218 if (check(objectID,deleter,m_scene) == false)
219 {
220 return false;
221 }
222 }
223 return true;
224 }
225
226 #endregion
227
228 #region TAKE OBJECT
229 public delegate bool CanTakeObjectHandler(UUID objectID, UUID stealer, Scene scene);
230 private List<CanTakeObjectHandler> CanTakeObjectCheckFunctions = new List<CanTakeObjectHandler>();
231
232 public void AddTakeObjectHandler(CanTakeObjectHandler delegateFunc)
233 {
234 if (!CanTakeObjectCheckFunctions.Contains(delegateFunc))
235 CanTakeObjectCheckFunctions.Add(delegateFunc);
236 }
237
238 public void RemoveTakeObjectHandler(CanTakeObjectHandler delegateFunc)
239 {
240 if (CanTakeObjectCheckFunctions.Contains(delegateFunc))
241 CanTakeObjectCheckFunctions.Remove(delegateFunc);
242 }
243
244 public bool CanTakeObject(UUID objectID, UUID AvatarTakingUUID)
245 {
246 foreach (CanTakeObjectHandler check in CanTakeObjectCheckFunctions)
247 {
248 if (check(objectID, AvatarTakingUUID, m_scene) == false)
249 {
250 return false;
251 }
252 }
253 return true;
254 }
255
256 #endregion
257
258 #region TAKE COPY OBJECT
259 public delegate bool CanTakeCopyObjectHandler(UUID objectID, UUID userID, Scene inScene);
260 private List<CanTakeCopyObjectHandler> CanTakeCopyObjectCheckFunctions = new List<CanTakeCopyObjectHandler>();
261
262 public void AddTakeCopyObjectHandler(CanTakeCopyObjectHandler delegateFunc)
263 {
264 if (!CanTakeCopyObjectCheckFunctions.Contains(delegateFunc))
265 CanTakeCopyObjectCheckFunctions.Add(delegateFunc);
266 }
267
268 public void RemoveTakeCopyObjectHandler(CanTakeCopyObjectHandler delegateFunc)
269 {
270 if (CanTakeCopyObjectCheckFunctions.Contains(delegateFunc))
271 CanTakeCopyObjectCheckFunctions.Remove(delegateFunc);
272 }
273
274 public bool CanTakeCopyObject(UUID objectID, UUID userID)
275 {
276 foreach (CanTakeCopyObjectHandler check in CanTakeCopyObjectCheckFunctions)
277 {
278 if (check(objectID,userID,m_scene) == false)
279 {
280 return false;
281 }
282 }
283 return true;
284 }
285
286 #endregion
287
288 #region DUPLICATE OBJECT
289 public delegate bool CanDuplicateObjectHandler(int objectCount, UUID objectID, UUID owner, Scene scene, Vector3 objectPosition);
290 private List<CanDuplicateObjectHandler> CanDuplicateObjectCheckFunctions = new List<CanDuplicateObjectHandler>();
291
292 public void AddDuplicateObjectHandler(CanDuplicateObjectHandler delegateFunc)
293 {
294 if (!CanDuplicateObjectCheckFunctions.Contains(delegateFunc))
295 CanDuplicateObjectCheckFunctions.Add(delegateFunc);
296 }
297
298 public void RemoveDuplicateObjectHandler(CanDuplicateObjectHandler delegateFunc)
299 {
300 if (CanDuplicateObjectCheckFunctions.Contains(delegateFunc))
301 CanDuplicateObjectCheckFunctions.Remove(delegateFunc);
302 }
303
304 public bool CanDuplicateObject(int objectCount, UUID objectID, UUID owner, Vector3 objectPosition)
305 {
306 foreach (CanDuplicateObjectHandler check in CanDuplicateObjectCheckFunctions)
307 {
308 if (check(objectCount, objectID, owner, m_scene, objectPosition) == false)
309 {
310 return false;
311 }
312 }
313 return true;
314 }
315
316 #endregion
317
318 #region EDIT OBJECT
319 public delegate bool CanEditObjectHandler(UUID objectID, UUID editorID, Scene scene);
320 private List<CanEditObjectHandler> CanEditObjectCheckFunctions = new List<CanEditObjectHandler>();
321
322 public void AddEditObjectHandler(CanEditObjectHandler delegateFunc)
323 {
324 if (!CanEditObjectCheckFunctions.Contains(delegateFunc))
325 CanEditObjectCheckFunctions.Add(delegateFunc);
326 }
327
328 public void RemoveEditObjectHandler(CanEditObjectHandler delegateFunc)
329 {
330 if (CanEditObjectCheckFunctions.Contains(delegateFunc))
331 CanEditObjectCheckFunctions.Remove(delegateFunc);
332 }
333
334 public bool CanEditObject(UUID objectID, UUID editorID)
335 {
336 foreach (CanEditObjectHandler check in CanEditObjectCheckFunctions)
337 {
338 if (check(objectID, editorID, m_scene) == false)
339 {
340 return false;
341 }
342 }
343 return true;
344 }
345
346 public delegate bool CanEditObjectInventoryHandler(UUID objectID, UUID editorID, Scene scene);
347 private List<CanEditObjectInventoryHandler> CanEditObjectInventoryCheckFunctions = new List<CanEditObjectInventoryHandler>();
348
349 public void AddEditObjectInventoryHandler(CanEditObjectInventoryHandler delegateFunc)
350 {
351 if (!CanEditObjectInventoryCheckFunctions.Contains(delegateFunc))
352 CanEditObjectInventoryCheckFunctions.Add(delegateFunc);
353 }
354
355 public void RemoveEditObjectInventoryHandler(CanEditObjectInventoryHandler delegateFunc)
356 {
357 if (CanEditObjectInventoryCheckFunctions.Contains(delegateFunc))
358 CanEditObjectInventoryCheckFunctions.Remove(delegateFunc);
359 }
360
361 public bool CanEditObjectInventory(UUID objectID, UUID editorID)
362 {
363 foreach (CanEditObjectInventoryHandler check in CanEditObjectInventoryCheckFunctions)
364 {
365 if (check(objectID, editorID, m_scene) == false)
366 {
367 return false;
368 }
369 }
370 return true;
371 }
372
373 #endregion
374
375 #region MOVE OBJECT
376 public delegate bool CanMoveObjectHandler(UUID objectID, UUID moverID, Scene scene);
377 private List<CanMoveObjectHandler> CanMoveObjectCheckFunctions = new List<CanMoveObjectHandler>();
378
379 public void AddMoveObjectHandler(CanMoveObjectHandler delegateFunc)
380 {
381 if (!CanMoveObjectCheckFunctions.Contains(delegateFunc))
382 CanMoveObjectCheckFunctions.Add(delegateFunc);
383 }
384
385 public void RemoveMoveObjectHandler(CanMoveObjectHandler delegateFunc)
386 {
387 if (CanMoveObjectCheckFunctions.Contains(delegateFunc))
388 CanMoveObjectCheckFunctions.Remove(delegateFunc);
389 }
390
391 public bool CanMoveObject(UUID objectID, UUID moverID)
392 {
393 foreach (CanMoveObjectHandler check in CanMoveObjectCheckFunctions)
394 {
395 if (check(objectID,moverID,m_scene) == false)
396 {
397 return false;
398 }
399 }
400 return true;
401 }
402
403 #endregion
404
405 #region OBJECT ENTRY
406 public delegate bool CanObjectEntryHandler(UUID objectID, bool enteringRegion, Vector3 newPoint, Scene scene);
407 private List<CanObjectEntryHandler> CanObjectEntryCheckFunctions = new List<CanObjectEntryHandler>();
408
409 public void AddObjectEntryHandler(CanObjectEntryHandler delegateFunc)
410 {
411 if (!CanObjectEntryCheckFunctions.Contains(delegateFunc))
412 CanObjectEntryCheckFunctions.Add(delegateFunc);
413 }
414
415 public void RemoveObjectEntryHandler(CanObjectEntryHandler delegateFunc)
416 {
417 if (CanObjectEntryCheckFunctions.Contains(delegateFunc))
418 CanObjectEntryCheckFunctions.Remove(delegateFunc);
419 }
420
421 public bool CanObjectEntry(UUID objectID, bool enteringRegion, Vector3 newPoint)
422 {
423 foreach (CanObjectEntryHandler check in CanObjectEntryCheckFunctions)
424 {
425 if (check(objectID, enteringRegion, newPoint, m_scene) == false)
426 {
427 return false;
428 }
429 }
430 return true;
431 }
432
433 #endregion
434
435 #region RETURN OBJECT
436 public delegate bool CanReturnObjectHandler(UUID objectID, UUID returnerID, Scene scene);
437 private List<CanReturnObjectHandler> CanReturnObjectCheckFunctions = new List<CanReturnObjectHandler>();
438
439 public void AddReturnObjectHandler(CanReturnObjectHandler delegateFunc)
440 {
441 if (!CanReturnObjectCheckFunctions.Contains(delegateFunc))
442 CanReturnObjectCheckFunctions.Add(delegateFunc);
443 }
444
445 public void RemoveReturnObjectHandler(CanReturnObjectHandler delegateFunc)
446 {
447 if (CanReturnObjectCheckFunctions.Contains(delegateFunc))
448 CanReturnObjectCheckFunctions.Remove(delegateFunc);
449 }
450
451 public bool CanReturnObject(UUID objectID, UUID returnerID)
452 {
453 foreach (CanReturnObjectHandler check in CanReturnObjectCheckFunctions)
454 {
455 if (check(objectID,returnerID,m_scene) == false)
456 {
457 return false;
458 }
459 }
460 return true;
461 }
462
463 #endregion
464
465 #region INSTANT MESSAGE
466 public delegate bool CanInstantMessageHandler(UUID user, UUID target, Scene startScene);
467 private List<CanInstantMessageHandler> CanInstantMessageCheckFunctions = new List<CanInstantMessageHandler>();
468
469 public void AddInstantMessageHandler(CanInstantMessageHandler delegateFunc)
470 {
471 if (!CanInstantMessageCheckFunctions.Contains(delegateFunc))
472 CanInstantMessageCheckFunctions.Add(delegateFunc);
473 }
474
475 public void RemoveInstantMessageHandler(CanInstantMessageHandler delegateFunc)
476 {
477 if (CanInstantMessageCheckFunctions.Contains(delegateFunc))
478 CanInstantMessageCheckFunctions.Remove(delegateFunc);
479 }
480
481 public bool CanInstantMessage(UUID user, UUID target)
482 {
483 foreach (CanInstantMessageHandler check in CanInstantMessageCheckFunctions)
484 {
485 if (check(user, target, m_scene) == false)
486 {
487 return false;
488 }
489 }
490 return true;
491 }
492
493 #endregion
494
495 #region INVENTORY TRANSFER
496 public delegate bool CanInventoryTransferHandler(UUID user, UUID target, Scene startScene);
497 private List<CanInventoryTransferHandler> CanInventoryTransferCheckFunctions = new List<CanInventoryTransferHandler>();
498
499 public void AddInventoryTransferHandler(CanInventoryTransferHandler delegateFunc)
500 {
501 if (!CanInventoryTransferCheckFunctions.Contains(delegateFunc))
502 CanInventoryTransferCheckFunctions.Add(delegateFunc);
503 }
504
505 public void RemoveInventoryTransferHandler(CanInventoryTransferHandler delegateFunc)
506 {
507 if (CanInventoryTransferCheckFunctions.Contains(delegateFunc))
508 CanInventoryTransferCheckFunctions.Remove(delegateFunc);
509 }
510
511 public bool CanInventoryTransfer(UUID user, UUID target)
512 {
513 foreach (CanInventoryTransferHandler check in CanInventoryTransferCheckFunctions)
514 {
515 if (check(user, target, m_scene) == false)
516 {
517 return false;
518 }
519 }
520 return true;
521 }
522
523 #endregion
524
525 #region VIEW SCRIPT
526 public delegate bool CanViewScriptHandler(UUID script, UUID objectID, UUID user, Scene scene);
527 private List<CanViewScriptHandler> CanViewScriptCheckFunctions = new List<CanViewScriptHandler>();
528
529 public void AddViewScriptHandler(CanViewScriptHandler delegateFunc)
530 {
531 if (!CanViewScriptCheckFunctions.Contains(delegateFunc))
532 CanViewScriptCheckFunctions.Add(delegateFunc);
533 }
534
535 public void RemoveViewScriptHandler(CanViewScriptHandler delegateFunc)
536 {
537 if (CanViewScriptCheckFunctions.Contains(delegateFunc))
538 CanViewScriptCheckFunctions.Remove(delegateFunc);
539 }
540
541 public bool CanViewScript(UUID script, UUID objectID, UUID user)
542 {
543 foreach (CanViewScriptHandler check in CanViewScriptCheckFunctions)
544 {
545 if (check(script, objectID, user, m_scene) == false)
546 {
547 return false;
548 }
549 }
550 return true;
551 }
552
553 public delegate bool CanViewNotecardHandler(UUID script, UUID objectID, UUID user, Scene scene);
554 private List<CanViewNotecardHandler> CanViewNotecardCheckFunctions = new List<CanViewNotecardHandler>();
555
556 public void AddViewNotecardHandler(CanViewNotecardHandler delegateFunc)
557 {
558 if (!CanViewNotecardCheckFunctions.Contains(delegateFunc))
559 CanViewNotecardCheckFunctions.Add(delegateFunc);
560 }
561
562 public void RemoveViewNotecardHandler(CanViewNotecardHandler delegateFunc)
563 {
564 if (CanViewNotecardCheckFunctions.Contains(delegateFunc))
565 CanViewNotecardCheckFunctions.Remove(delegateFunc);
566 }
567
568 public bool CanViewNotecard(UUID script, UUID objectID, UUID user)
569 {
570 foreach (CanViewNotecardHandler check in CanViewNotecardCheckFunctions)
571 {
572 if (check(script, objectID, user, m_scene) == false)
573 {
574 return false;
575 }
576 }
577 return true;
578 }
579
580 #endregion
581
582 #region EDIT SCRIPT
583 public delegate bool CanEditScriptHandler(UUID script, UUID objectID, UUID user, Scene scene);
584 private List<CanEditScriptHandler> CanEditScriptCheckFunctions = new List<CanEditScriptHandler>();
585
586 public void AddEditScriptHandler(CanEditScriptHandler delegateFunc)
587 {
588 if (!CanEditScriptCheckFunctions.Contains(delegateFunc))
589 CanEditScriptCheckFunctions.Add(delegateFunc);
590 }
591
592 public void RemoveEditScriptHandler(CanEditScriptHandler delegateFunc)
593 {
594 if (CanEditScriptCheckFunctions.Contains(delegateFunc))
595 CanEditScriptCheckFunctions.Remove(delegateFunc);
596 }
597
598 public bool CanEditScript(UUID script, UUID objectID, UUID user)
599 {
600 foreach (CanEditScriptHandler check in CanEditScriptCheckFunctions)
601 {
602 if (check(script, objectID, user, m_scene) == false)
603 {
604 return false;
605 }
606 }
607 return true;
608 }
609
610 public delegate bool CanEditNotecardHandler(UUID notecard, UUID objectID, UUID user, Scene scene);
611 private List<CanEditNotecardHandler> CanEditNotecardCheckFunctions = new List<CanEditNotecardHandler>();
612
613 public void AddEditNotecardHandler(CanEditNotecardHandler delegateFunc)
614 {
615 if (!CanEditNotecardCheckFunctions.Contains(delegateFunc))
616 CanEditNotecardCheckFunctions.Add(delegateFunc);
617 }
618
619 public void RemoveEditNotecardHandler(CanEditNotecardHandler delegateFunc)
620 {
621 if (CanEditNotecardCheckFunctions.Contains(delegateFunc))
622 CanEditNotecardCheckFunctions.Remove(delegateFunc);
623 }
624
625 public bool CanEditNotecard(UUID script, UUID objectID, UUID user)
626 {
627 foreach (CanEditNotecardHandler check in CanEditNotecardCheckFunctions)
628 {
629 if (check(script, objectID, user, m_scene) == false)
630 {
631 return false;
632 }
633 }
634 return true;
635 }
636
637 #endregion
638
639 #region RUN SCRIPT (When Script Placed in Object)
640 public delegate bool CanRunScriptHandler(UUID script, UUID objectID, UUID user, Scene scene);
641 private List<CanRunScriptHandler> CanRunScriptCheckFunctions = new List<CanRunScriptHandler>();
642
643 public void AddRunScriptHandler(CanRunScriptHandler delegateFunc)
644 {
645 if (!CanRunScriptCheckFunctions.Contains(delegateFunc))
646 CanRunScriptCheckFunctions.Add(delegateFunc);
647 }
648
649 public void RemoveRunScriptHandler(CanRunScriptHandler delegateFunc)
650 {
651 if (CanRunScriptCheckFunctions.Contains(delegateFunc))
652 CanRunScriptCheckFunctions.Remove(delegateFunc);
653 }
654
655 public bool CanRunScript(UUID script, UUID objectID, UUID user)
656 {
657 foreach (CanRunScriptHandler check in CanRunScriptCheckFunctions)
658 {
659 if (check(script, objectID, user, m_scene) == false)
660 {
661 return false;
662 }
663 }
664 return true;
665 }
666
667 #endregion
668
669 #region START SCRIPT (When Script run box is Checked after placed in object)
670 public delegate bool CanStartScriptHandler(UUID script, UUID user, Scene scene);
671 private List<CanStartScriptHandler> CanStartScriptCheckFunctions = new List<CanStartScriptHandler>();
672
673 public void AddStartScriptHandler(CanStartScriptHandler delegateFunc)
674 {
675 if (!CanStartScriptCheckFunctions.Contains(delegateFunc))
676 CanStartScriptCheckFunctions.Add(delegateFunc);
677 }
678
679 public void RemoveStartScriptHandler(CanStartScriptHandler delegateFunc)
680 {
681 if (CanStartScriptCheckFunctions.Contains(delegateFunc))
682 CanStartScriptCheckFunctions.Remove(delegateFunc);
683 }
684
685 public bool CanStartScript(UUID script, UUID user)
686 {
687 foreach (CanStartScriptHandler check in CanStartScriptCheckFunctions)
688 {
689 if (check(script, user, m_scene) == false)
690 {
691 return false;
692 }
693 }
694 return true;
695 }
696
697 #endregion
698
699 #region STOP SCRIPT (When Script run box is unchecked after placed in object)
700 public delegate bool CanStopScriptHandler(UUID script, UUID user, Scene scene);
701 private List<CanStopScriptHandler> CanStopScriptCheckFunctions = new List<CanStopScriptHandler>();
702
703 public void AddStopScriptHandler(CanStopScriptHandler delegateFunc)
704 {
705 if (!CanStopScriptCheckFunctions.Contains(delegateFunc))
706 CanStopScriptCheckFunctions.Add(delegateFunc);
707 }
708
709 public void RemoveStopScriptHandler(CanStopScriptHandler delegateFunc)
710 {
711 if (CanStopScriptCheckFunctions.Contains(delegateFunc))
712 CanStopScriptCheckFunctions.Remove(delegateFunc);
713 }
714
715 public bool CanStopScript(UUID script, UUID user)
716 {
717 foreach (CanStopScriptHandler check in CanStopScriptCheckFunctions)
718 {
719 if (check(script, user, m_scene) == false)
720 {
721 return false;
722 }
723 }
724 return true;
725 }
726
727 #endregion
728
729 #region RESET SCRIPT
730 public delegate bool CanResetScriptHandler(UUID prim, UUID script, UUID user, Scene scene);
731 private List<CanResetScriptHandler> CanResetScriptCheckFunctions = new List<CanResetScriptHandler>();
732
733 public void AddResetScriptHandler(CanResetScriptHandler delegateFunc)
734 {
735 if (!CanResetScriptCheckFunctions.Contains(delegateFunc))
736 CanResetScriptCheckFunctions.Add(delegateFunc);
737 }
738
739 public void RemoveResetScriptHandler(CanResetScriptHandler delegateFunc)
740 {
741 if (CanResetScriptCheckFunctions.Contains(delegateFunc))
742 CanResetScriptCheckFunctions.Remove(delegateFunc);
743 }
744
745 public bool CanResetScript(UUID prim, UUID script, UUID user)
746 {
747 foreach (CanResetScriptHandler check in CanResetScriptCheckFunctions)
748 {
749 if (check(prim, script, user, m_scene) == false)
750 {
751 return false;
752 }
753 }
754 return true;
755 }
756
757 #endregion
758
759 #region TERRAFORM LAND
760 public delegate bool CanTerraformLandHandler(UUID user, Vector3 position, Scene requestFromScene);
761 private List<CanTerraformLandHandler> CanTerraformLandCheckFunctions = new List<CanTerraformLandHandler>();
762
763 public void AddTerraformLandHandler(CanTerraformLandHandler delegateFunc)
764 {
765 if (!CanTerraformLandCheckFunctions.Contains(delegateFunc))
766 CanTerraformLandCheckFunctions.Add(delegateFunc);
767 }
768
769 public void RemoveTerraformLandHandler(CanTerraformLandHandler delegateFunc)
770 {
771 if (CanTerraformLandCheckFunctions.Contains(delegateFunc))
772 CanTerraformLandCheckFunctions.Remove(delegateFunc);
773 }
774
775 public bool CanTerraformLand(UUID user, Vector3 pos)
776 {
777 foreach (CanTerraformLandHandler check in CanTerraformLandCheckFunctions)
778 {
779 if (check(user, pos, m_scene) == false)
780 {
781 return false;
782 }
783 }
784 return true;
785 }
786
787 #endregion
788
789 #region RUN CONSOLE COMMAND
790 public delegate bool CanRunConsoleCommandHandler(UUID user, Scene requestFromScene);
791 private List<CanRunConsoleCommandHandler> CanRunConsoleCommandCheckFunctions = new List<CanRunConsoleCommandHandler>();
792
793 public void AddRunConsoleCommandHandler(CanRunConsoleCommandHandler delegateFunc)
794 {
795 if (!CanRunConsoleCommandCheckFunctions.Contains(delegateFunc))
796 CanRunConsoleCommandCheckFunctions.Add(delegateFunc);
797 }
798
799 public void RemoveRunConsoleCommandHandler(CanRunConsoleCommandHandler delegateFunc)
800 {
801 if (CanRunConsoleCommandCheckFunctions.Contains(delegateFunc))
802 CanRunConsoleCommandCheckFunctions.Remove(delegateFunc);
803 }
804
805 public bool CanRunConsoleCommand(UUID user)
806 {
807 foreach (CanRunConsoleCommandHandler check in CanRunConsoleCommandCheckFunctions)
808 {
809 if (check(user, m_scene) == false)
810 {
811 return false;
812 }
813 }
814 return true;
815 }
816
817 #endregion
818
819 #region CAN ISSUE ESTATE COMMAND
820 public delegate bool CanIssueEstateCommandHandler(UUID user, Scene requestFromScene, bool ownerCommand);
821 private List<CanIssueEstateCommandHandler> CanIssueEstateCommandCheckFunctions = new List<CanIssueEstateCommandHandler>();
822
823 public void AddIssueEstateCommandHandler(CanIssueEstateCommandHandler delegateFunc)
824 {
825 if (!CanIssueEstateCommandCheckFunctions.Contains(delegateFunc))
826 CanIssueEstateCommandCheckFunctions.Add(delegateFunc);
827 }
828
829 public void RemoveIssueEstateCommandHandler(CanIssueEstateCommandHandler delegateFunc)
830 {
831 if (CanIssueEstateCommandCheckFunctions.Contains(delegateFunc))
832 CanIssueEstateCommandCheckFunctions.Remove(delegateFunc);
833 }
834
835 public bool CanIssueEstateCommand(UUID user, bool ownerCommand)
836 {
837 foreach (CanIssueEstateCommandHandler check in CanIssueEstateCommandCheckFunctions)
838 {
839 if (check(user, m_scene, ownerCommand) == false)
840 {
841 return false;
842 }
843 }
844 return true;
845 }
846 #endregion
847
848 #region CAN BE GODLIKE
849 public delegate bool IsGodHandler(UUID user, Scene requestFromScene);
850 private List<IsGodHandler> IsGodCheckFunctions = new List<IsGodHandler>();
851
852 public void AddIsGodHandler(IsGodHandler delegateFunc)
853 {
854 if (!IsGodCheckFunctions.Contains(delegateFunc))
855 IsGodCheckFunctions.Add(delegateFunc);
856 }
857
858 public void RemoveIsGodHandler(IsGodHandler delegateFunc)
859 {
860 if (IsGodCheckFunctions.Contains(delegateFunc))
861 IsGodCheckFunctions.Remove(delegateFunc);
862 }
863
864 public bool IsGod(UUID user)
865 {
866 foreach (IsGodHandler check in IsGodCheckFunctions)
867 {
868 if (check(user, m_scene) == false)
869 {
870 return false;
871 }
872 }
873 return true;
874 }
875 #endregion
876
877 #region EDIT PARCEL
878 public delegate bool CanEditParcelHandler(UUID user, ILandObject parcel, Scene scene);
879 private List<CanEditParcelHandler> CanEditParcelCheckFunctions = new List<CanEditParcelHandler>();
880
881 public void AddEditParcelHandler(CanEditParcelHandler delegateFunc)
882 {
883 if (!CanEditParcelCheckFunctions.Contains(delegateFunc))
884 CanEditParcelCheckFunctions.Add(delegateFunc);
885 }
886
887 public void RemoveEditParcelHandler(CanEditParcelHandler delegateFunc)
888 {
889 if (CanEditParcelCheckFunctions.Contains(delegateFunc))
890 CanEditParcelCheckFunctions.Remove(delegateFunc);
891 }
892
893 public bool CanEditParcel(UUID user, ILandObject parcel)
894 {
895 foreach (CanEditParcelHandler check in CanEditParcelCheckFunctions)
896 {
897 if (check(user, parcel, m_scene) == false)
898 {
899 return false;
900 }
901 }
902 return true;
903 }
904 #endregion
905
906 #region SELL PARCEL
907 public delegate bool CanSellParcelHandler(UUID user, ILandObject parcel, Scene scene);
908 private List<CanSellParcelHandler> CanSellParcelCheckFunctions = new List<CanSellParcelHandler>();
909
910 public void AddSellParcelHandler(CanSellParcelHandler delegateFunc)
911 {
912 if (!CanSellParcelCheckFunctions.Contains(delegateFunc))
913 CanSellParcelCheckFunctions.Add(delegateFunc);
914 }
915
916 public void RemoveSellParcelHandler(CanSellParcelHandler delegateFunc)
917 {
918 if (CanSellParcelCheckFunctions.Contains(delegateFunc))
919 CanSellParcelCheckFunctions.Remove(delegateFunc);
920 }
921
922 public bool CanSellParcel(UUID user, ILandObject parcel)
923 {
924 foreach (CanSellParcelHandler check in CanSellParcelCheckFunctions)
925 {
926 if (check(user, parcel, m_scene) == false)
927 {
928 return false;
929 }
930 }
931 return true;
932 }
933 #endregion
934
935 #region ABANDON PARCEL
936 public delegate bool CanAbandonParcelHandler(UUID user, ILandObject parcel, Scene scene);
937 private List<CanAbandonParcelHandler> CanAbandonParcelCheckFunctions = new List<CanAbandonParcelHandler>();
938
939 public void AddAbandonParcelHandler(CanAbandonParcelHandler delegateFunc)
940 {
941 if (!CanAbandonParcelCheckFunctions.Contains(delegateFunc))
942 CanAbandonParcelCheckFunctions.Add(delegateFunc);
943 }
944
945 public void RemoveAbandonParcelHandler(CanAbandonParcelHandler delegateFunc)
946 {
947 if (CanAbandonParcelCheckFunctions.Contains(delegateFunc))
948 CanAbandonParcelCheckFunctions.Remove(delegateFunc);
949 }
950
951 public bool CanAbandonParcel(UUID user, ILandObject parcel)
952 {
953 foreach (CanAbandonParcelHandler check in CanAbandonParcelCheckFunctions)
954 {
955 if (check(user, parcel, m_scene) == false)
956 {
957 return false;
958 }
959 }
960 return true;
961 }
962 #endregion
963
964 public delegate bool CanReclaimParcelHandler(UUID user, ILandObject parcel, Scene scene);
965 private List<CanReclaimParcelHandler> CanReclaimParcelCheckFunctions = new List<CanReclaimParcelHandler>();
966
967 public void AddReclaimParcelHandler(CanReclaimParcelHandler delegateFunc)
968 {
969 if (!CanReclaimParcelCheckFunctions.Contains(delegateFunc))
970 CanReclaimParcelCheckFunctions.Add(delegateFunc);
971 }
972
973 public void RemoveReclaimParcelHandler(CanReclaimParcelHandler delegateFunc)
974 {
975 if (CanReclaimParcelCheckFunctions.Contains(delegateFunc))
976 CanReclaimParcelCheckFunctions.Remove(delegateFunc);
977 }
978
979 public bool CanReclaimParcel(UUID user, ILandObject parcel)
980 {
981 foreach (CanReclaimParcelHandler check in CanReclaimParcelCheckFunctions)
982 {
983 if (check(user, parcel, m_scene) == false)
984 {
985 return false;
986 }
987 }
988 return true;
989 }
990 public delegate bool CanBuyLandHandler(UUID user, ILandObject parcel, Scene scene);
991 private List<CanBuyLandHandler> CanBuyLandCheckFunctions = new List<CanBuyLandHandler>();
992
993 public void AddCanBuyLandHandler(CanBuyLandHandler delegateFunc)
994 {
995 if (!CanBuyLandCheckFunctions.Contains(delegateFunc))
996 CanBuyLandCheckFunctions.Add(delegateFunc);
997 }
998
999 public void RemoveCanBuyLandHandler(CanBuyLandHandler delegateFunc)
1000 {
1001 if (CanBuyLandCheckFunctions.Contains(delegateFunc))
1002 CanBuyLandCheckFunctions.Remove(delegateFunc);
1003 }
1004
1005 public bool CanBuyLand(UUID user, ILandObject parcel)
1006 {
1007 foreach (CanBuyLandHandler check in CanBuyLandCheckFunctions)
1008 {
1009 if (check(user, parcel, m_scene) == false)
1010 {
1011 return false;
1012 }
1013 }
1014 return true;
1015 }
1016
1017 public delegate bool CanLinkObjectHandler(UUID user, UUID objectID);
1018 private List<CanLinkObjectHandler> CanLinkObjectCheckFunctions = new List<CanLinkObjectHandler>();
1019
1020 public void AddCanLinkObjectHandler(CanLinkObjectHandler delegateFunc)
1021 {
1022 if (!CanLinkObjectCheckFunctions.Contains(delegateFunc))
1023 CanLinkObjectCheckFunctions.Add(delegateFunc);
1024 }
1025
1026 public void RemoveCanLinkObjectHandler(CanLinkObjectHandler delegateFunc)
1027 {
1028 if (CanLinkObjectCheckFunctions.Contains(delegateFunc))
1029 CanLinkObjectCheckFunctions.Remove(delegateFunc);
1030 }
1031
1032 public bool CanLinkObject(UUID user, UUID objectID)
1033 {
1034 foreach (CanLinkObjectHandler check in CanLinkObjectCheckFunctions)
1035 {
1036 if (check(user, objectID) == false)
1037 {
1038 return false;
1039 }
1040 }
1041 return true;
1042 }
1043
1044 public delegate bool CanDelinkObjectHandler(UUID user, UUID objectID);
1045 private List<CanDelinkObjectHandler> CanDelinkObjectCheckFunctions = new List<CanDelinkObjectHandler>();
1046
1047 public void AddCanDelinkObjectHandler(CanDelinkObjectHandler delegateFunc)
1048 {
1049 if (!CanDelinkObjectCheckFunctions.Contains(delegateFunc))
1050 CanDelinkObjectCheckFunctions.Add(delegateFunc);
1051 }
1052
1053 public void RemoveCanDelinkObjectHandler(CanDelinkObjectHandler delegateFunc)
1054 {
1055 if (CanDelinkObjectCheckFunctions.Contains(delegateFunc))
1056 CanDelinkObjectCheckFunctions.Remove(delegateFunc);
1057 }
1058
1059 public bool CanDelinkObject(UUID user, UUID objectID)
1060 {
1061 foreach (CanDelinkObjectHandler check in CanDelinkObjectCheckFunctions)
1062 {
1063 if (check(user, objectID) == false)
1064 {
1065 return false;
1066 }
1067 }
1068 return true;
1069 }
1070
1071 #endregion
1072
1073 public delegate bool CanCreateObjectInventoryHandler(int invType, UUID objectID, UUID userID);
1074 private List<CanCreateObjectInventoryHandler> CanCreateObjectInventoryCheckFunctions
1075 = new List<CanCreateObjectInventoryHandler>();
1076
1077
1078 public void AddCanCreateObjectInventoryHandler(CanCreateObjectInventoryHandler delegateFunc)
1079 {
1080 if (!CanCreateObjectInventoryCheckFunctions.Contains(delegateFunc))
1081 CanCreateObjectInventoryCheckFunctions.Add(delegateFunc);
1082 }
1083
1084 public void RemoveCanCreateObjectInventoryHandler(CanCreateObjectInventoryHandler delegateFunc)
1085 {
1086 if (CanCreateObjectInventoryCheckFunctions.Contains(delegateFunc))
1087 CanCreateObjectInventoryCheckFunctions.Remove(delegateFunc);
1088 }
1089
1090 /// <summary>
1091 /// Check whether the specified user is allowed to directly create the given inventory type in a prim's
1092 /// inventory (e.g. the New Script button in the 1.21 Linden Lab client).
1093 /// </summary>
1094 /// <param name="invType"></param>
1095 /// <param name="objectID"></param>
1096 /// <param name="userID"></param>
1097 /// <returns></returns>
1098 public bool CanCreateObjectInventory(int invType, UUID objectID, UUID userID)
1099 {
1100 foreach (CanCreateObjectInventoryHandler check in CanCreateObjectInventoryCheckFunctions)
1101 {
1102 if (check(invType, objectID, userID) == false)
1103 {
1104 return false;
1105 }
1106 }
1107
1108 return true;
1109 }
1110
1111 public delegate bool CanCopyObjectInventoryHandler(UUID itemID, UUID objectID, UUID userID);
1112 private List<CanCopyObjectInventoryHandler> CanCopyObjectInventoryCheckFunctions = new List<CanCopyObjectInventoryHandler>();
1113
1114 public void AddCanCopyObjectInventoryHandler(CanCopyObjectInventoryHandler delegateFunc)
1115 {
1116 if (!CanCopyObjectInventoryCheckFunctions.Contains(delegateFunc))
1117 CanCopyObjectInventoryCheckFunctions.Add(delegateFunc);
1118 }
1119
1120 public void RemoveCanCopyObjectInventoryHandler(CanCopyObjectInventoryHandler delegateFunc)
1121 {
1122 if (CanCopyObjectInventoryCheckFunctions.Contains(delegateFunc))
1123 CanCopyObjectInventoryCheckFunctions.Remove(delegateFunc);
1124 }
1125
1126 public bool CanCopyObjectInventory(UUID itemID, UUID objectID, UUID userID)
1127 {
1128 foreach (CanCopyObjectInventoryHandler check in CanCopyObjectInventoryCheckFunctions)
1129 {
1130 if (check(itemID, objectID, userID) == false)
1131 {
1132 return false;
1133 }
1134 }
1135 return true;
1136 }
1137
1138 public delegate bool CanDeleteObjectInventoryHandler(UUID itemID, UUID objectID, UUID userID);
1139 private List<CanDeleteObjectInventoryHandler> CanDeleteObjectInventoryCheckFunctions
1140 = new List<CanDeleteObjectInventoryHandler>();
1141
1142 public void AddCanDeleteObjectInventoryHandler(CanDeleteObjectInventoryHandler delegateFunc)
1143 {
1144 if (!CanDeleteObjectInventoryCheckFunctions.Contains(delegateFunc))
1145 CanDeleteObjectInventoryCheckFunctions.Add(delegateFunc);
1146 }
1147
1148 public void RemoveCanDeleteObjectInventoryHandler(CanDeleteObjectInventoryHandler delegateFunc)
1149 {
1150 if (CanDeleteObjectInventoryCheckFunctions.Contains(delegateFunc))
1151 CanDeleteObjectInventoryCheckFunctions.Remove(delegateFunc);
1152 }
1153
1154 public bool CanDeleteObjectInventory(UUID itemID, UUID objectID, UUID userID)
1155 {
1156 foreach (CanDeleteObjectInventoryHandler check in CanDeleteObjectInventoryCheckFunctions)
1157 {
1158 if (check(itemID, objectID, userID) == false)
1159 {
1160 return false;
1161 }
1162 }
1163
1164 return true;
1165 }
1166
1167 public delegate bool CanCreateUserInventoryHandler(int invType, UUID userID);
1168 private List<CanCreateUserInventoryHandler> CanCreateUserInventoryCheckFunctions
1169 = new List<CanCreateUserInventoryHandler>();
1170
1171 public void AddCanCreateUserInventoryHandler(CanCreateUserInventoryHandler delegateFunc)
1172 {
1173 if (!CanCreateUserInventoryCheckFunctions.Contains(delegateFunc))
1174 CanCreateUserInventoryCheckFunctions.Add(delegateFunc);
1175 }
1176
1177 public void RemoveCanCreateUserInventoryHandler(CanCreateUserInventoryHandler delegateFunc)
1178 {
1179 if (CanCreateUserInventoryCheckFunctions.Contains(delegateFunc))
1180 CanCreateUserInventoryCheckFunctions.Remove(delegateFunc);
1181 }
1182
1183 /// <summary>
1184 /// Check whether the specified user is allowed to create the given inventory type in their inventory.
1185 /// </summary>
1186 /// <param name="invType"></param>
1187 /// <param name="userID"></param>
1188 /// <returns></returns>
1189 public bool CanCreateUserInventory(int invType, UUID userID)
1190 {
1191 foreach (CanCreateUserInventoryHandler check in CanCreateUserInventoryCheckFunctions)
1192 {
1193 if (check(invType, userID) == false)
1194 {
1195 return false;
1196 }
1197 }
1198
1199 return true;
1200 }
1201
1202 public delegate bool CanEditUserInventoryHandler(UUID itemID, UUID userID);
1203 private List<CanEditUserInventoryHandler> CanEditUserInventoryCheckFunctions
1204 = new List<CanEditUserInventoryHandler>();
1205
1206 public void AddCanEditUserInventoryHandler(CanEditUserInventoryHandler delegateFunc)
1207 {
1208 if (!CanEditUserInventoryCheckFunctions.Contains(delegateFunc))
1209 CanEditUserInventoryCheckFunctions.Add(delegateFunc);
1210 }
1211
1212 public void RemoveCanEditUserInventoryHandler(CanEditUserInventoryHandler delegateFunc)
1213 {
1214 if (CanEditUserInventoryCheckFunctions.Contains(delegateFunc))
1215 CanEditUserInventoryCheckFunctions.Remove(delegateFunc);
1216 }
1217
1218 /// <summary>
1219 /// Check whether the specified user is allowed to edit the given inventory item within their own inventory.
1220 /// </summary>
1221 /// <param name="itemID"></param>
1222 /// <param name="userID"></param>
1223 /// <returns></returns>
1224 public bool CanEditUserInventory(UUID itemID, UUID userID)
1225 {
1226 foreach (CanEditUserInventoryHandler check in CanEditUserInventoryCheckFunctions)
1227 {
1228 if (check(itemID, userID) == false)
1229 {
1230 return false;
1231 }
1232 }
1233
1234 return true;
1235 }
1236
1237 public delegate bool CanCopyUserInventoryHandler(UUID itemID, UUID userID);
1238 private List<CanCopyUserInventoryHandler> CanCopyUserInventoryCheckFunctions
1239 = new List<CanCopyUserInventoryHandler>();
1240
1241 public void AddCanCopyUserInventoryHandler(CanCopyUserInventoryHandler delegateFunc)
1242 {
1243 if (!CanCopyUserInventoryCheckFunctions.Contains(delegateFunc))
1244 CanCopyUserInventoryCheckFunctions.Add(delegateFunc);
1245 }
1246
1247 public void RemoveCanCopyUserInventoryHandler(CanCopyUserInventoryHandler delegateFunc)
1248 {
1249 if (CanCopyUserInventoryCheckFunctions.Contains(delegateFunc))
1250 CanCopyUserInventoryCheckFunctions.Remove(delegateFunc);
1251 }
1252
1253 /// <summary>
1254 /// Check whether the specified user is allowed to copy the given inventory item from their own inventory.
1255 /// </summary>
1256 /// <param name="itemID"></param>
1257 /// <param name="userID"></param>
1258 /// <returns></returns>
1259 public bool CanCopyUserInventory(UUID itemID, UUID userID)
1260 {
1261 foreach (CanCopyUserInventoryHandler check in CanCopyUserInventoryCheckFunctions)
1262 {
1263 if (check(itemID, userID) == false)
1264 {
1265 return false;
1266 }
1267 }
1268
1269 return true;
1270 }
1271
1272 public delegate bool CanDeleteUserInventoryHandler(UUID itemID, UUID userID);
1273 private List<CanDeleteUserInventoryHandler> CanDeleteUserInventoryCheckFunctions
1274 = new List<CanDeleteUserInventoryHandler>();
1275
1276 public void AddCanDeleteUserInventoryHandler(CanDeleteUserInventoryHandler delegateFunc)
1277 {
1278 if (!CanDeleteUserInventoryCheckFunctions.Contains(delegateFunc))
1279 CanDeleteUserInventoryCheckFunctions.Add(delegateFunc);
1280 }
1281
1282 public void RemoveCanDeleteUserInventoryHandler(CanDeleteUserInventoryHandler delegateFunc)
1283 {
1284 if (CanDeleteUserInventoryCheckFunctions.Contains(delegateFunc))
1285 CanDeleteUserInventoryCheckFunctions.Remove(delegateFunc);
1286 }
1287
1288 /// <summary>
1289 /// Check whether the specified user is allowed to edit the given inventory item within their own inventory.
1290 /// </summary>
1291 /// <param name="itemID"></param>
1292 /// <param name="userID"></param>
1293 /// <returns></returns>
1294 public bool CanDeleteUserInventory(UUID itemID, UUID userID)
1295 {
1296 foreach (CanDeleteUserInventoryHandler check in CanDeleteUserInventoryCheckFunctions)
1297 {
1298 if (check(itemID, userID) == false)
1299 {
1300 return false;
1301 }
1302 }
1303
1304 return true;
1305 }
1306
1307 public delegate bool CanTeleportHandler(UUID userID);
1308 private List<CanTeleportHandler> CanTeleportCheckFunctions = new List<CanTeleportHandler>();
1309
1310 public void AddCanTeleportHandler(CanTeleportHandler delegateFunc)
1311 {
1312 if (!CanTeleportCheckFunctions.Contains(delegateFunc))
1313 CanTeleportCheckFunctions.Add(delegateFunc);
1314 }
1315
1316 public void RemoveCanTeleportHandler(CanTeleportHandler delegateFunc)
1317 {
1318 if (CanTeleportCheckFunctions.Contains(delegateFunc))
1319 CanTeleportCheckFunctions.Remove(delegateFunc);
1320 }
1321
1322 public bool CanTeleport(UUID userID)
1323 {
1324 foreach (CanTeleportHandler check in CanTeleportCheckFunctions)
1325 {
1326 if (check(userID) == false)
1327 {
1328 return false;
1329 }
1330 }
1331 return true;
1332 }
1333 }
1334}
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
new file mode 100644
index 0000000..f07391d
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -0,0 +1,4239 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Drawing;
31using System.Drawing.Imaging;
32using System.IO;
33using System.Xml;
34using System.Threading;
35using System.Timers;
36using OpenMetaverse;
37using OpenMetaverse.Imaging;
38using OpenMetaverse.Packets;
39using OpenSim.Framework;
40using OpenSim.Framework.Communications;
41using OpenSim.Framework.Communications.Cache;
42using OpenSim.Framework.Servers;
43using OpenSim.Region.Framework.Interfaces;
44using OpenSim.Region.Framework.Scenes.Scripting;
45using OpenSim.Region.Physics.Manager;
46using Nini.Config;
47using Caps = OpenSim.Framework.Communications.Capabilities.Caps;
48using Image = System.Drawing.Image;
49using TPFlags = OpenSim.Framework.Constants.TeleportFlags;
50using Timer = System.Timers.Timer;
51using OSD = OpenMetaverse.StructuredData.OSD;
52
53namespace OpenSim.Region.Framework.Scenes
54{
55 public delegate bool FilterAvatarList(ScenePresence avatar);
56
57 public partial class Scene : SceneBase
58 {
59 public delegate void SynchronizeSceneHandler(Scene scene);
60 public SynchronizeSceneHandler SynchronizeScene = null;
61 public int splitID = 0;
62
63 private const long DEFAULT_MIN_TIME_FOR_PERSISTENCE = 60L;
64 private const long DEFAULT_MAX_TIME_FOR_PERSISTENCE = 600L;
65
66 #region Fields
67
68 protected Timer m_restartWaitTimer = new Timer();
69
70 public SimStatsReporter StatsReporter;
71
72 protected List<RegionInfo> m_regionRestartNotifyList = new List<RegionInfo>();
73 protected List<RegionInfo> m_neighbours = new List<RegionInfo>();
74
75 /// <value>
76 /// The scene graph for this scene
77 /// </value>
78 /// TODO: Possibly stop other classes being able to manipulate this directly.
79 public SceneGraph m_sceneGraph;
80
81 /// <summary>
82 /// Are we applying physics to any of the prims in this scene?
83 /// </summary>
84 public bool m_physicalPrim;
85 public float m_maxNonphys = 65536;
86 public float m_maxPhys = 10;
87 public bool m_clampPrimSize = false;
88 public bool m_trustBinaries = false;
89 public bool m_allowScriptCrossings = false;
90
91 public bool m_seeIntoRegionFromNeighbor;
92 public int MaxUndoCount = 5;
93 private int m_RestartTimerCounter;
94 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
95 private int m_incrementsof15seconds = 0;
96 private volatile bool m_backingup = false;
97
98 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
99
100 protected string m_simulatorVersion = "OpenSimulator Server";
101
102 protected ModuleLoader m_moduleLoader;
103 protected StorageManager m_storageManager;
104 protected AgentCircuitManager m_authenticateHandler;
105 public CommunicationsManager CommsManager;
106
107 protected SceneCommunicationService m_sceneGridService;
108
109 public SceneCommunicationService SceneGridService
110 {
111 get { return m_sceneGridService; }
112 }
113
114 public IXfer XferManager;
115
116 protected IXMLRPC m_xmlrpcModule;
117 protected IWorldComm m_worldCommModule;
118 protected IAvatarFactory m_AvatarFactory;
119 protected IConfigSource m_config;
120 protected IRegionSerialiserModule m_serialiser;
121 protected IInterregionCommsOut m_interregionCommsOut;
122 protected IInterregionCommsIn m_interregionCommsIn;
123 protected IDialogModule m_dialogModule;
124
125 protected ICapabilitiesModule m_capsModule;
126 public ICapabilitiesModule CapsModule
127 {
128 get { return m_capsModule; }
129 }
130
131 // Central Update Loop
132
133 protected int m_fps = 10;
134 protected int m_frame = 0;
135 protected float m_timespan = 0.089f;
136 protected DateTime m_lastupdate = DateTime.Now;
137
138 protected float m_timedilation = 1.0f;
139
140 private int m_update_physics = 1;
141 private int m_update_entitymovement = 1;
142 private int m_update_entities = 1; // Run through all objects checking for updates
143 private int m_update_entitiesquick = 200; // Run through objects that have scheduled updates checking for updates
144 private int m_update_presences = 1; // Update scene presence movements
145 private int m_update_events = 1;
146 private int m_update_backup = 200;
147 private int m_update_terrain = 50;
148 private int m_update_land = 1;
149
150 private int frameMS = 0;
151 private int physicsMS2 = 0;
152 private int physicsMS = 0;
153 private int otherMS = 0;
154
155 private bool m_physics_enabled = true;
156 private bool m_scripts_enabled = true;
157 private string m_defaultScriptEngine;
158 private int m_LastLogin = 0;
159 private Thread HeartbeatThread;
160 private volatile bool shuttingdown = false;
161
162 private object m_deleting_scene_object = new object();
163
164 // the minimum time that must elapse before a changed object will be considered for persisted
165 public long m_dontPersistBefore = DEFAULT_MIN_TIME_FOR_PERSISTENCE * 10000000L;
166 // the maximum time that must elapse before a changed object will be considered for persisted
167 public long m_persistAfter = DEFAULT_MAX_TIME_FOR_PERSISTENCE * 10000000L;
168
169 #endregion
170
171 #region Properties
172
173 public AgentCircuitManager AuthenticateHandler
174 {
175 get { return m_authenticateHandler; }
176 }
177
178 public SceneGraph SceneContents
179 {
180 get { return m_sceneGraph; }
181 }
182
183 // an instance to the physics plugin's Scene object.
184 public PhysicsScene PhysicsScene
185 {
186 get { return m_sceneGraph.PhysicsScene; }
187 set
188 {
189 // If we're not doing the initial set
190 // Then we've got to remove the previous
191 // event handler
192 if (PhysicsScene != null && PhysicsScene.SupportsNINJAJoints)
193 {
194 PhysicsScene.OnJointMoved -= jointMoved;
195 PhysicsScene.OnJointDeactivated -= jointDeactivated;
196 PhysicsScene.OnJointErrorMessage -= jointErrorMessage;
197 }
198
199 m_sceneGraph.PhysicsScene = value;
200
201 if (PhysicsScene != null && m_sceneGraph.PhysicsScene.SupportsNINJAJoints)
202 {
203 // register event handlers to respond to joint movement/deactivation
204 PhysicsScene.OnJointMoved += jointMoved;
205 PhysicsScene.OnJointDeactivated += jointDeactivated;
206 PhysicsScene.OnJointErrorMessage += jointErrorMessage;
207 }
208
209 }
210 }
211
212 // This gets locked so things stay thread safe.
213 public object SyncRoot
214 {
215 get { return m_sceneGraph.m_syncRoot; }
216 }
217
218 public float TimeDilation
219 {
220 get { return m_timedilation; }
221 }
222
223 /// <summary>
224 /// This is for llGetRegionFPS
225 /// </summary>
226 public float SimulatorFPS
227 {
228 get { return StatsReporter.getLastReportedSimFPS(); }
229 }
230
231 public string DefaultScriptEngine
232 {
233 get { return m_defaultScriptEngine; }
234 }
235
236 // Local reference to the objects in the scene (which are held in the scenegraph)
237 // public Dictionary<UUID, SceneObjectGroup> Objects
238 // {
239 // get { return m_sceneGraph.SceneObjects; }
240 // }
241
242 // Reference to all of the agents in the scene (root and child)
243 protected Dictionary<UUID, ScenePresence> m_scenePresences
244 {
245 get { return m_sceneGraph.ScenePresences; }
246 set { m_sceneGraph.ScenePresences = value; }
247 }
248
249 // protected Dictionary<UUID, SceneObjectGroup> m_sceneObjects
250 // {
251 // get { return m_sceneGraph.SceneObjects; }
252 // set { m_sceneGraph.SceneObjects = value; }
253 // }
254
255 public EntityManager Entities
256 {
257 get { return m_sceneGraph.Entities; }
258 }
259
260 public Dictionary<UUID, ScenePresence> m_restorePresences
261 {
262 get { return m_sceneGraph.RestorePresences; }
263 set { m_sceneGraph.RestorePresences = value; }
264 }
265
266 public int objectCapacity = 45000;
267
268 #endregion
269
270 #region Constructors
271
272 public Scene(RegionInfo regInfo, AgentCircuitManager authen,
273 CommunicationsManager commsMan, SceneCommunicationService sceneGridService,
274 AssetCache assetCach, StorageManager storeManager,
275 ModuleLoader moduleLoader, bool dumpAssetsToFile, bool physicalPrim,
276 bool SeeIntoRegionFromNeighbor, IConfigSource config, string simulatorVersion)
277 {
278 m_config = config;
279
280 Random random = new Random();
281 m_lastAllocatedLocalId = (uint)(random.NextDouble() * (double)(uint.MaxValue/2))+(uint)(uint.MaxValue/4);
282 m_moduleLoader = moduleLoader;
283 m_authenticateHandler = authen;
284 CommsManager = commsMan;
285 m_sceneGridService = sceneGridService;
286 m_storageManager = storeManager;
287 AssetCache = assetCach;
288 m_regInfo = regInfo;
289 m_regionHandle = m_regInfo.RegionHandle;
290 m_regionName = m_regInfo.RegionName;
291 m_datastore = m_regInfo.DataStore;
292
293 m_physicalPrim = physicalPrim;
294 m_seeIntoRegionFromNeighbor = SeeIntoRegionFromNeighbor;
295
296 m_eventManager = new EventManager();
297 m_permissions = new ScenePermissions(this);
298
299 m_asyncSceneObjectDeleter = new AsyncSceneObjectGroupDeleter(this);
300 m_asyncSceneObjectDeleter.Enabled = true;
301
302 // Load region settings
303 m_regInfo.RegionSettings = m_storageManager.DataStore.LoadRegionSettings(m_regInfo.RegionID);
304 if (m_storageManager.EstateDataStore != null)
305 m_regInfo.EstateSettings = m_storageManager.EstateDataStore.LoadEstateSettings(m_regInfo.RegionID);
306
307 //Bind Storage Manager functions to some land manager functions for this scene
308 EventManager.OnLandObjectAdded +=
309 new EventManager.LandObjectAdded(m_storageManager.DataStore.StoreLandObject);
310 EventManager.OnLandObjectRemoved +=
311 new EventManager.LandObjectRemoved(m_storageManager.DataStore.RemoveLandObject);
312
313 m_sceneGraph = new SceneGraph(this, m_regInfo);
314
315 // If the scene graph has an Unrecoverable error, restart this sim.
316 // Currently the only thing that causes it to happen is two kinds of specific
317 // Physics based crashes.
318 //
319 // Out of memory
320 // Operating system has killed the plugin
321 m_sceneGraph.UnRecoverableError += RestartNow;
322
323 RegisterDefaultSceneEvents();
324
325 DumpAssetsToFile = dumpAssetsToFile;
326
327 m_scripts_enabled = !RegionInfo.RegionSettings.DisableScripts;
328
329 m_physics_enabled = !RegionInfo.RegionSettings.DisablePhysics;
330
331 StatsReporter = new SimStatsReporter(this);
332 StatsReporter.OnSendStatsResult += SendSimStatsPackets;
333 StatsReporter.OnStatsIncorrect += m_sceneGraph.RecalculateStats;
334
335 StatsReporter.SetObjectCapacity(objectCapacity);
336
337 m_simulatorVersion = simulatorVersion
338 + " (OS " + Util.GetOperatingSystemInformation() + ")"
339 + " ChilTasks:" + m_seeIntoRegionFromNeighbor.ToString()
340 + " PhysPrim:" + m_physicalPrim.ToString();
341
342 try
343 {
344 // Region config overrides global config
345 //
346 IConfig startupConfig = m_config.Configs["Startup"];
347 m_maxNonphys = startupConfig.GetFloat("NonPhysicalPrimMax", 65536.0f);
348 if (RegionInfo.NonphysPrimMax > 0)
349 m_maxNonphys = RegionInfo.NonphysPrimMax;
350
351 m_maxPhys = startupConfig.GetFloat("PhysicalPrimMax", 10.0f);
352
353 if (RegionInfo.PhysPrimMax > 0)
354 m_maxPhys = RegionInfo.PhysPrimMax;
355
356 // Here, if clamping is requested in either global or
357 // local config, it will be used
358 //
359 m_clampPrimSize = startupConfig.GetBoolean("ClampPrimSize", false);
360 if (RegionInfo.ClampPrimSize)
361 m_clampPrimSize = true;
362
363 m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", false);
364 m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", false);
365 m_dontPersistBefore =
366 startupConfig.GetLong("MinimumTimeBeforePersistenceConsidered", DEFAULT_MIN_TIME_FOR_PERSISTENCE);
367 m_dontPersistBefore *= 10000000;
368 m_persistAfter =
369 startupConfig.GetLong("MaximumTimeBeforePersistenceConsidered", DEFAULT_MAX_TIME_FOR_PERSISTENCE);
370 m_persistAfter *= 10000000;
371
372 m_defaultScriptEngine = startupConfig.GetString("DefaultScriptEngine", "DotNetEngine");
373 }
374 catch
375 {
376 m_log.Warn("[SCENE]: Failed to load StartupConfig");
377 }
378 }
379
380 /// <summary>
381 /// Mock constructor for scene group persistency unit tests.
382 /// SceneObjectGroup RegionId property is delegated to Scene.
383 /// </summary>
384 /// <param name="regInfo"></param>
385 public Scene(RegionInfo regInfo)
386 {
387 m_regInfo = regInfo;
388 m_eventManager = new EventManager();
389 }
390
391 #endregion
392
393 #region Startup / Close Methods
394
395 public bool ShuttingDown
396 {
397 get { return shuttingdown; }
398 }
399
400 protected virtual void RegisterDefaultSceneEvents()
401 {
402 IDialogModule dm = RequestModuleInterface<IDialogModule>();
403
404 if (dm != null)
405 m_eventManager.OnPermissionError += dm.SendAlertToUser;
406 }
407
408 public override string GetSimulatorVersion()
409 {
410 return m_simulatorVersion;
411 }
412
413 /// <summary>
414 /// Another region is up. Gets called from Grid Comms:
415 /// (OGS1 -> LocalBackEnd -> RegionListened -> SceneCommunicationService)
416 /// We have to tell all our ScenePresences about it, and add it to the
417 /// neighbor list.
418 ///
419 /// We only add it to the neighbor list if it's within 1 region from here.
420 /// Agents may have draw distance values that cross two regions though, so
421 /// we add it to the notify list regardless of distance. We'll check
422 /// the agent's draw distance before notifying them though.
423 /// </summary>
424 /// <param name="otherRegion">RegionInfo handle for the new region.</param>
425 /// <returns>True after all operations complete, throws exceptions otherwise.</returns>
426 public override bool OtherRegionUp(RegionInfo otherRegion)
427 {
428 if (RegionInfo.RegionHandle != otherRegion.RegionHandle)
429 {
430 for (int i = 0; i < m_neighbours.Count; i++)
431 {
432 // The purpose of this loop is to re-update the known neighbors
433 // when another region comes up on top of another one.
434 // The latest region in that location ends up in the
435 // 'known neighbors list'
436 // Additionally, the commFailTF property gets reset to false.
437 if (m_neighbours[i].RegionHandle == otherRegion.RegionHandle)
438 {
439 lock (m_neighbours)
440 {
441 m_neighbours[i] = otherRegion;
442 }
443 }
444 }
445
446 // If the value isn't in the neighbours, add it.
447 // If the RegionInfo isn't exact but is for the same XY World location,
448 // then the above loop will fix that.
449
450 if (!(CheckNeighborRegion(otherRegion)))
451 {
452 lock (m_neighbours)
453 {
454 m_neighbours.Add(otherRegion);
455 //m_log.Info("[UP]: " + otherRegion.RegionHandle.ToString());
456 }
457 }
458
459 // If these are cast to INT because long + negative values + abs returns invalid data
460 int resultX = Math.Abs((int)otherRegion.RegionLocX - (int)RegionInfo.RegionLocX);
461 int resultY = Math.Abs((int)otherRegion.RegionLocY - (int)RegionInfo.RegionLocY);
462 if (resultX <= 1 && resultY <= 1)
463 {
464 try
465 {
466 ForEachScenePresence(delegate(ScenePresence agent)
467 {
468 // If agent is a root agent.
469 if (!agent.IsChildAgent)
470 {
471 //agent.ControllingClient.new
472 //this.CommsManager.InterRegion.InformRegionOfChildAgent(otherRegion.RegionHandle, agent.ControllingClient.RequestClientInfo());
473 InformClientOfNeighbor(agent, otherRegion);
474 }
475 }
476 );
477 }
478 catch (NullReferenceException)
479 {
480 // This means that we're not booted up completely yet.
481 // This shouldn't happen too often anymore.
482 m_log.Error("[SCENE]: Couldn't inform client of regionup because we got a null reference exception");
483 }
484 }
485 else
486 {
487 m_log.Info("[INTERGRID]: Got notice about far away Region: " + otherRegion.RegionName.ToString() +
488 " at (" + otherRegion.RegionLocX.ToString() + ", " +
489 otherRegion.RegionLocY.ToString() + ")");
490 }
491 }
492 return true;
493 }
494
495 public void AddNeighborRegion(RegionInfo region)
496 {
497 lock (m_neighbours)
498 {
499 if (!CheckNeighborRegion(region))
500 {
501 m_neighbours.Add(region);
502 }
503 }
504 }
505
506 public bool CheckNeighborRegion(RegionInfo region)
507 {
508 bool found = false;
509 lock (m_neighbours)
510 {
511 foreach (RegionInfo reg in m_neighbours)
512 {
513 if (reg.RegionHandle == region.RegionHandle)
514 {
515 found = true;
516 break;
517 }
518 }
519 }
520 return found;
521 }
522
523 /// <summary>
524 /// Given float seconds, this will restart the region.
525 /// </summary>
526 /// <param name="seconds">float indicating duration before restart.</param>
527 public virtual void Restart(float seconds)
528 {
529 // notifications are done in 15 second increments
530 // so .. if the number of seconds is less then 15 seconds, it's not really a restart request
531 // It's a 'Cancel restart' request.
532
533 // RestartNow() does immediate restarting.
534 if (seconds < 15)
535 {
536 m_restartTimer.Stop();
537 m_dialogModule.SendGeneralAlert("Restart Aborted");
538 }
539 else
540 {
541 // Now we figure out what to set the timer to that does the notifications and calls, RestartNow()
542 m_restartTimer.Interval = 15000;
543 m_incrementsof15seconds = (int)seconds / 15;
544 m_RestartTimerCounter = 0;
545 m_restartTimer.AutoReset = true;
546 m_restartTimer.Elapsed += new ElapsedEventHandler(RestartTimer_Elapsed);
547 m_log.Info("[REGION]: Restarting Region in " + (seconds / 60) + " minutes");
548 m_restartTimer.Start();
549 m_dialogModule.SendNotificationToUsersInRegion(
550 UUID.Random(), String.Empty, RegionInfo.RegionName + ": Restarting in 2 Minutes");
551 }
552 }
553
554 // The Restart timer has occured.
555 // We have to figure out if this is a notification or if the number of seconds specified in Restart
556 // have elapsed.
557 // If they have elapsed, call RestartNow()
558 public void RestartTimer_Elapsed(object sender, ElapsedEventArgs e)
559 {
560 m_RestartTimerCounter++;
561 if (m_RestartTimerCounter <= m_incrementsof15seconds)
562 {
563 if (m_RestartTimerCounter == 4 || m_RestartTimerCounter == 6 || m_RestartTimerCounter == 7)
564 m_dialogModule.SendNotificationToUsersInRegion(
565 UUID.Random(),
566 String.Empty,
567 RegionInfo.RegionName + ": Restarting in " + ((8 - m_RestartTimerCounter) * 15) + " seconds");
568 }
569 else
570 {
571 m_restartTimer.Stop();
572 m_restartTimer.AutoReset = false;
573 RestartNow();
574 }
575 }
576
577 // This causes the region to restart immediatley.
578 public void RestartNow()
579 {
580 if (PhysicsScene != null)
581 {
582 PhysicsScene.Dispose();
583 }
584
585 m_log.Error("[REGION]: Closing");
586 Close();
587 m_log.Error("[REGION]: Firing Region Restart Message");
588 base.Restart(0);
589 }
590
591 // This is a helper function that notifies root agents in this region that a new sim near them has come up
592 // This is in the form of a timer because when an instance of OpenSim.exe is started,
593 // Even though the sims initialize, they don't listen until 'all of the sims are initialized'
594 // If we tell an agent about a sim that's not listening yet, the agent will not be able to connect to it.
595 // subsequently the agent will never see the region come back online.
596 public void RestartNotifyWaitElapsed(object sender, ElapsedEventArgs e)
597 {
598 m_restartWaitTimer.Stop();
599 lock (m_regionRestartNotifyList)
600 {
601 foreach (RegionInfo region in m_regionRestartNotifyList)
602 {
603 try
604 {
605 ForEachScenePresence(delegate(ScenePresence agent)
606 {
607 // If agent is a root agent.
608 if (!agent.IsChildAgent)
609 {
610 //agent.ControllingClient.new
611 //this.CommsManager.InterRegion.InformRegionOfChildAgent(otherRegion.RegionHandle, agent.ControllingClient.RequestClientInfo());
612 InformClientOfNeighbor(agent, region);
613 }
614 }
615 );
616 }
617 catch (NullReferenceException)
618 {
619 // This means that we're not booted up completely yet.
620 // This shouldn't happen too often anymore.
621 }
622 }
623
624 // Reset list to nothing.
625 m_regionRestartNotifyList.Clear();
626 }
627 }
628
629 public void SetSceneCoreDebug(bool ScriptEngine, bool CollisionEvents, bool PhysicsEngine)
630 {
631 if (m_scripts_enabled != !ScriptEngine)
632 {
633 // Tedd! Here's the method to disable the scripting engine!
634 if (ScriptEngine)
635 {
636 m_log.Info("Stopping all Scripts in Scene");
637 foreach (EntityBase ent in Entities)
638 {
639 if (ent is SceneObjectGroup)
640 {
641 ((SceneObjectGroup) ent).RemoveScriptInstances();
642 }
643 }
644 }
645 else
646 {
647 m_log.Info("Starting all Scripts in Scene");
648 lock (Entities)
649 {
650 foreach (EntityBase ent in Entities)
651 {
652 if (ent is SceneObjectGroup)
653 {
654 ((SceneObjectGroup)ent).CreateScriptInstances(0, false, DefaultScriptEngine, 0);
655 }
656 }
657 }
658 }
659 m_scripts_enabled = !ScriptEngine;
660 m_log.Info("[TOTEDD]: Here is the method to trigger disabling of the scripting engine");
661 }
662
663 if (m_physics_enabled != !PhysicsEngine)
664 {
665 m_physics_enabled = !PhysicsEngine;
666 }
667 }
668
669 public int GetInaccurateNeighborCount()
670 {
671 lock (m_neighbours)
672 {
673 return m_neighbours.Count;
674 }
675 }
676
677 // This is the method that shuts down the scene.
678 public override void Close()
679 {
680 m_log.InfoFormat("[SCENE]: Closing down the single simulator: {0}", RegionInfo.RegionName);
681
682 // Kick all ROOT agents with the message, 'The simulator is going down'
683 ForEachScenePresence(delegate(ScenePresence avatar)
684 {
685 if (avatar.KnownChildRegionHandles.Contains(RegionInfo.RegionHandle))
686 avatar.KnownChildRegionHandles.Remove(RegionInfo.RegionHandle);
687
688 if (!avatar.IsChildAgent)
689 avatar.ControllingClient.Kick("The simulator is going down.");
690
691 avatar.ControllingClient.SendShutdownConnectionNotice();
692 });
693
694 // Wait here, or the kick messages won't actually get to the agents before the scene terminates.
695 Thread.Sleep(500);
696
697 // Stop all client threads.
698 ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(true); });
699
700 // Stop updating the scene objects and agents.
701 //m_heartbeatTimer.Close();
702 shuttingdown = true;
703
704 m_log.Debug("[SCENE]: Persisting changed objects");
705 List<EntityBase> entities = GetEntities();
706 foreach (EntityBase entity in entities)
707 {
708 if (!entity.IsDeleted && entity is SceneObjectGroup && ((SceneObjectGroup)entity).HasGroupChanged)
709 {
710 ((SceneObjectGroup)entity).ProcessBackup(m_storageManager.DataStore, false);
711 }
712 }
713
714 m_sceneGraph.Close();
715
716 // De-register with region communications (events cleanup)
717 UnRegisterRegionWithComms();
718
719 // call the base class Close method.
720 base.Close();
721 }
722
723 /// <summary>
724 /// Start the timer which triggers regular scene updates
725 /// </summary>
726 public void StartTimer()
727 {
728 //m_log.Debug("[SCENE]: Starting timer");
729 //m_heartbeatTimer.Enabled = true;
730 //m_heartbeatTimer.Interval = (int)(m_timespan * 1000);
731 //m_heartbeatTimer.Elapsed += new ElapsedEventHandler(Heartbeat);
732 HeartbeatThread = new Thread(new ParameterizedThreadStart(Heartbeat));
733 HeartbeatThread.SetApartmentState(ApartmentState.MTA);
734 HeartbeatThread.Name = "Heartbeat";
735 HeartbeatThread.Priority = ThreadPriority.AboveNormal;
736 ThreadTracker.Add(HeartbeatThread);
737 HeartbeatThread.Start();
738 }
739
740 /// <summary>
741 /// Sets up references to modules required by the scene
742 /// </summary>
743 public void SetModuleInterfaces()
744 {
745 m_xmlrpcModule = RequestModuleInterface<IXMLRPC>();
746 m_worldCommModule = RequestModuleInterface<IWorldComm>();
747 XferManager = RequestModuleInterface<IXfer>();
748 m_AvatarFactory = RequestModuleInterface<IAvatarFactory>();
749 m_serialiser = RequestModuleInterface<IRegionSerialiserModule>();
750 m_interregionCommsOut = RequestModuleInterface<IInterregionCommsOut>();
751 m_interregionCommsIn = RequestModuleInterface<IInterregionCommsIn>();
752 m_dialogModule = RequestModuleInterface<IDialogModule>();
753 m_capsModule = RequestModuleInterface<ICapabilitiesModule>();
754 }
755
756 #endregion
757
758 #region Update Methods
759
760 /// <summary>
761 /// Performs per-frame updates regularly
762 /// </summary>
763 /// <param name="sender"></param>
764 /// <param name="e"></param>
765 private void Heartbeat(object sender)
766 {
767 Update();
768 }
769
770 /// <summary>
771 /// Performs per-frame updates on the scene, this should be the central scene loop
772 /// </summary>
773 public override void Update()
774 {
775 int maintc = 0;
776 while (!shuttingdown)
777 {
778 maintc = System.Environment.TickCount;
779
780 TimeSpan SinceLastFrame = DateTime.Now - m_lastupdate;
781 // Aquire a lock so only one update call happens at once
782 //updateLock.WaitOne();
783 float physicsFPS = 0;
784 //m_log.Info("sadfadf" + m_neighbours.Count.ToString());
785 int agentsInScene = m_sceneGraph.GetRootAgentCount() + m_sceneGraph.GetChildAgentCount();
786
787 if (agentsInScene > 21)
788 {
789 if (m_update_entities == 1)
790 {
791 m_update_entities = 5;
792 StatsReporter.SetUpdateMS(6000);
793 }
794 }
795 else
796 {
797 if (m_update_entities == 5)
798 {
799 m_update_entities = 1;
800 StatsReporter.SetUpdateMS(3000);
801 }
802 }
803
804 frameMS = System.Environment.TickCount;
805 try
806 {
807 // Increment the frame counter
808 m_frame++;
809
810 // Loop it
811 if (m_frame == Int32.MaxValue)
812 m_frame = 0;
813
814 physicsMS2 = System.Environment.TickCount;
815 if ((m_frame % m_update_physics == 0) && m_physics_enabled)
816 m_sceneGraph.UpdatePreparePhysics();
817 physicsMS2 = System.Environment.TickCount - physicsMS2;
818
819 if (m_frame % m_update_entitymovement == 0)
820 m_sceneGraph.UpdateEntityMovement();
821
822 physicsMS = System.Environment.TickCount;
823 if ((m_frame % m_update_physics == 0) && m_physics_enabled)
824 physicsFPS = m_sceneGraph.UpdatePhysics(
825 Math.Max(SinceLastFrame.TotalSeconds, m_timespan)
826 );
827 if (m_frame % m_update_physics == 0 && SynchronizeScene != null)
828 SynchronizeScene(this);
829
830 physicsMS = System.Environment.TickCount - physicsMS;
831 physicsMS += physicsMS2;
832
833 otherMS = System.Environment.TickCount;
834 // run through all entities looking for updates (slow)
835 if (m_frame % m_update_entities == 0)
836 m_sceneGraph.UpdateEntities();
837
838 // run through entities that have scheduled themselves for
839 // updates looking for updates(faster)
840 if (m_frame % m_update_entitiesquick == 0)
841 m_sceneGraph.ProcessUpdates();
842
843 // Run through scenepresences looking for updates
844 if (m_frame % m_update_presences == 0)
845 m_sceneGraph.UpdatePresences();
846
847 // Delete temp-on-rez stuff
848 if (m_frame % m_update_backup == 0)
849 CleanTempObjects();
850
851 if (Region_Status != RegionStatus.SlaveScene)
852 {
853 if (m_frame % m_update_events == 0)
854 UpdateEvents();
855
856 if (m_frame % m_update_backup == 0)
857 {
858 UpdateStorageBackup();
859 }
860
861 if (m_frame % m_update_terrain == 0)
862 UpdateTerrain();
863
864 if (m_frame % m_update_land == 0)
865 UpdateLand();
866 otherMS = System.Environment.TickCount - otherMS;
867 // if (m_frame%m_update_avatars == 0)
868 // UpdateInWorldTime();
869 StatsReporter.AddPhysicsFPS(physicsFPS);
870 StatsReporter.AddTimeDilation(m_timedilation);
871 StatsReporter.AddFPS(1);
872 StatsReporter.AddInPackets(0);
873 StatsReporter.SetRootAgents(m_sceneGraph.GetRootAgentCount());
874 StatsReporter.SetChildAgents(m_sceneGraph.GetChildAgentCount());
875 StatsReporter.SetObjects(m_sceneGraph.GetTotalObjectsCount());
876 StatsReporter.SetActiveObjects(m_sceneGraph.GetActiveObjectsCount());
877 frameMS = System.Environment.TickCount - frameMS;
878 StatsReporter.addFrameMS(frameMS);
879 StatsReporter.addPhysicsMS(physicsMS);
880 StatsReporter.addOtherMS(otherMS);
881 StatsReporter.SetActiveScripts(m_sceneGraph.GetActiveScriptsCount());
882 StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS());
883 }
884 }
885 catch (NotImplementedException)
886 {
887 throw;
888 }
889 catch (AccessViolationException e)
890 {
891 m_log.Error("[Scene]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
892 }
893 //catch (NullReferenceException e)
894 //{
895 // m_log.Error("[Scene]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
896 //}
897 catch (InvalidOperationException e)
898 {
899 m_log.Error("[Scene]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
900 }
901 catch (Exception e)
902 {
903 m_log.Error("[Scene]: Failed with exception " + e.ToString() + " On Region: " + RegionInfo.RegionName);
904 }
905 finally
906 {
907 //updateLock.ReleaseMutex();
908 // Get actual time dilation
909 float tmpval = (m_timespan / (float)SinceLastFrame.TotalSeconds);
910
911 // If actual time dilation is greater then one, we're catching up, so subtract
912 // the amount that's greater then 1 from the time dilation
913 if (tmpval > 1.0)
914 {
915 tmpval = tmpval - (tmpval - 1.0f);
916 }
917 m_timedilation = tmpval;
918
919 m_lastupdate = DateTime.Now;
920 }
921 maintc = System.Environment.TickCount - maintc;
922 maintc = (int)(m_timespan * 1000) - maintc;
923
924 if ((maintc < (m_timespan * 1000)) && maintc > 0)
925 Thread.Sleep(maintc);
926 }
927 }
928
929 private void SendSimStatsPackets(SimStats stats)
930 {
931 List<ScenePresence> StatSendAgents = GetScenePresences();
932 foreach (ScenePresence agent in StatSendAgents)
933 {
934 if (!agent.IsChildAgent)
935 {
936 agent.ControllingClient.SendSimStats(stats);
937 }
938 }
939 }
940
941 private void UpdateLand()
942 {
943 if (LandChannel != null)
944 {
945 if (LandChannel.IsLandPrimCountTainted())
946 {
947 EventManager.TriggerParcelPrimCountUpdate();
948 }
949 }
950 }
951
952 private void UpdateTerrain()
953 {
954 EventManager.TriggerTerrainTick();
955 }
956
957 private void UpdateStorageBackup()
958 {
959 if (!m_backingup)
960 {
961 m_backingup = true;
962 Thread backupthread = new Thread(Backup);
963 backupthread.Name = "BackupWriter";
964 backupthread.IsBackground = true;
965 backupthread.Start();
966 }
967 }
968
969 private void UpdateEvents()
970 {
971 m_eventManager.TriggerOnFrame();
972 }
973
974 /// <summary>
975 /// Perform delegate action on all clients subscribing to updates from this region.
976 /// </summary>
977 /// <returns></returns>
978 public void Broadcast(Action<IClientAPI> whatToDo)
979 {
980 ForEachScenePresence(delegate(ScenePresence presence) { whatToDo(presence.ControllingClient); });
981 }
982
983 /// <summary>
984 /// Backup the scene. This acts as the main method of the backup thread.
985 /// </summary>
986 /// <returns></returns>
987 public void Backup()
988 {
989 lock (m_returns)
990 {
991 EventManager.TriggerOnBackup(m_storageManager.DataStore);
992 m_backingup = false;
993
994 foreach (KeyValuePair<UUID, ReturnInfo> ret in m_returns)
995 {
996 UUID transaction = UUID.Random();
997
998 GridInstantMessage msg = new GridInstantMessage();
999 msg.fromAgentID = new Guid(UUID.Zero.ToString()); // From server
1000 msg.toAgentID = new Guid(ret.Key.ToString());
1001 msg.imSessionID = new Guid(transaction.ToString());
1002 msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
1003 msg.fromAgentName = "Server";
1004 msg.dialog = (byte)19; // Object msg
1005 msg.fromGroup = false;
1006 msg.offline = (byte)1;
1007 msg.ParentEstateID = RegionInfo.EstateSettings.ParentEstateID;
1008 msg.Position = Vector3.Zero;
1009 msg.RegionID = RegionInfo.RegionID.Guid;
1010 msg.binaryBucket = new byte[0];
1011 if (ret.Value.count > 1)
1012 msg.message = string.Format("Your {0} objects were returned from {1} in region {2} due to {3}", ret.Value.count, ret.Value.location.ToString(), RegionInfo.RegionName, ret.Value.reason);
1013 else
1014 msg.message = string.Format("Your object {0} was returned from {1} in region {2} due to {3}", ret.Value.objectName, ret.Value.location.ToString(), RegionInfo.RegionName, ret.Value.reason);
1015
1016 IMessageTransferModule tr = RequestModuleInterface<IMessageTransferModule>();
1017 if (tr != null)
1018 tr.SendInstantMessage(msg, delegate(bool success) {} );
1019 }
1020 m_returns.Clear();
1021 }
1022 }
1023
1024 public void ForceSceneObjectBackup(SceneObjectGroup group)
1025 {
1026 if (group != null)
1027 {
1028 group.ProcessBackup(m_storageManager.DataStore, true);
1029 }
1030 }
1031
1032 public void AddReturn(UUID agentID, string objectName, Vector3 location, string reason)
1033 {
1034 lock (m_returns)
1035 {
1036 if (m_returns.ContainsKey(agentID))
1037 {
1038 ReturnInfo info = m_returns[agentID];
1039 info.count++;
1040 m_returns[agentID] = info;
1041 }
1042 else
1043 {
1044 ReturnInfo info = new ReturnInfo();
1045 info.count = 1;
1046 info.objectName = objectName;
1047 info.location = location;
1048 info.reason = reason;
1049 m_returns[agentID] = info;
1050 }
1051 }
1052 }
1053
1054 #endregion
1055
1056 #region Load Terrain
1057
1058 public void ExportWorldMap(string fileName)
1059 {
1060 List<MapBlockData> mapBlocks =
1061 m_sceneGridService.RequestNeighbourMapBlocks((int)(RegionInfo.RegionLocX - 9),
1062 (int)(RegionInfo.RegionLocY - 9),
1063 (int)(RegionInfo.RegionLocX + 9),
1064 (int)(RegionInfo.RegionLocY + 9));
1065 List<AssetBase> textures = new List<AssetBase>();
1066 List<Image> bitImages = new List<Image>();
1067
1068 foreach (MapBlockData mapBlock in mapBlocks)
1069 {
1070 AssetBase texAsset = AssetCache.GetAsset(mapBlock.MapImageId, true);
1071
1072 if (texAsset != null)
1073 {
1074 textures.Add(texAsset);
1075 }
1076 else
1077 {
1078 texAsset = AssetCache.GetAsset(mapBlock.MapImageId, true);
1079 if (texAsset != null)
1080 {
1081 textures.Add(texAsset);
1082 }
1083 }
1084 }
1085
1086 foreach (AssetBase asset in textures)
1087 {
1088 ManagedImage managedImage;
1089 Image image;
1090
1091 if (OpenJPEG.DecodeToImage(asset.Data, out managedImage, out image))
1092 bitImages.Add(image);
1093 }
1094
1095 Bitmap mapTexture = new Bitmap(2560, 2560);
1096 Graphics g = Graphics.FromImage(mapTexture);
1097 SolidBrush sea = new SolidBrush(Color.DarkBlue);
1098 g.FillRectangle(sea, 0, 0, 2560, 2560);
1099
1100 for (int i = 0; i < mapBlocks.Count; i++)
1101 {
1102 ushort x = (ushort)((mapBlocks[i].X - RegionInfo.RegionLocX) + 10);
1103 ushort y = (ushort)((mapBlocks[i].Y - RegionInfo.RegionLocY) + 10);
1104 g.DrawImage(bitImages[i], (x * 128), (y * 128), 128, 128);
1105 }
1106 mapTexture.Save(fileName, ImageFormat.Jpeg);
1107 }
1108
1109 public void SaveTerrain()
1110 {
1111 m_storageManager.DataStore.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
1112 }
1113
1114 /// <summary>
1115 /// Loads the World heightmap
1116 /// </summary>
1117 public override void LoadWorldMap()
1118 {
1119 try
1120 {
1121 double[,] map = m_storageManager.DataStore.LoadTerrain(RegionInfo.RegionID);
1122 if (map == null)
1123 {
1124 m_log.Info("[TERRAIN]: No default terrain. Generating a new terrain.");
1125 Heightmap = new TerrainChannel();
1126
1127 m_storageManager.DataStore.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
1128 }
1129 else
1130 {
1131 Heightmap = new TerrainChannel(map);
1132 }
1133
1134 }
1135 catch (Exception e)
1136 {
1137 m_log.Warn("[TERRAIN]: Scene.cs: LoadWorldMap() - Failed with exception " + e.ToString());
1138 }
1139 }
1140
1141 /// <summary>
1142 /// Register this region with a grid service
1143 /// </summary>
1144 /// <exception cref="System.Exception">Thrown if registration of the region itself fails.</exception>
1145 public void RegisterRegionWithGrid()
1146 {
1147 RegisterCommsEvents();
1148
1149 // These two 'commands' *must be* next to each other or sim rebooting fails.
1150 m_sceneGridService.RegisterRegion(m_interregionCommsOut, RegionInfo);
1151 m_sceneGridService.InformNeighborsThatRegionisUp(RegionInfo);
1152
1153 Dictionary<string, string> dGridSettings = m_sceneGridService.GetGridSettings();
1154
1155 if (dGridSettings.ContainsKey("allow_forceful_banlines"))
1156 {
1157 if (dGridSettings["allow_forceful_banlines"] != "TRUE")
1158 {
1159 m_log.Info("[GRID]: Grid is disabling forceful parcel banlists");
1160 EventManager.TriggerSetAllowForcefulBan(false);
1161 }
1162 else
1163 {
1164 m_log.Info("[GRID]: Grid is allowing forceful parcel banlists");
1165 EventManager.TriggerSetAllowForcefulBan(true);
1166 }
1167 }
1168 }
1169
1170 /// <summary>
1171 ///
1172 /// </summary>
1173 public void CreateTerrainTexture(bool temporary)
1174 {
1175 //create a texture asset of the terrain
1176 IMapImageGenerator terrain = RequestModuleInterface<IMapImageGenerator>();
1177
1178 // Cannot create a map for a nonexistant heightmap yet.
1179 if (Heightmap == null)
1180 return;
1181
1182 if (terrain == null)
1183 {
1184 #region Fallback default maptile generation
1185
1186 int tc = System.Environment.TickCount;
1187 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain");
1188 Bitmap mapbmp = new Bitmap(256, 256);
1189 double[,] hm = Heightmap.GetDoubles();
1190 bool ShadowDebugContinue = true;
1191 //Color prim = Color.FromArgb(120, 120, 120);
1192 //Vector3 RayEnd = new Vector3(0, 0, 0);
1193 //Vector3 RayStart = new Vector3(0, 0, 0);
1194 //Vector3 direction = new Vector3(0, 0, -1);
1195 //Vector3 AXOrigin = new Vector3();
1196 //Vector3 AXdirection = new Vector3();
1197 //Ray testRay = new Ray();
1198 //EntityIntersection rt = new EntityIntersection();
1199 bool terraincorruptedwarningsaid = false;
1200
1201 float low = 255;
1202 float high = 0;
1203 for (int x = 0; x < 256; x++)
1204 {
1205 for (int y = 0; y < 256; y++)
1206 {
1207 float hmval = (float)hm[x, y];
1208 if (hmval < low)
1209 low = hmval;
1210 if (hmval > high)
1211 high = hmval;
1212 }
1213 }
1214
1215 float mid = (high + low) * 0.5f;
1216
1217 // temporary initializer
1218 float hfvalue = (float)m_regInfo.RegionSettings.WaterHeight;
1219 float hfvaluecompare = hfvalue;
1220 float hfdiff = hfvalue;
1221 int hfdiffi = 0;
1222
1223 for (int x = 0; x < 256; x++)
1224 {
1225 //int tc = System.Environment.TickCount;
1226 for (int y = 0; y < 256; y++)
1227 {
1228 //RayEnd = new Vector3(x, y, 0);
1229 //RayStart = new Vector3(x, y, 255);
1230
1231 //direction = Vector3.Norm(RayEnd - RayStart);
1232 //AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z);
1233 //AXdirection = new Vector3(direction.X, direction.Y, direction.Z);
1234
1235 //testRay = new Ray(AXOrigin, AXdirection);
1236 //rt = m_sceneGraph.GetClosestIntersectingPrim(testRay);
1237
1238 //if (rt.HitTF)
1239 //{
1240 //mapbmp.SetPixel(x, y, prim);
1241 //}
1242 //else
1243 //{
1244 //float tmpval = (float)hm[x, y];
1245 float heightvalue = (float)hm[x, y];
1246
1247 if (heightvalue > (float)m_regInfo.RegionSettings.WaterHeight)
1248 {
1249 // scale height value
1250 heightvalue = low + mid * (heightvalue - low) / mid;
1251
1252 if (heightvalue > 255)
1253 heightvalue = 255;
1254
1255 if (heightvalue < 0)
1256 heightvalue = 0;
1257
1258 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
1259 heightvalue = 0;
1260
1261 try
1262 {
1263 Color green = Color.FromArgb((int)heightvalue, 100, (int)heightvalue);
1264
1265 // Y flip the cordinates
1266 mapbmp.SetPixel(x, (256 - y) - 1, green);
1267
1268 //X
1269 // .
1270 //
1271 // Shade the terrain for shadows
1272 if ((x - 1 > 0) && (y - 1 > 0))
1273 {
1274 hfvalue = (float)hm[x, y];
1275 hfvaluecompare = (float)hm[x - 1, y - 1];
1276
1277 if (Single.IsInfinity(hfvalue) || Single.IsNaN(hfvalue))
1278 hfvalue = 0;
1279
1280 if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare))
1281 hfvaluecompare = 0;
1282
1283 hfdiff = hfvaluecompare - hfvalue;
1284
1285 if (hfdiff > 0.3f)
1286 {
1287
1288 }
1289 else if (hfdiff < -0.3f)
1290 {
1291 // We have to desaturate and blacken the land at the same time
1292 // we use floats, colors use bytes, so shrink are space down to
1293 // 0-255
1294
1295 try
1296 {
1297 hfdiffi = Math.Abs((int)((hfdiff * 4) + (hfdiff * 0.5))) + 1;
1298 if (hfdiff % 1 != 0)
1299 {
1300 hfdiffi = hfdiffi + Math.Abs((int)(((hfdiff % 1) * 0.5f) * 10f) - 1);
1301 }
1302 }
1303 catch (System.OverflowException)
1304 {
1305 m_log.Debug("[MAPTILE]: Shadow failed at value: " + hfdiff.ToString());
1306 ShadowDebugContinue = false;
1307 }
1308
1309 if (ShadowDebugContinue)
1310 {
1311 if ((256 - y) - 1 > 0)
1312 {
1313 Color Shade = mapbmp.GetPixel(x - 1, (256 - y) - 1);
1314
1315 int r = Shade.R;
1316
1317 int g = Shade.G;
1318 int b = Shade.B;
1319 Shade = Color.FromArgb((r - hfdiffi > 0) ? r - hfdiffi : 0, (g - hfdiffi > 0) ? g - hfdiffi : 0, (b - hfdiffi > 0) ? b - hfdiffi : 0);
1320 //Console.WriteLine("d:" + hfdiff.ToString() + ", i:" + hfdiffi + ", pos: " + x + "," + y + " - R:" + Shade.R.ToString() + ", G:" + Shade.G.ToString() + ", B:" + Shade.G.ToString());
1321 mapbmp.SetPixel(x - 1, (256 - y) - 1, Shade);
1322 }
1323 }
1324 }
1325 }
1326 }
1327 catch (System.ArgumentException)
1328 {
1329 if (!terraincorruptedwarningsaid)
1330 {
1331 m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", RegionInfo.RegionName);
1332 terraincorruptedwarningsaid = true;
1333 }
1334 Color black = Color.Black;
1335 mapbmp.SetPixel(x, (256 - y) - 1, black);
1336 }
1337 }
1338 else
1339 {
1340 // Y flip the cordinates
1341 heightvalue = (float)m_regInfo.RegionSettings.WaterHeight - heightvalue;
1342 if (heightvalue > 19)
1343 heightvalue = 19;
1344 if (heightvalue < 0)
1345 heightvalue = 0;
1346
1347 heightvalue = 100 - (heightvalue * 100) / 19;
1348
1349 if (heightvalue > 255)
1350 heightvalue = 255;
1351
1352 if (heightvalue < 0)
1353 heightvalue = 0;
1354
1355 if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
1356 heightvalue = 0;
1357
1358 try
1359 {
1360 Color water = Color.FromArgb((int)heightvalue, (int)heightvalue, 255);
1361 mapbmp.SetPixel(x, (256 - y) - 1, water);
1362 }
1363 catch (System.ArgumentException)
1364 {
1365 if (!terraincorruptedwarningsaid)
1366 {
1367 m_log.WarnFormat("[MAPIMAGE]: Your terrain is corrupted in region {0}, it might take a few minutes to generate the map image depending on the corruption level", RegionInfo.RegionName);
1368 terraincorruptedwarningsaid = true;
1369 }
1370 Color black = Color.Black;
1371 mapbmp.SetPixel(x, (256 - y) - 1, black);
1372 }
1373 }
1374 }
1375 //}
1376
1377 //tc = System.Environment.TickCount - tc;
1378 //m_log.Info("[MAPTILE]: Completed One row in " + tc + " ms");
1379 }
1380
1381 m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (System.Environment.TickCount - tc) + " ms");
1382
1383 bool drawPrimVolume = true;
1384
1385 try
1386 {
1387 IConfig startupConfig = m_config.Configs["Startup"];
1388 drawPrimVolume = startupConfig.GetBoolean("DrawPrimOnMapTile", true);
1389 }
1390 catch
1391 {
1392 m_log.Warn("[MAPTILE]: Failed to load StartupConfig");
1393 }
1394
1395 if (drawPrimVolume)
1396 {
1397 tc = System.Environment.TickCount;
1398 m_log.Info("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile");
1399 List<EntityBase> objs = GetEntities();
1400
1401 lock (objs)
1402 {
1403 foreach (EntityBase obj in objs)
1404 {
1405 // Only draw the contents of SceneObjectGroup
1406 if (obj is SceneObjectGroup)
1407 {
1408 SceneObjectGroup mapdot = (SceneObjectGroup)obj;
1409 Color mapdotspot = Color.Gray; // Default color when prim color is white
1410 // Loop over prim in group
1411 foreach (SceneObjectPart part in mapdot.Children.Values)
1412 {
1413 if (part == null)
1414 continue;
1415
1416 // Draw if the object is at least 1 meter wide in any direction
1417 if (part.Scale.X > 1f || part.Scale.Y > 1f || part.Scale.Z > 1f)
1418 {
1419 // Try to get the RGBA of the default texture entry..
1420 //
1421 try
1422 {
1423 if (part == null)
1424 continue;
1425
1426 if (part.Shape == null)
1427 continue;
1428
1429 if (part.Shape.PCode == (byte)PCode.Tree || part.Shape.PCode == (byte)PCode.NewTree)
1430 continue; // eliminates trees from this since we don't really have a good tree representation
1431 // if you want tree blocks on the map comment the above line and uncomment the below line
1432 //mapdotspot = Color.PaleGreen;
1433
1434 if (part.Shape.Textures == null)
1435 continue;
1436
1437 if (part.Shape.Textures.DefaultTexture == null)
1438 continue;
1439
1440 Color4 texcolor = part.Shape.Textures.DefaultTexture.RGBA;
1441
1442 // Not sure why some of these are null, oh well.
1443
1444 int colorr = 255 - (int)(texcolor.R * 255f);
1445 int colorg = 255 - (int)(texcolor.G * 255f);
1446 int colorb = 255 - (int)(texcolor.B * 255f);
1447
1448 if (!(colorr == 255 && colorg == 255 && colorb == 255))
1449 {
1450 //Try to set the map spot color
1451 try
1452 {
1453 // If the color gets goofy somehow, skip it *shakes fist at Color4
1454 mapdotspot = Color.FromArgb(colorr, colorg, colorb);
1455 }
1456 catch (ArgumentException)
1457 {
1458 }
1459 }
1460 }
1461 catch (IndexOutOfRangeException)
1462 {
1463 // Windows Array
1464 }
1465 catch (ArgumentOutOfRangeException)
1466 {
1467 // Mono Array
1468 }
1469
1470 Vector3 pos = part.GetWorldPosition();
1471
1472 // skip prim outside of retion
1473 if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f)
1474 continue;
1475
1476 // skip prim in non-finite position
1477 if (Single.IsNaN(pos.X) || Single.IsNaN(pos.Y) || Single.IsInfinity(pos.X)
1478 || Single.IsInfinity(pos.Y))
1479 continue;
1480
1481 // Figure out if object is under 256m above the height of the terrain
1482 bool isBelow256AboveTerrain = false;
1483
1484 try
1485 {
1486 isBelow256AboveTerrain = (pos.Z < ((float)hm[(int)pos.X, (int)pos.Y] + 256f));
1487 }
1488 catch (Exception)
1489 {
1490 }
1491
1492 if (isBelow256AboveTerrain)
1493 {
1494 // Translate scale by rotation so scale is represented properly when object is rotated
1495 Vector3 scale = part.Shape.Scale;
1496 Quaternion rot = part.GetWorldRotation();
1497 scale *= rot;
1498
1499 // negative scales don't work in this situation
1500 scale.X = Math.Abs(scale.X);
1501 scale.Y = Math.Abs(scale.Y);
1502 scale.Z = Math.Abs(scale.Z);
1503
1504 // This scaling isn't very accurate and doesn't take into account the face rotation :P
1505 int mapdrawstartX = (int)(pos.X - scale.X);
1506 int mapdrawstartY = (int)(pos.Y - scale.Y);
1507 int mapdrawendX = (int)(pos.X + scale.X);
1508 int mapdrawendY = (int)(pos.Y + scale.Y);
1509
1510 // If object is beyond the edge of the map, don't draw it to avoid errors
1511 if (mapdrawstartX < 0 || mapdrawstartX > 255 || mapdrawendX < 0 || mapdrawendX > 255
1512 || mapdrawstartY < 0 || mapdrawstartY > 255 || mapdrawendY < 0
1513 || mapdrawendY > 255)
1514 continue;
1515
1516 int wy = 0;
1517
1518 bool breakYN = false; // If we run into an error drawing, break out of the
1519 // loop so we don't lag to death on error handling
1520 for (int wx = mapdrawstartX; wx < mapdrawendX; wx++)
1521 {
1522 for (wy = mapdrawstartY; wy < mapdrawendY; wy++)
1523 {
1524 //m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy);
1525 try
1526 {
1527 // Remember, flip the y!
1528 mapbmp.SetPixel(wx, (255 - wy), mapdotspot);
1529 }
1530 catch (ArgumentException)
1531 {
1532 breakYN = true;
1533 }
1534
1535 if (breakYN)
1536 break;
1537 }
1538
1539 if (breakYN)
1540 break;
1541 }
1542 } // Object is within 256m Z of terrain
1543 } // object is at least a meter wide
1544 } // loop over group children
1545 } // entitybase is sceneobject group
1546 } // foreach loop over entities
1547 } // lock entities objs
1548
1549 m_log.Info("[MAPTILE]: Generating Maptile Step 2: Done in " + (System.Environment.TickCount - tc) + " ms");
1550 } // end if drawPrimOnMaptle
1551
1552 byte[] data;
1553 try
1554 {
1555 data = OpenJPEG.EncodeFromImage(mapbmp, false);
1556 }
1557 catch (Exception)
1558 {
1559 return;
1560 }
1561
1562 LazySaveGeneratedMaptile(data,temporary);
1563
1564 #endregion
1565 }
1566 else
1567 {
1568 // Use the module to generate the maptile.
1569 byte[] data = terrain.WriteJpeg2000Image("defaultstripe.png");
1570 if (data != null)
1571 {
1572 LazySaveGeneratedMaptile(data,temporary);
1573 }
1574 }
1575 }
1576
1577 public void LazySaveGeneratedMaptile(byte[] data, bool temporary)
1578 {
1579 // Overwrites the local Asset cache with new maptile data
1580 // Assets are single write, this causes the asset server to ignore this update,
1581 // but the local asset cache does not
1582
1583 // this is on purpose! The net result of this is the region always has the most up to date
1584 // map tile while protecting the (grid) asset database from bloat caused by a new asset each
1585 // time a mapimage is generated!
1586
1587 UUID lastMapRegionUUID = m_regInfo.lastMapUUID;
1588
1589 int lastMapRefresh = 0;
1590 int twoDays = 172800;
1591 int RefreshSeconds = twoDays;
1592
1593 try
1594 {
1595 lastMapRefresh = Convert.ToInt32(m_regInfo.lastMapRefresh);
1596 }
1597 catch (ArgumentException)
1598 {
1599 }
1600 catch (FormatException)
1601 {
1602 }
1603 catch (OverflowException)
1604 {
1605 }
1606
1607 UUID TerrainImageUUID = UUID.Random();
1608
1609 if (lastMapRegionUUID == UUID.Zero || (lastMapRefresh + RefreshSeconds) < Util.UnixTimeSinceEpoch())
1610 {
1611 m_regInfo.SaveLastMapUUID(TerrainImageUUID);
1612
1613 m_log.Warn("[MAPTILE]: STORING MAPTILE IMAGE");
1614 }
1615 else
1616 {
1617 TerrainImageUUID = lastMapRegionUUID;
1618 m_log.Warn("[MAPTILE]: REUSING OLD MAPTILE IMAGE ID");
1619 }
1620
1621 m_regInfo.RegionSettings.TerrainImageID = TerrainImageUUID;
1622
1623 AssetBase asset = new AssetBase();
1624 asset.Metadata.FullID = m_regInfo.RegionSettings.TerrainImageID;
1625 asset.Data = data;
1626 asset.Metadata.Name = "terrainImage_" + m_regInfo.RegionID.ToString() + "_" + lastMapRefresh.ToString();
1627 asset.Metadata.Description = RegionInfo.RegionName;
1628
1629 asset.Metadata.Type = 0;
1630 asset.Metadata.Temporary = temporary;
1631 AssetCache.AddAsset(asset);
1632 }
1633
1634 #endregion
1635
1636 #region Load Land
1637
1638 public void loadAllLandObjectsFromStorage(UUID regionID)
1639 {
1640 m_log.Info("[SCENE]: Loading land objects from storage");
1641 List<LandData> landData = m_storageManager.DataStore.LoadLandObjects(regionID);
1642
1643 if (LandChannel != null)
1644 {
1645 if (landData.Count == 0)
1646 {
1647 EventManager.TriggerNoticeNoLandDataFromStorage();
1648 }
1649 else
1650 {
1651 EventManager.TriggerIncomingLandDataFromStorage(landData);
1652 }
1653 }
1654 else
1655 {
1656 m_log.Error("[SCENE]: Land Channel is not defined. Cannot load from storage!");
1657 }
1658 }
1659
1660 #endregion
1661
1662 #region Primitives Methods
1663
1664 /// <summary>
1665 /// Loads the World's objects
1666 /// </summary>
1667 public virtual void LoadPrimsFromStorage(UUID regionID)
1668 {
1669 m_log.Info("[SCENE]: Loading objects from datastore");
1670
1671 List<SceneObjectGroup> PrimsFromDB = m_storageManager.DataStore.LoadObjects(regionID);
1672 foreach (SceneObjectGroup group in PrimsFromDB)
1673 {
1674 if (group.RootPart == null)
1675 {
1676 m_log.ErrorFormat("[SCENE] Found a SceneObjectGroup with m_rootPart == null and {0} children",
1677 group.Children == null ? 0 : group.Children.Count);
1678 }
1679
1680 AddRestoredSceneObject(group, true, true);
1681 SceneObjectPart rootPart = group.GetChildPart(group.UUID);
1682 rootPart.ObjectFlags &= ~(uint)PrimFlags.Scripted;
1683 rootPart.TrimPermissions();
1684 group.CheckSculptAndLoad();
1685 //rootPart.DoPhysicsPropertyUpdate(UsePhysics, true);
1686 }
1687
1688 m_log.Info("[SCENE]: Loaded " + PrimsFromDB.Count.ToString() + " SceneObject(s)");
1689 }
1690
1691 public Vector3 GetNewRezLocation(Vector3 RayStart, Vector3 RayEnd, UUID RayTargetID, Quaternion rot, byte bypassRayCast, byte RayEndIsIntersection, bool frontFacesOnly, Vector3 scale, bool FaceCenter)
1692 {
1693 Vector3 pos = Vector3.Zero;
1694 if (RayEndIsIntersection == (byte)1)
1695 {
1696 pos = RayEnd;
1697 return pos;
1698 }
1699
1700 if (RayTargetID != UUID.Zero)
1701 {
1702 SceneObjectPart target = GetSceneObjectPart(RayTargetID);
1703
1704 Vector3 direction = Vector3.Normalize(RayEnd - RayStart);
1705 Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z);
1706 Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z);
1707
1708 if (target != null)
1709 {
1710 pos = target.AbsolutePosition;
1711 //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString());
1712
1713 // TODO: Raytrace better here
1714
1715 //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection));
1716 Ray NewRay = new Ray(AXOrigin, AXdirection);
1717
1718 // Ray Trace against target here
1719 EntityIntersection ei = target.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, FaceCenter);
1720
1721 // Un-comment out the following line to Get Raytrace results printed to the console.
1722 // m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
1723 float ScaleOffset = 0.5f;
1724
1725 // If we hit something
1726 if (ei.HitTF)
1727 {
1728 Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z);
1729 if (scaleComponent.X != 0) ScaleOffset = scale.X;
1730 if (scaleComponent.Y != 0) ScaleOffset = scale.Y;
1731 if (scaleComponent.Z != 0) ScaleOffset = scale.Z;
1732 ScaleOffset = Math.Abs(ScaleOffset);
1733 Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
1734 Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z);
1735 // Set the position to the intersection point
1736 Vector3 offset = (normal * (ScaleOffset / 2f));
1737 pos = (intersectionpoint + offset);
1738
1739 // Un-offset the prim (it gets offset later by the consumer method)
1740 pos.Z -= 0.25F;
1741 }
1742
1743 return pos;
1744 }
1745 else
1746 {
1747 // We don't have a target here, so we're going to raytrace all the objects in the scene.
1748
1749 EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection), true, false);
1750
1751 // Un-comment the following line to print the raytrace results to the console.
1752 //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
1753
1754 if (ei.HitTF)
1755 {
1756 pos = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
1757 } else
1758 {
1759 // fall back to our stupid functionality
1760 pos = RayEnd;
1761 }
1762
1763 return pos;
1764 }
1765 }
1766 else
1767 {
1768 // fall back to our stupid functionality
1769 pos = RayEnd;
1770 return pos;
1771 }
1772 }
1773
1774 public virtual void AddNewPrim(UUID ownerID, UUID groupID, Vector3 RayEnd, Quaternion rot, PrimitiveBaseShape shape,
1775 byte bypassRaycast, Vector3 RayStart, UUID RayTargetID,
1776 byte RayEndIsIntersection)
1777 {
1778 Vector3 pos = GetNewRezLocation(RayStart, RayEnd, RayTargetID, rot, bypassRaycast, RayEndIsIntersection, true, new Vector3(0.5f, 0.5f, 0.5f), false);
1779
1780 if (Permissions.CanRezObject(1, ownerID, pos))
1781 {
1782 // rez ON the ground, not IN the ground
1783 pos.Z += 0.25F;
1784
1785 AddNewPrim(ownerID, groupID, pos, rot, shape);
1786 }
1787 }
1788
1789 public virtual SceneObjectGroup AddNewPrim(
1790 UUID ownerID, UUID groupID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
1791 {
1792 //m_log.DebugFormat(
1793 // "[SCENE]: Scene.AddNewPrim() pcode {0} called for {1} in {2}", shape.PCode, ownerID, RegionInfo.RegionName);
1794
1795 // If an entity creator has been registered for this prim type then use that
1796 if (m_entityCreators.ContainsKey((PCode)shape.PCode))
1797 return m_entityCreators[(PCode)shape.PCode].CreateEntity(ownerID, groupID, pos, rot, shape);
1798
1799 // Otherwise, use this default creation code;
1800 SceneObjectGroup sceneObject = new SceneObjectGroup(ownerID, pos, rot, shape);
1801 AddNewSceneObject(sceneObject, true);
1802 sceneObject.SetGroup(groupID, null);
1803
1804 return sceneObject;
1805 }
1806
1807 /// <summary>
1808 /// Add an object into the scene that has come from storage
1809 /// </summary>
1810 ///
1811 /// <param name="sceneObject"></param>
1812 /// <param name="attachToBackup">
1813 /// If true, changes to the object will be reflected in its persisted data
1814 /// If false, the persisted data will not be changed even if the object in the scene is changed
1815 /// </param>
1816 /// <param name="alreadyPersisted">
1817 /// If true, we won't persist this object until it changes
1818 /// If false, we'll persist this object immediately
1819 /// </param>
1820 /// <returns>
1821 /// true if the object was added, false if an object with the same uuid was already in the scene
1822 /// </returns>
1823 public bool AddRestoredSceneObject(
1824 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted)
1825 {
1826 return m_sceneGraph.AddRestoredSceneObject(sceneObject, attachToBackup, alreadyPersisted);
1827 }
1828
1829 /// <summary>
1830 /// Add a newly created object to the scene
1831 /// </summary>
1832 /// <param name="sceneObject"></param>
1833 /// <param name="attachToBackup">
1834 /// If true, the object is made persistent into the scene.
1835 /// If false, the object will not persist over server restarts
1836 /// </param>
1837 public bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup)
1838 {
1839 return m_sceneGraph.AddNewSceneObject(sceneObject, attachToBackup);
1840 }
1841
1842 /// <summary>
1843 /// Delete every object from the scene
1844 /// </summary>
1845 public void DeleteAllSceneObjects()
1846 {
1847 lock (Entities)
1848 {
1849 ICollection<EntityBase> entities = new List<EntityBase>(Entities);
1850
1851 foreach (EntityBase e in entities)
1852 {
1853 if (e is SceneObjectGroup)
1854 DeleteSceneObject((SceneObjectGroup)e, false);
1855 }
1856 }
1857 }
1858
1859 /// <summary>
1860 /// Synchronously delete the given object from the scene.
1861 /// </summary>
1862 /// <param name="group">Object Id</param>
1863 /// <param name="silent">Suppress broadcasting changes to other clients.</param>
1864 public void DeleteSceneObject(SceneObjectGroup group, bool silent)
1865 {
1866 //SceneObjectPart rootPart = group.GetChildPart(group.UUID);
1867
1868 // Serialise calls to RemoveScriptInstances to avoid
1869 // deadlocking on m_parts inside SceneObjectGroup
1870 lock (m_deleting_scene_object)
1871 {
1872 group.RemoveScriptInstances();
1873 }
1874
1875 foreach (SceneObjectPart part in group.Children.Values)
1876 {
1877 if (part.IsJoint() && ((part.ObjectFlags&(uint)PrimFlags.Physics) != 0) )
1878 {
1879 PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed?
1880 }
1881 else if (part.PhysActor != null)
1882 {
1883 PhysicsScene.RemovePrim(part.PhysActor);
1884 part.PhysActor = null;
1885 }
1886 }
1887// if (rootPart.PhysActor != null)
1888// {
1889// PhysicsScene.RemovePrim(rootPart.PhysActor);
1890// rootPart.PhysActor = null;
1891// }
1892
1893 if (UnlinkSceneObject(group.UUID, false))
1894 {
1895 EventManager.TriggerObjectBeingRemovedFromScene(group);
1896 EventManager.TriggerParcelPrimCountTainted();
1897 }
1898
1899 group.DeleteGroup(silent);
1900 }
1901
1902 /// <summary>
1903 /// Unlink the given object from the scene. Unlike delete, this just removes the record of the object - the
1904 /// object itself is not destroyed.
1905 /// </summary>
1906 /// <param name="uuid">Id of object.</param>
1907 /// <returns>true if the object was in the scene, false if it was not</returns>
1908 /// <param name="softDelete">If true, only deletes from scene, but keeps object in database.</param>
1909 public bool UnlinkSceneObject(UUID uuid, bool softDelete)
1910 {
1911 if (m_sceneGraph.DeleteSceneObject(uuid, softDelete))
1912 {
1913 if (!softDelete)
1914 {
1915 m_storageManager.DataStore.RemoveObject(uuid,
1916 m_regInfo.RegionID);
1917 }
1918
1919 return true;
1920 }
1921
1922 return false;
1923 }
1924
1925 /// <summary>
1926 /// Move the given scene object into a new region depending on which region its absolute position has moved
1927 /// into.
1928 ///
1929 /// This method locates the new region handle and offsets the prim position for the new region
1930 /// </summary>
1931 /// <param name="attemptedPosition">the attempted out of region position of the scene object</param>
1932 /// <param name="grp">the scene object that we're crossing</param>
1933 public void CrossPrimGroupIntoNewRegion(Vector3 attemptedPosition, SceneObjectGroup grp, bool silent)
1934 {
1935 if (grp == null)
1936 return;
1937 if (grp.IsDeleted)
1938 return;
1939
1940 if (grp.RootPart.DIE_AT_EDGE)
1941 {
1942 // We remove the object here
1943 try
1944 {
1945 DeleteSceneObject(grp, false);
1946 }
1947 catch (Exception)
1948 {
1949 m_log.Warn("[DATABASE]: exception when trying to remove the prim that crossed the border.");
1950 }
1951 return;
1952 }
1953
1954 int thisx = (int)RegionInfo.RegionLocX;
1955 int thisy = (int)RegionInfo.RegionLocY;
1956
1957 ulong newRegionHandle = 0;
1958 Vector3 pos = attemptedPosition;
1959
1960 if (attemptedPosition.X > Constants.RegionSize + 0.1f)
1961 {
1962 pos.X = ((pos.X - Constants.RegionSize));
1963 newRegionHandle
1964 = Util.UIntsToLong((uint)((thisx + 1) * Constants.RegionSize), (uint)(thisy * Constants.RegionSize));
1965 // x + 1
1966 }
1967 else if (attemptedPosition.X < -0.1f)
1968 {
1969 pos.X = ((pos.X + Constants.RegionSize));
1970 newRegionHandle
1971 = Util.UIntsToLong((uint)((thisx - 1) * Constants.RegionSize), (uint)(thisy * Constants.RegionSize));
1972 // x - 1
1973 }
1974
1975 if (attemptedPosition.Y > Constants.RegionSize + 0.1f)
1976 {
1977 pos.Y = ((pos.Y - Constants.RegionSize));
1978 newRegionHandle
1979 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + 1) * Constants.RegionSize));
1980 // y + 1
1981 }
1982 else if (attemptedPosition.Y < -0.1f)
1983 {
1984 pos.Y = ((pos.Y + Constants.RegionSize));
1985 newRegionHandle
1986 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - 1) * Constants.RegionSize));
1987 // y - 1
1988 }
1989
1990 // Offset the positions for the new region across the border
1991 Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
1992 grp.OffsetForNewRegion(pos);
1993
1994 // If we fail to cross the border, then reset the position of the scene object on that border.
1995 if (!CrossPrimGroupIntoNewRegion(newRegionHandle, grp, silent))
1996 {
1997 grp.OffsetForNewRegion(oldGroupPosition);
1998 grp.ScheduleGroupForFullUpdate();
1999 }
2000 }
2001
2002 /// <summary>
2003 /// Move the given scene object into a new region
2004 /// </summary>
2005 /// <param name="newRegionHandle"></param>
2006 /// <param name="grp">Scene Object Group that we're crossing</param>
2007 /// <returns>
2008 /// true if the crossing itself was successful, false on failure
2009 /// FIMXE: we still return true if the crossing object was not successfully deleted from the originating region
2010 /// </returns>
2011 public bool CrossPrimGroupIntoNewRegion(ulong newRegionHandle, SceneObjectGroup grp, bool silent)
2012 {
2013 bool successYN = false;
2014 grp.RootPart.UpdateFlag = 0;
2015 int primcrossingXMLmethod = 0;
2016
2017 if (newRegionHandle != 0)
2018 {
2019 string objectState = grp.GetStateSnapshot();
2020
2021 successYN
2022 = m_sceneGridService.PrimCrossToNeighboringRegion(
2023 newRegionHandle, grp.UUID, m_serialiser.SaveGroupToXml2(grp), primcrossingXMLmethod);
2024 if (successYN && (objectState != "") && m_allowScriptCrossings)
2025 {
2026 successYN = m_sceneGridService.PrimCrossToNeighboringRegion(
2027 newRegionHandle, grp.UUID, objectState, 100);
2028 }
2029
2030 if (successYN)
2031 {
2032 // We remove the object here
2033 try
2034 {
2035 DeleteSceneObject(grp, silent);
2036 }
2037 catch (Exception e)
2038 {
2039 m_log.ErrorFormat(
2040 "[INTERREGION]: Exception deleting the old object left behind on a border crossing for {0}, {1}",
2041 grp, e);
2042 }
2043 }
2044 else
2045 {
2046 if (!grp.IsDeleted)
2047 {
2048 if (grp.RootPart.PhysActor != null)
2049 {
2050 grp.RootPart.PhysActor.CrossingFailure();
2051 }
2052 }
2053
2054 m_log.ErrorFormat("[INTERREGION]: Prim crossing failed for {0}", grp);
2055 }
2056 }
2057 else
2058 {
2059 m_log.Error("[INTERREGION]: region handle was unexpectedly 0 in Scene.CrossPrimGroupIntoNewRegion()");
2060 }
2061
2062 return successYN;
2063 }
2064
2065 /// <summary>
2066 /// Handle a scene object that is crossing into this region from another.
2067 /// </summary>
2068 /// <param name="regionHandle"></param>
2069 /// <param name="primID"></param>
2070 /// <param name="objXMLData"></param>
2071 /// <param name="XMLMethod"></param>
2072 /// <returns></returns>
2073 public bool IncomingInterRegionPrimGroup(UUID primID, string objXMLData, int XMLMethod)
2074 {
2075
2076 if (XMLMethod == 0)
2077 {
2078 m_log.DebugFormat("[INTERREGION]: A new prim {0} arrived from a neighbor", primID);
2079 SceneObjectGroup sceneObject = m_serialiser.DeserializeGroupFromXml2(objXMLData);
2080
2081 // If the user is banned, we won't let any of their objects
2082 // enter. Period.
2083 //
2084 if (m_regInfo.EstateSettings.IsBanned(sceneObject.OwnerID))
2085 {
2086 m_log.Info("[INTERREGION]: Denied prim crossing for "+
2087 "banned avatar");
2088
2089 return false;
2090 }
2091
2092 // Force allocation of new LocalId
2093 //
2094 foreach (SceneObjectPart p in sceneObject.Children.Values)
2095 p.LocalId = 0;
2096
2097 if (sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim)
2098 {
2099 if (sceneObject.RootPart.Shape.State != 0)
2100 {
2101 // Fix up attachment Parent Local ID
2102 //
2103 ScenePresence sp = GetScenePresence(sceneObject.OwnerID);
2104
2105 uint parentLocalID = 0;
2106 if (sp != null)
2107 parentLocalID = sp.LocalId;
2108
2109 sceneObject.RootPart.IsAttachment = true;
2110 sceneObject.RootPart.SetParentLocalId(parentLocalID);
2111
2112 AddRestoredSceneObject(sceneObject, false, false);
2113
2114 // Handle attachment special case
2115 //
2116 SceneObjectPart RootPrim = GetSceneObjectPart(primID);
2117
2118 if (RootPrim != null)
2119 {
2120 SceneObjectGroup grp = RootPrim.ParentGroup;
2121
2122 RootPrim.SetParentLocalId(parentLocalID);
2123
2124 if (grp != null)
2125 {
2126 m_log.DebugFormat("[ATTACHMENT]: Received "+
2127 "attachment {0}, inworld asset id {1}",
2128 grp.RootPart.LastOwnerID.ToString(),
2129 grp.UUID.ToString());
2130
2131 if (sp != null)
2132 {
2133 grp.SetFromAssetID(grp.RootPart.LastOwnerID);
2134 m_log.DebugFormat("[ATTACHMENT]: Attach "+
2135 "to avatar {0}",
2136 sp.UUID.ToString());
2137 AttachObject(sp.ControllingClient,
2138 grp.LocalId, (uint)0,
2139 grp.GroupRotation,
2140 grp.AbsolutePosition, false);
2141 grp.SendGroupFullUpdate();
2142 }
2143 else
2144 {
2145 RootPrim.RemFlag(PrimFlags.TemporaryOnRez);
2146 RootPrim.AddFlag(PrimFlags.TemporaryOnRez);
2147 }
2148 }
2149 }
2150 }
2151 else
2152 {
2153 AddRestoredSceneObject(sceneObject, true, false);
2154
2155 if (!Permissions.CanObjectEntry(sceneObject.UUID,
2156 true, sceneObject.AbsolutePosition))
2157 {
2158 // Deny non attachments based on parcel settings
2159 //
2160 m_log.Info("[INTERREGION]: Denied prim crossing "+
2161 "because of parcel settings");
2162
2163 DeleteSceneObject(sceneObject, false);
2164
2165 return false;
2166 }
2167 }
2168 }
2169 }
2170 else if ((XMLMethod == 100) && m_allowScriptCrossings)
2171 {
2172 m_log.Warn("[INTERREGION]: Prim state data arrived from a neighbor");
2173 XmlDocument doc = new XmlDocument();
2174 doc.LoadXml(objXMLData);
2175
2176 XmlNodeList rootL = doc.GetElementsByTagName("ScriptData");
2177 if (rootL.Count == 1)
2178 {
2179 XmlNode rootNode = rootL[0];
2180 if (rootNode != null)
2181 {
2182 XmlNodeList partL = rootNode.ChildNodes;
2183
2184 foreach (XmlNode part in partL)
2185 {
2186 XmlNodeList nodeL = part.ChildNodes;
2187
2188 switch (part.Name)
2189 {
2190 case "Assemblies":
2191 foreach (XmlNode asm in nodeL)
2192 {
2193 string fn = asm.Attributes.GetNamedItem("Filename").Value;
2194
2195 Byte[] filedata = Convert.FromBase64String(asm.InnerText);
2196 string path = Path.Combine("ScriptEngines", RegionInfo.RegionID.ToString());
2197 path = Path.Combine(path, fn);
2198
2199 if (!File.Exists(path))
2200 {
2201 FileStream fs = File.Create(path);
2202 fs.Write(filedata, 0, filedata.Length);
2203 fs.Close();
2204 }
2205 }
2206 break;
2207 case "ScriptStates":
2208 foreach (XmlNode st in nodeL)
2209 {
2210 string id = st.Attributes.GetNamedItem("UUID").Value;
2211 UUID uuid = new UUID(id);
2212 XmlNode state = st.ChildNodes[0];
2213
2214 XmlDocument sdoc = new XmlDocument();
2215 XmlNode sxmlnode = sdoc.CreateNode(
2216 XmlNodeType.XmlDeclaration,
2217 "", "");
2218 sdoc.AppendChild(sxmlnode);
2219
2220 XmlNode newnode = sdoc.ImportNode(state, true);
2221 sdoc.AppendChild(newnode);
2222
2223 string spath = Path.Combine("ScriptEngines", RegionInfo.RegionID.ToString());
2224 spath = Path.Combine(spath, uuid.ToString());
2225 FileStream sfs = File.Create(spath + ".state");
2226 System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
2227 Byte[] buf = enc.GetBytes(sdoc.InnerXml);
2228 sfs.Write(buf, 0, buf.Length);
2229 sfs.Close();
2230 }
2231 break;
2232 }
2233 }
2234 }
2235 }
2236
2237 SceneObjectPart RootPrim = GetSceneObjectPart(primID);
2238 RootPrim.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, 1);
2239
2240 return true;
2241 }
2242
2243 return true;
2244 }
2245
2246 #endregion
2247
2248 #region Add/Remove Avatar Methods
2249
2250 public override void AddNewClient(IClientAPI client)
2251 {
2252 SubscribeToClientEvents(client);
2253 ScenePresence presence;
2254
2255 if (m_restorePresences.ContainsKey(client.AgentId))
2256 {
2257 m_log.DebugFormat("[SCENE]: Restoring agent {0} {1} in {2}", client.Name, client.AgentId, RegionInfo.RegionName);
2258
2259 presence = m_restorePresences[client.AgentId];
2260 m_restorePresences.Remove(client.AgentId);
2261
2262 // This is one of two paths to create avatars that are
2263 // used. This tends to get called more in standalone
2264 // than grid, not really sure why, but as such needs
2265 // an explicity appearance lookup here.
2266 AvatarAppearance appearance = null;
2267 GetAvatarAppearance(client, out appearance);
2268 presence.Appearance = appearance;
2269
2270 presence.initializeScenePresence(client, RegionInfo, this);
2271
2272 m_sceneGraph.AddScenePresence(presence);
2273
2274 lock (m_restorePresences)
2275 {
2276 Monitor.PulseAll(m_restorePresences);
2277 }
2278 }
2279 else
2280 {
2281 m_log.DebugFormat(
2282 "[SCENE]: Adding new child agent for {0} in {1}",
2283 client.Name, RegionInfo.RegionName);
2284
2285 CommsManager.UserProfileCacheService.AddNewUser(client.AgentId);
2286
2287 CreateAndAddScenePresence(client);
2288 }
2289
2290 m_LastLogin = System.Environment.TickCount;
2291 EventManager.TriggerOnNewClient(client);
2292 }
2293
2294 protected virtual void SubscribeToClientEvents(IClientAPI client)
2295 {
2296 client.OnRegionHandShakeReply += SendLayerData;
2297 client.OnAddPrim += AddNewPrim;
2298 client.OnUpdatePrimGroupPosition += m_sceneGraph.UpdatePrimPosition;
2299 client.OnUpdatePrimSinglePosition += m_sceneGraph.UpdatePrimSinglePosition;
2300 client.OnUpdatePrimGroupRotation += m_sceneGraph.UpdatePrimRotation;
2301 client.OnUpdatePrimGroupMouseRotation += m_sceneGraph.UpdatePrimRotation;
2302 client.OnUpdatePrimSingleRotation += m_sceneGraph.UpdatePrimSingleRotation;
2303 client.OnUpdatePrimScale += m_sceneGraph.UpdatePrimScale;
2304 client.OnUpdatePrimGroupScale += m_sceneGraph.UpdatePrimGroupScale;
2305 client.OnUpdateExtraParams += m_sceneGraph.UpdateExtraParam;
2306 client.OnUpdatePrimShape += m_sceneGraph.UpdatePrimShape;
2307 client.OnUpdatePrimTexture += m_sceneGraph.UpdatePrimTexture;
2308 client.OnTeleportLocationRequest += RequestTeleportLocation;
2309 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
2310 client.OnObjectSelect += SelectPrim;
2311 client.OnObjectDeselect += DeselectPrim;
2312 client.OnGrabUpdate += m_sceneGraph.MoveObject;
2313 client.OnDeRezObject += DeRezObject;
2314 client.OnRezObject += RezObject;
2315 client.OnRezSingleAttachmentFromInv += RezSingleAttachment;
2316 client.OnDetachAttachmentIntoInv += DetachSingleAttachmentToInv;
2317 client.OnObjectAttach += m_sceneGraph.AttachObject;
2318 client.OnObjectDetach += m_sceneGraph.DetachObject;
2319 client.OnObjectDrop += m_sceneGraph.DropObject;
2320 client.OnNameFromUUIDRequest += CommsManager.HandleUUIDNameRequest;
2321 client.OnObjectDescription += m_sceneGraph.PrimDescription;
2322 client.OnObjectName += m_sceneGraph.PrimName;
2323 client.OnObjectClickAction += m_sceneGraph.PrimClickAction;
2324 client.OnObjectMaterial += m_sceneGraph.PrimMaterial;
2325 client.OnLinkObjects += m_sceneGraph.LinkObjects;
2326 client.OnDelinkObjects += m_sceneGraph.DelinkObjects;
2327 client.OnObjectDuplicate += m_sceneGraph.DuplicateObject;
2328 client.OnObjectDuplicateOnRay += doObjectDuplicateOnRay;
2329 client.OnUpdatePrimFlags += m_sceneGraph.UpdatePrimFlags;
2330 client.OnRequestObjectPropertiesFamily += m_sceneGraph.RequestObjectPropertiesFamily;
2331 client.OnRequestGodlikePowers += handleRequestGodlikePowers;
2332 client.OnGodKickUser += HandleGodlikeKickUser;
2333 client.OnObjectPermissions += HandleObjectPermissionsUpdate;
2334 client.OnCreateNewInventoryItem += CreateNewInventoryItem;
2335 client.OnCreateNewInventoryFolder += HandleCreateInventoryFolder;
2336 client.OnUpdateInventoryFolder += HandleUpdateInventoryFolder;
2337 client.OnMoveInventoryFolder += HandleMoveInventoryFolder;
2338 client.OnFetchInventoryDescendents += HandleFetchInventoryDescendents;
2339 client.OnPurgeInventoryDescendents += HandlePurgeInventoryDescendents;
2340 client.OnFetchInventory += HandleFetchInventory;
2341 client.OnUpdateInventoryItem += UpdateInventoryItemAsset;
2342 client.OnCopyInventoryItem += CopyInventoryItem;
2343 client.OnMoveInventoryItem += MoveInventoryItem;
2344 client.OnRemoveInventoryItem += RemoveInventoryItem;
2345 client.OnRemoveInventoryFolder += RemoveInventoryFolder;
2346 client.OnRezScript += RezScript;
2347 client.OnRequestTaskInventory += RequestTaskInventory;
2348 client.OnRemoveTaskItem += RemoveTaskInventory;
2349 client.OnUpdateTaskInventory += UpdateTaskInventory;
2350 client.OnMoveTaskItem += ClientMoveTaskInventoryItem;
2351 client.OnGrabObject += ProcessObjectGrab;
2352 client.OnDeGrabObject += ProcessObjectDeGrab;
2353 client.OnMoneyTransferRequest += ProcessMoneyTransferRequest;
2354 client.OnParcelBuy += ProcessParcelBuy;
2355 client.OnAvatarPickerRequest += ProcessAvatarPickerRequest;
2356 client.OnObjectIncludeInSearch += m_sceneGraph.MakeObjectSearchable;
2357 client.OnTeleportHomeRequest += TeleportClientHome;
2358 client.OnSetStartLocationRequest += SetHomeRezPoint;
2359 client.OnUndo += m_sceneGraph.HandleUndo;
2360 client.OnObjectGroupRequest += m_sceneGraph.HandleObjectGroupUpdate;
2361 client.OnParcelReturnObjectsRequest += LandChannel.ReturnObjectsInParcel;
2362 client.OnParcelSetOtherCleanTime += LandChannel.SetParcelOtherCleanTime;
2363 client.OnObjectSaleInfo += ObjectSaleInfo;
2364 client.OnScriptReset += ProcessScriptReset;
2365 client.OnGetScriptRunning += GetScriptRunning;
2366 client.OnSetScriptRunning += SetScriptRunning;
2367 client.OnRegionHandleRequest += RegionHandleRequest;
2368 client.OnUnackedTerrain += TerrainUnAcked;
2369
2370 client.OnObjectOwner += ObjectOwner;
2371
2372 if (StatsReporter != null)
2373 client.OnNetworkStatsUpdate += StatsReporter.AddPacketsFromClientStats;
2374
2375 // EventManager.TriggerOnNewClient(client);
2376 }
2377
2378 /// <summary>
2379 /// Teleport an avatar to their home region
2380 /// </summary>
2381 /// <param name="agentId"></param>
2382 /// <param name="client"></param>
2383 public virtual void TeleportClientHome(UUID agentId, IClientAPI client)
2384 {
2385 UserProfileData UserProfile = CommsManager.UserService.GetUserProfile(agentId);
2386 if (UserProfile != null)
2387 {
2388 RegionInfo regionInfo = CommsManager.GridService.RequestNeighbourInfo(UserProfile.HomeRegionID);
2389 if (regionInfo == null)
2390 {
2391 regionInfo = CommsManager.GridService.RequestNeighbourInfo(UserProfile.HomeRegion);
2392 if (regionInfo != null) // home region can be away temporarily, too
2393 {
2394 UserProfile.HomeRegionID = regionInfo.RegionID;
2395 CommsManager.UserService.UpdateUserProfile(UserProfile);
2396 }
2397 }
2398 if (regionInfo == null)
2399 {
2400 // can't find the Home region: Tell viewer and abort
2401 client.SendTeleportFailed("Your home-region could not be found.");
2402 return;
2403 }
2404 RequestTeleportLocation(
2405 client, regionInfo.RegionHandle, UserProfile.HomeLocation, UserProfile.HomeLookAt,
2406 (uint)(TPFlags.SetLastToTarget | TPFlags.ViaHome));
2407 }
2408 }
2409
2410 public void doObjectDuplicateOnRay(uint localID, uint dupeFlags, UUID AgentID, UUID GroupID,
2411 UUID RayTargetObj, Vector3 RayEnd, Vector3 RayStart,
2412 bool BypassRaycast, bool RayEndIsIntersection, bool CopyCenters, bool CopyRotates)
2413 {
2414 Vector3 pos;
2415 const bool frontFacesOnly = true;
2416 //m_log.Info("HITTARGET: " + RayTargetObj.ToString() + ", COPYTARGET: " + localID.ToString());
2417 SceneObjectPart target = GetSceneObjectPart(localID);
2418 SceneObjectPart target2 = GetSceneObjectPart(RayTargetObj);
2419
2420 if (target != null && target2 != null)
2421 {
2422 Vector3 direction = Vector3.Normalize(RayEnd - RayStart);
2423 Vector3 AXOrigin = new Vector3(RayStart.X, RayStart.Y, RayStart.Z);
2424 Vector3 AXdirection = new Vector3(direction.X, direction.Y, direction.Z);
2425
2426 if (target2.ParentGroup != null)
2427 {
2428 pos = target2.AbsolutePosition;
2429 //m_log.Info("[OBJECT_REZ]: TargetPos: " + pos.ToString() + ", RayStart: " + RayStart.ToString() + ", RayEnd: " + RayEnd.ToString() + ", Volume: " + Util.GetDistanceTo(RayStart,RayEnd).ToString() + ", mag1: " + Util.GetMagnitude(RayStart).ToString() + ", mag2: " + Util.GetMagnitude(RayEnd).ToString());
2430
2431 // TODO: Raytrace better here
2432
2433 //EntityIntersection ei = m_sceneGraph.GetClosestIntersectingPrim(new Ray(AXOrigin, AXdirection));
2434 Ray NewRay = new Ray(AXOrigin, AXdirection);
2435
2436 // Ray Trace against target here
2437 EntityIntersection ei = target2.TestIntersectionOBB(NewRay, Quaternion.Identity, frontFacesOnly, CopyCenters);
2438
2439 // Un-comment out the following line to Get Raytrace results printed to the console.
2440 //m_log.Info("[RAYTRACERESULTS]: Hit:" + ei.HitTF.ToString() + " Point: " + ei.ipoint.ToString() + " Normal: " + ei.normal.ToString());
2441 float ScaleOffset = 0.5f;
2442
2443 // If we hit something
2444 if (ei.HitTF)
2445 {
2446 Vector3 scale = target.Scale;
2447 Vector3 scaleComponent = new Vector3(ei.AAfaceNormal.X, ei.AAfaceNormal.Y, ei.AAfaceNormal.Z);
2448 if (scaleComponent.X != 0) ScaleOffset = scale.X;
2449 if (scaleComponent.Y != 0) ScaleOffset = scale.Y;
2450 if (scaleComponent.Z != 0) ScaleOffset = scale.Z;
2451 ScaleOffset = Math.Abs(ScaleOffset);
2452 Vector3 intersectionpoint = new Vector3(ei.ipoint.X, ei.ipoint.Y, ei.ipoint.Z);
2453 Vector3 normal = new Vector3(ei.normal.X, ei.normal.Y, ei.normal.Z);
2454 Vector3 offset = normal * (ScaleOffset / 2f);
2455 pos = intersectionpoint + offset;
2456
2457 // stick in offset format from the original prim
2458 pos = pos - target.ParentGroup.AbsolutePosition;
2459 if (CopyRotates)
2460 {
2461 Quaternion worldRot = target2.GetWorldRotation();
2462
2463 // SceneObjectGroup obj = m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot);
2464 m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID, worldRot);
2465 //obj.Rotation = worldRot;
2466 //obj.UpdateGroupRotation(worldRot);
2467 }
2468 else
2469 {
2470 m_sceneGraph.DuplicateObject(localID, pos, target.GetEffectiveObjectFlags(), AgentID, GroupID);
2471 }
2472 }
2473
2474 return;
2475 }
2476
2477 return;
2478 }
2479 }
2480
2481 public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
2482 {
2483 UserProfileData UserProfile = CommsManager.UserService.GetUserProfile(remoteClient.AgentId);
2484 if (UserProfile != null)
2485 {
2486 // I know I'm ignoring the regionHandle provided by the teleport location request.
2487 // reusing the TeleportLocationRequest delegate, so regionHandle isn't valid
2488 UserProfile.HomeRegionID = RegionInfo.RegionID;
2489 // TODO: The next line can be removed, as soon as only homeRegionID based UserServers are around.
2490 // TODO: The HomeRegion property can be removed then, too
2491 UserProfile.HomeRegion = RegionInfo.RegionHandle;
2492 UserProfile.HomeLocation = position;
2493 UserProfile.HomeLookAt = lookAt;
2494 CommsManager.UserService.UpdateUserProfile(UserProfile);
2495
2496 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
2497 m_dialogModule.SendAlertToUser(remoteClient, "Home position set.");
2498 }
2499 else
2500 {
2501 m_dialogModule.SendAlertToUser(remoteClient, "Set Home request Failed.");
2502 }
2503 }
2504
2505 /// <summary>
2506 /// Create a child agent scene presence and add it to this scene.
2507 /// </summary>
2508 /// <param name="client"></param>
2509 /// <returns></returns>
2510 protected virtual ScenePresence CreateAndAddScenePresence(IClientAPI client)
2511 {
2512 AvatarAppearance appearance = null;
2513 GetAvatarAppearance(client, out appearance);
2514
2515 ScenePresence avatar = m_sceneGraph.CreateAndAddChildScenePresence(client, appearance);
2516 //avatar.KnownRegions = GetChildrenSeeds(avatar.UUID);
2517 return avatar;
2518 }
2519
2520 /// <summary>
2521 /// Get the avatar apperance for the given client.
2522 /// </summary>
2523 /// <param name="client"></param>
2524 /// <param name="appearance"></param>
2525 public void GetAvatarAppearance(IClientAPI client, out AvatarAppearance appearance)
2526 {
2527 appearance = new AvatarAppearance();
2528
2529 try
2530 {
2531 if (m_AvatarFactory != null)
2532 {
2533 if (m_AvatarFactory.TryGetAvatarAppearance(client.AgentId, out appearance))
2534 return;
2535 }
2536 }
2537 catch (Exception e)
2538 {
2539 m_log.ErrorFormat("[APPEARANCE]: Problem fetching appearance for avatar {0}, {1}",
2540 client.Name, e);
2541 }
2542
2543 m_log.Warn("[APPEARANCE]: Appearance not found, returning default");
2544 }
2545
2546 /// <summary>
2547 /// Remove the given client from the scene.
2548 /// </summary>
2549 /// <param name="agentID"></param>
2550 public override void RemoveClient(UUID agentID)
2551 {
2552 bool childagentYN = false;
2553 ScenePresence avatar = GetScenePresence(agentID);
2554 if (avatar != null)
2555 {
2556 childagentYN = avatar.IsChildAgent;
2557 }
2558
2559 try
2560 {
2561 m_log.DebugFormat(
2562 "[SCENE]: Removing {0} agent {1} from region {2}",
2563 (childagentYN ? "child" : "root"), agentID, RegionInfo.RegionName);
2564
2565 m_sceneGraph.removeUserCount(!childagentYN);
2566 CapsModule.RemoveCapsHandler(agentID);
2567
2568 if (avatar.Scene.NeedSceneCacheClear(avatar.UUID))
2569 {
2570 CommsManager.UserProfileCacheService.RemoveUser(agentID);
2571 }
2572
2573 if (!avatar.IsChildAgent)
2574 {
2575 m_sceneGridService.LogOffUser(agentID, RegionInfo.RegionID, RegionInfo.RegionHandle, avatar.AbsolutePosition, avatar.Lookat);
2576 //List<ulong> childknownRegions = new List<ulong>();
2577 //List<ulong> ckn = avatar.KnownChildRegionHandles;
2578 //for (int i = 0; i < ckn.Count; i++)
2579 //{
2580 // childknownRegions.Add(ckn[i]);
2581 //}
2582 List<ulong> regions = new List<ulong>(avatar.KnownChildRegionHandles);
2583 regions.Remove(RegionInfo.RegionHandle);
2584 m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
2585
2586 }
2587 m_eventManager.TriggerClientClosed(agentID);
2588 }
2589 catch (NullReferenceException)
2590 {
2591 // We don't know which count to remove it from
2592 // Avatar is already disposed :/
2593 }
2594
2595 m_eventManager.TriggerOnRemovePresence(agentID);
2596 Broadcast(delegate(IClientAPI client)
2597 {
2598 try
2599 {
2600 client.SendKillObject(avatar.RegionHandle, avatar.LocalId);
2601 }
2602 catch (NullReferenceException)
2603 {
2604 //We can safely ignore null reference exceptions. It means the avatar are dead and cleaned up anyway.
2605 }
2606 });
2607
2608 ForEachScenePresence(
2609 delegate(ScenePresence presence) { presence.CoarseLocationChange(); });
2610
2611 IAgentAssetTransactions agentTransactions = this.RequestModuleInterface<IAgentAssetTransactions>();
2612 if (agentTransactions != null)
2613 {
2614 agentTransactions.RemoveAgentAssetTransactions(agentID);
2615 }
2616
2617 m_sceneGraph.RemoveScenePresence(agentID);
2618
2619 try
2620 {
2621 avatar.Close();
2622 }
2623 catch (NullReferenceException)
2624 {
2625 //We can safely ignore null reference exceptions. It means the avatar are dead and cleaned up anyway.
2626 }
2627 catch (Exception e)
2628 {
2629 m_log.Error("[SCENE] Scene.cs:RemoveClient exception: " + e.ToString());
2630 }
2631
2632 // Remove client agent from profile, so new logins will work
2633 if (!childagentYN)
2634 {
2635 m_sceneGridService.ClearUserAgent(agentID);
2636 }
2637
2638 //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false));
2639 //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true));
2640 }
2641
2642 public void HandleRemoveKnownRegionsFromAvatar(UUID avatarID, List<ulong> regionslst)
2643 {
2644 ScenePresence av = GetScenePresence(avatarID);
2645 if (av != null)
2646 {
2647 lock (av)
2648 {
2649
2650 for (int i = 0; i < regionslst.Count; i++)
2651 {
2652 av.KnownChildRegionHandles.Remove(regionslst[i]);
2653 }
2654 }
2655 }
2656 }
2657
2658 public override void CloseAllAgents(uint circuitcode)
2659 {
2660 // Called by ClientView to kill all circuit codes
2661 ClientManager.CloseAllAgents(circuitcode);
2662 }
2663
2664 public void NotifyMyCoarseLocationChange()
2665 {
2666 ForEachScenePresence(delegate(ScenePresence presence) { presence.CoarseLocationChange(); });
2667 }
2668
2669 #endregion
2670
2671 #region Entities
2672
2673 public void SendKillObject(uint localID)
2674 {
2675 SceneObjectPart part = GetSceneObjectPart(localID);
2676 if (part != null) // It is a prim
2677 {
2678 if (part.ParentGroup != null && !part.ParentGroup.IsDeleted) // Valid
2679 {
2680 if (part.ParentGroup.RootPart != part) // Child part
2681 return;
2682 }
2683 }
2684 Broadcast(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, localID); });
2685 }
2686
2687 #endregion
2688
2689 #region RegionComms
2690
2691 /// <summary>
2692 /// Register the methods that should be invoked when this scene receives various incoming events
2693 /// </summary>
2694 public void RegisterCommsEvents()
2695 {
2696 m_sceneGridService.OnExpectUser += NewUserConnection;
2697 m_sceneGridService.OnAvatarCrossingIntoRegion += AgentCrossing;
2698 m_sceneGridService.OnCloseAgentConnection += IncomingCloseAgent;
2699 m_sceneGridService.OnRegionUp += OtherRegionUp;
2700 //m_sceneGridService.OnChildAgentUpdate += IncomingChildAgentDataUpdate;
2701 m_sceneGridService.OnExpectPrim += IncomingInterRegionPrimGroup;
2702 //m_sceneGridService.OnRemoveKnownRegionFromAvatar += HandleRemoveKnownRegionsFromAvatar;
2703 m_sceneGridService.OnLogOffUser += HandleLogOffUserFromGrid;
2704 m_sceneGridService.KiPrimitive += SendKillObject;
2705 m_sceneGridService.OnGetLandData += GetLandData;
2706
2707 if (m_interregionCommsIn != null)
2708 {
2709 m_log.Debug("[SCENE]: Registering with InterregionCommsIn");
2710 m_interregionCommsIn.OnChildAgentUpdate += IncomingChildAgentDataUpdate;
2711 }
2712 else
2713 m_log.Debug("[SCENE]: Unable to register with InterregionCommsIn");
2714
2715 }
2716
2717 /// <summary>
2718 /// Deregister this scene from receiving incoming region events
2719 /// </summary>
2720 public void UnRegisterRegionWithComms()
2721 {
2722 m_sceneGridService.KiPrimitive -= SendKillObject;
2723 m_sceneGridService.OnLogOffUser -= HandleLogOffUserFromGrid;
2724 //m_sceneGridService.OnRemoveKnownRegionFromAvatar -= HandleRemoveKnownRegionsFromAvatar;
2725 m_sceneGridService.OnExpectPrim -= IncomingInterRegionPrimGroup;
2726 //m_sceneGridService.OnChildAgentUpdate -= IncomingChildAgentDataUpdate;
2727 m_sceneGridService.OnRegionUp -= OtherRegionUp;
2728 m_sceneGridService.OnExpectUser -= NewUserConnection;
2729 m_sceneGridService.OnAvatarCrossingIntoRegion -= AgentCrossing;
2730 m_sceneGridService.OnCloseAgentConnection -= IncomingCloseAgent;
2731 m_sceneGridService.OnGetLandData -= GetLandData;
2732
2733 if (m_interregionCommsIn != null)
2734 m_interregionCommsIn.OnChildAgentUpdate -= IncomingChildAgentDataUpdate;
2735
2736 m_sceneGridService.Close();
2737 }
2738
2739 /// <summary>
2740 /// Do the work necessary to initiate a new user connection for a particular scene.
2741 /// At the moment, this consists of setting up the caps infrastructure
2742 /// </summary>
2743 /// <param name="regionHandle"></param>
2744 /// <param name="agent"></param>
2745 public void NewUserConnection(AgentCircuitData agent)
2746 {
2747 CapsModule.NewUserConnection(agent);
2748
2749 ScenePresence sp = m_sceneGraph.GetScenePresence(agent.AgentID);
2750 if (sp != null)
2751 {
2752 m_log.DebugFormat(
2753 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
2754 agent.AgentID, RegionInfo.RegionName);
2755
2756 sp.AdjustKnownSeeds();
2757
2758 return;
2759 }
2760
2761 // Don't disable this log message - it's too helpful
2762 m_log.DebugFormat(
2763 "[CONNECTION BEGIN]: Region {0} told of incoming client {1} {2} {3} (circuit code {4})",
2764 RegionInfo.RegionName, agent.firstname, agent.lastname, agent.AgentID, agent.circuitcode);
2765
2766 if (m_regInfo.EstateSettings.IsBanned(agent.AgentID))
2767 {
2768 m_log.WarnFormat(
2769 "[CONNECTION BEGIN]: Denied access to: {0} at {1} because the user is on the region banlist",
2770 agent.AgentID, RegionInfo.RegionName);
2771 }
2772
2773 CapsModule.AddCapsHandler(agent.AgentID);
2774
2775 if (!agent.child)
2776 {
2777 // Honor parcel landing type and position.
2778 ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
2779 if (land != null)
2780 {
2781 if (land.landData.LandingType == (byte)1 && land.landData.UserLocation != Vector3.Zero)
2782 {
2783 agent.startpos = land.landData.UserLocation;
2784 }
2785 }
2786 }
2787
2788 m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent);
2789
2790 // rewrite session_id
2791 CachedUserInfo userinfo = CommsManager.UserProfileCacheService.GetUserDetails(agent.AgentID);
2792
2793 if (userinfo != null)
2794 {
2795 userinfo.SessionID = agent.SessionID;
2796 }
2797 else
2798 {
2799 m_log.WarnFormat(
2800 "[CONNECTION BEGIN]: We couldn't find a User Info record for {0}. This is usually an indication that the UUID we're looking up is invalid", agent.AgentID);
2801 }
2802 }
2803
2804 public void UpdateCircuitData(AgentCircuitData data)
2805 {
2806 m_authenticateHandler.UpdateAgentData(data);
2807 }
2808
2809 public bool ChangeCircuitCode(uint oldcc, uint newcc)
2810 {
2811 return m_authenticateHandler.TryChangeCiruitCode(oldcc, newcc);
2812 }
2813
2814 protected void HandleLogOffUserFromGrid(UUID AvatarID, UUID RegionSecret, string message)
2815 {
2816 ScenePresence loggingOffUser = null;
2817 loggingOffUser = GetScenePresence(AvatarID);
2818 if (loggingOffUser != null)
2819 {
2820 UUID localRegionSecret = UUID.Zero;
2821 bool parsedsecret = UUID.TryParse(m_regInfo.regionSecret, out localRegionSecret);
2822
2823 // Region Secret is used here in case a new sessionid overwrites an old one on the user server.
2824 // Will update the user server in a few revisions to use it.
2825
2826 if (RegionSecret == loggingOffUser.ControllingClient.SecureSessionId || (parsedsecret && RegionSecret == localRegionSecret))
2827 {
2828 m_sceneGridService.SendCloseChildAgentConnections(loggingOffUser.UUID, new List<ulong>(loggingOffUser.KnownRegions.Keys));
2829 loggingOffUser.ControllingClient.Kick(message);
2830 // Give them a second to receive the message!
2831 System.Threading.Thread.Sleep(1000);
2832 loggingOffUser.ControllingClient.Close(true);
2833 }
2834 else
2835 {
2836 m_log.Info("[USERLOGOFF]: System sending the LogOff user message failed to sucessfully authenticate");
2837 }
2838 }
2839 else
2840 {
2841 m_log.InfoFormat("[USERLOGOFF]: Got a logoff request for {0} but the user isn't here. The user might already have been logged out", AvatarID.ToString());
2842 }
2843 }
2844
2845 /// <summary>
2846 /// Triggered when an agent crosses into this sim. Also happens on initial login.
2847 /// </summary>
2848 /// <param name="agentID"></param>
2849 /// <param name="position"></param>
2850 /// <param name="isFlying"></param>
2851 public virtual void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
2852 {
2853 ScenePresence presence;
2854
2855 lock (m_scenePresences)
2856 {
2857 m_scenePresences.TryGetValue(agentID, out presence);
2858 }
2859
2860 if (presence != null)
2861 {
2862 try
2863 {
2864 presence.MakeRootAgent(position, isFlying);
2865 }
2866 catch (Exception e)
2867 {
2868 m_log.ErrorFormat("[SCENE]: Unable to do agent crossing, exception {0}", e);
2869 }
2870 }
2871 else
2872 {
2873 m_log.ErrorFormat(
2874 "[SCENE]: Could not find presence for agent {0} crossing into scene {1}",
2875 agentID, RegionInfo.RegionName);
2876 }
2877 }
2878
2879 public virtual bool IncomingChildAgentDataUpdate(AgentData cAgentData)
2880 {
2881// m_log.DebugFormat(
2882// "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName);
2883
2884 // We have to wait until the viewer contacts this region after receiving EAC.
2885 // That calls AddNewClient, which finally creates the ScenePresence
2886 ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID);
2887 if (childAgentUpdate != null)
2888 {
2889 childAgentUpdate.ChildAgentDataUpdate(cAgentData);
2890 return true;
2891 }
2892
2893 return false;
2894 }
2895
2896 public virtual bool IncomingChildAgentDataUpdate(AgentPosition cAgentData)
2897 {
2898 //Console.WriteLine(" XXX Scene IncomingChildAgentDataUpdate POSITION in " + RegionInfo.RegionName);
2899 ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
2900 if (childAgentUpdate != null)
2901 {
2902 // I can't imagine *yet* why we would get an update if the agent is a root agent..
2903 // however to avoid a race condition crossing borders..
2904 if (childAgentUpdate.IsChildAgent)
2905 {
2906 uint rRegionX = (uint)(cAgentData.RegionHandle >> 40);
2907 uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8);
2908 uint tRegionX = RegionInfo.RegionLocX;
2909 uint tRegionY = RegionInfo.RegionLocY;
2910 //Send Data to ScenePresence
2911 childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
2912 // Not Implemented:
2913 //TODO: Do we need to pass the message on to one of our neighbors?
2914 }
2915
2916 return true;
2917 }
2918
2919 return false;
2920 }
2921
2922 protected virtual ScenePresence WaitGetScenePresence(UUID agentID)
2923 {
2924 int ntimes = 10;
2925 ScenePresence childAgentUpdate = null;
2926 while ((childAgentUpdate = GetScenePresence(agentID)) == null && (ntimes-- > 0))
2927 Thread.Sleep(1000);
2928 return childAgentUpdate;
2929
2930 }
2931
2932 public virtual bool IncomingReleaseAgent(UUID id)
2933 {
2934 return m_sceneGridService.ReleaseAgent(id);
2935 }
2936
2937 public void SendReleaseAgent(ulong regionHandle, UUID id, string uri)
2938 {
2939 m_interregionCommsOut.SendReleaseAgent(regionHandle, id, uri);
2940 }
2941
2942 /// <summary>
2943 /// Tell a single agent to disconnect from the region.
2944 /// </summary>
2945 /// <param name="regionHandle"></param>
2946 /// <param name="agentID"></param>
2947 public bool IncomingCloseAgent(UUID agentID)
2948 {
2949 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
2950
2951 ScenePresence presence = m_sceneGraph.GetScenePresence(agentID);
2952 if (presence != null)
2953 {
2954 // Nothing is removed here, so down count it as such
2955 if (presence.IsChildAgent)
2956 {
2957 m_sceneGraph.removeUserCount(false);
2958 }
2959 else
2960 {
2961 m_sceneGraph.removeUserCount(true);
2962 }
2963
2964 // Don't do this to root agents on logout, it's not nice for the viewer
2965 if (presence.IsChildAgent)
2966 {
2967 // Tell a single agent to disconnect from the region.
2968 IEventQueue eq = RequestModuleInterface<IEventQueue>();
2969 if (eq != null)
2970 {
2971 eq.DisableSimulator(RegionInfo.RegionHandle, agentID);
2972 }
2973 else
2974 presence.ControllingClient.SendShutdownConnectionNotice();
2975 }
2976
2977 presence.ControllingClient.Close(true);
2978 return true;
2979 }
2980
2981 // Agent not here
2982 return false;
2983 }
2984
2985 /// <summary>
2986 /// Tell neighboring regions about this agent
2987 /// When the regions respond with a true value,
2988 /// tell the agents about the region.
2989 ///
2990 /// We have to tell the regions about the agents first otherwise it'll deny them access
2991 ///
2992 /// </summary>
2993 /// <param name="presence"></param>
2994 public void InformClientOfNeighbours(ScenePresence presence)
2995 {
2996 m_sceneGridService.EnableNeighbourChildAgents(presence, m_neighbours);
2997 }
2998
2999 /// <summary>
3000 /// Tell a neighboring region about this agent
3001 /// </summary>
3002 /// <param name="presence"></param>
3003 /// <param name="region"></param>
3004 public void InformClientOfNeighbor(ScenePresence presence, RegionInfo region)
3005 {
3006 m_sceneGridService.InformNeighborChildAgent(presence, region, m_neighbours);
3007 }
3008
3009 /// <summary>
3010 /// Requests information about this region from gridcomms
3011 /// </summary>
3012 /// <param name="regionHandle"></param>
3013 /// <returns></returns>
3014 public RegionInfo RequestNeighbouringRegionInfo(ulong regionHandle)
3015 {
3016 return m_sceneGridService.RequestNeighbouringRegionInfo(regionHandle);
3017 }
3018
3019 /// <summary>
3020 /// Requests textures for map from minimum region to maximum region in world cordinates
3021 /// </summary>
3022 /// <param name="remoteClient"></param>
3023 /// <param name="minX"></param>
3024 /// <param name="minY"></param>
3025 /// <param name="maxX"></param>
3026 /// <param name="maxY"></param>
3027 public void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY)
3028 {
3029 m_log.InfoFormat("[MAPBLOCK]: {0}-{1}, {2}-{3}", minX, minY, maxX, maxY);
3030 m_sceneGridService.RequestMapBlocks(remoteClient, minX, minY, maxX, maxY);
3031 }
3032
3033 /// <summary>
3034 /// Tries to teleport agent to other region.
3035 /// </summary>
3036 /// <param name="remoteClient"></param>
3037 /// <param name="regionName"></param>
3038 /// <param name="position"></param>
3039 /// <param name="lookAt"></param>
3040 /// <param name="teleportFlags"></param>
3041 public void RequestTeleportLocation(IClientAPI remoteClient, string regionName, Vector3 position,
3042 Vector3 lookat, uint teleportFlags)
3043 {
3044 RegionInfo regionInfo = m_sceneGridService.RequestClosestRegion(regionName);
3045 if (regionInfo == null)
3046 {
3047 // can't find the region: Tell viewer and abort
3048 remoteClient.SendTeleportFailed("The region '" + regionName + "' could not be found.");
3049 return;
3050 }
3051
3052 RequestTeleportLocation(remoteClient, regionInfo.RegionHandle, position, lookat, teleportFlags);
3053 }
3054
3055 /// <summary>
3056 /// Tries to teleport agent to other region.
3057 /// </summary>
3058 /// <param name="remoteClient"></param>
3059 /// <param name="regionHandle"></param>
3060 /// <param name="position"></param>
3061 /// <param name="lookAt"></param>
3062 /// <param name="teleportFlags"></param>
3063 public void RequestTeleportLocation(IClientAPI remoteClient, ulong regionHandle, Vector3 position,
3064 Vector3 lookAt, uint teleportFlags)
3065 {
3066 ScenePresence sp = null;
3067 lock (m_scenePresences)
3068 {
3069 if (m_scenePresences.ContainsKey(remoteClient.AgentId))
3070 sp = m_scenePresences[remoteClient.AgentId];
3071 }
3072
3073 if (sp != null)
3074 {
3075 m_sceneGridService.RequestTeleportToLocation(sp, regionHandle,
3076 position, lookAt, teleportFlags);
3077 }
3078 }
3079
3080 /// <summary>
3081 /// Tries to teleport agent to landmark.
3082 /// </summary>
3083 /// <param name="remoteClient"></param>
3084 /// <param name="regionHandle"></param>
3085 /// <param name="position"></param>
3086 public void RequestTeleportLandmark(IClientAPI remoteClient, UUID regionID, Vector3 position)
3087 {
3088 RegionInfo info = CommsManager.GridService.RequestNeighbourInfo(regionID);
3089
3090 if (info == null)
3091 {
3092 // can't find the region: Tell viewer and abort
3093 remoteClient.SendTeleportFailed("The teleport destination could not be found.");
3094 return;
3095 }
3096
3097 ScenePresence sp = null;
3098 lock (m_scenePresences)
3099 {
3100 if (m_scenePresences.ContainsKey(remoteClient.AgentId))
3101 sp = m_scenePresences[remoteClient.AgentId];
3102 }
3103 if (sp != null)
3104 {
3105 m_sceneGridService.RequestTeleportToLocation(sp, info.RegionHandle,
3106 position, Vector3.Zero, (uint)(TPFlags.SetLastToTarget | TPFlags.ViaLandmark));
3107 }
3108 }
3109
3110 /// <summary>
3111 /// Agent is crossing the border into a neighbouring region. Tell the neighbour about it!
3112 /// </summary>
3113 /// <param name="regionHandle"></param>
3114 /// <param name="agentID"></param>
3115 /// <param name="position"></param>
3116 /// <param name="isFlying"></param>
3117 /// <returns></returns>
3118 public bool InformNeighbourOfCrossing(ulong regionHandle, UUID agentID, Vector3 position, bool isFlying)
3119 {
3120 return m_sceneGridService.CrossToNeighbouringRegion(regionHandle, agentID, position, isFlying);
3121 }
3122
3123 public void SendOutChildAgentUpdates(AgentPosition cadu, ScenePresence presence)
3124 {
3125 m_sceneGridService.SendChildAgentDataUpdate(cadu, presence);
3126 }
3127
3128 #endregion
3129
3130 #region Other Methods
3131
3132 public void SetObjectCapacity(int objects)
3133 {
3134 // Region specific config overrides global
3135 //
3136 if (RegionInfo.ObjectCapacity != 0)
3137 objects = RegionInfo.ObjectCapacity;
3138
3139 if (StatsReporter != null)
3140 {
3141 StatsReporter.SetObjectCapacity(objects);
3142 }
3143 objectCapacity = objects;
3144 }
3145
3146 public List<FriendListItem> GetFriendList(UUID avatarID)
3147 {
3148 return CommsManager.GetUserFriendList(avatarID);
3149 }
3150
3151 public Dictionary<UUID, FriendRegionInfo> GetFriendRegionInfos(List<UUID> uuids)
3152 {
3153 return CommsManager.GetFriendRegionInfos(uuids);
3154 }
3155
3156 public List<UUID> InformFriendsInOtherRegion(UUID agentId, ulong destRegionHandle, List<UUID> friends, bool online)
3157 {
3158 return CommsManager.InformFriendsInOtherRegion(agentId, destRegionHandle, friends, online);
3159 }
3160
3161 public bool TriggerTerminateFriend(ulong regionHandle, UUID agentID, UUID exFriendID)
3162 {
3163 return CommsManager.TriggerTerminateFriend(regionHandle, agentID, exFriendID);
3164 }
3165
3166 public virtual void StoreAddFriendship(UUID ownerID, UUID friendID, uint perms)
3167 {
3168 m_sceneGridService.AddNewUserFriend(ownerID, friendID, perms);
3169 }
3170
3171 public virtual void StoreUpdateFriendship(UUID ownerID, UUID friendID, uint perms)
3172 {
3173 m_sceneGridService.UpdateUserFriendPerms(ownerID, friendID, perms);
3174 }
3175
3176 public virtual void StoreRemoveFriendship(UUID ownerID, UUID ExfriendID)
3177 {
3178 m_sceneGridService.RemoveUserFriend(ownerID, ExfriendID);
3179 }
3180
3181 public void AddPacketStats(int inPackets, int outPackets, int unAckedBytes)
3182 {
3183 StatsReporter.AddInPackets(inPackets);
3184 StatsReporter.AddOutPackets(outPackets);
3185 StatsReporter.AddunAckedBytes(unAckedBytes);
3186 }
3187
3188 public void AddAgentTime(int ms)
3189 {
3190 StatsReporter.addFrameMS(ms);
3191 StatsReporter.addAgentMS(ms);
3192 }
3193
3194 public void AddAgentUpdates(int count)
3195 {
3196 StatsReporter.AddAgentUpdates(count);
3197 }
3198
3199 public void AddPendingDownloads(int count)
3200 {
3201 StatsReporter.addPendingDownload(count);
3202 }
3203
3204 #endregion
3205
3206 #region Alert Methods
3207
3208 /// <summary>
3209 /// Handle a request for admin rights
3210 /// </summary>
3211 /// <param name="agentID"></param>
3212 /// <param name="sessionID"></param>
3213 /// <param name="token"></param>
3214 /// <param name="controllingClient"></param>
3215 public void handleRequestGodlikePowers(UUID agentID, UUID sessionID, UUID token, bool godLike,
3216 IClientAPI controllingClient)
3217 {
3218 ScenePresence sp = null;
3219
3220 lock (m_scenePresences)
3221 {
3222 // User needs to be logged into this sim
3223 m_scenePresences.TryGetValue(agentID, out sp);
3224 }
3225
3226 if (sp != null)
3227 {
3228 if (godLike == false)
3229 {
3230 sp.GrantGodlikePowers(agentID, sessionID, token, godLike);
3231 return;
3232 }
3233
3234 // First check that this is the sim owner
3235 if (Permissions.IsGod(agentID))
3236 {
3237 // Next we check for spoofing.....
3238 UUID testSessionID = sp.ControllingClient.SessionId;
3239 if (sessionID == testSessionID)
3240 {
3241 if (sessionID == controllingClient.SessionId)
3242 {
3243 //m_log.Info("godlike: " + godLike.ToString());
3244 sp.GrantGodlikePowers(agentID, testSessionID, token, godLike);
3245 }
3246 }
3247 }
3248 else
3249 {
3250 m_dialogModule.SendAlertToUser(agentID, "Request for god powers denied");
3251 }
3252 }
3253 }
3254
3255 /// <summary>
3256 /// Kicks User specified from the simulator. This logs them off of the grid
3257 /// If the client gets the UUID: 44e87126e7944ded05b37c42da3d5cdb it assumes
3258 /// that you're kicking it even if the avatar's UUID isn't the UUID that the
3259 /// agent is assigned
3260 /// </summary>
3261 /// <param name="godID">The person doing the kicking</param>
3262 /// <param name="sessionID">The session of the person doing the kicking</param>
3263 /// <param name="agentID">the person that is being kicked</param>
3264 /// <param name="kickflags">This isn't used apparently</param>
3265 /// <param name="reason">The message to send to the user after it's been turned into a field</param>
3266 public void HandleGodlikeKickUser(UUID godID, UUID sessionID, UUID agentID, uint kickflags, byte[] reason)
3267 {
3268 // For some reason the client sends this seemingly hard coded UUID for kicking everyone. Dun-know.
3269 UUID kickUserID = new UUID("44e87126e7944ded05b37c42da3d5cdb");
3270 lock (m_scenePresences)
3271 {
3272 if (m_scenePresences.ContainsKey(agentID) || agentID == kickUserID)
3273 {
3274 if (Permissions.IsGod(godID))
3275 {
3276 if (agentID == kickUserID)
3277 {
3278 ClientManager.ForEachClient(delegate(IClientAPI controller)
3279 {
3280 if (controller.AgentId != godID)
3281 controller.Kick(Utils.BytesToString(reason));
3282 }
3283 );
3284
3285 // This is a bit crude. It seems the client will be null before it actually stops the thread
3286 // The thread will kill itself eventually :/
3287 // Is there another way to make sure *all* clients get this 'inter region' message?
3288 ClientManager.ForEachClient(delegate(IClientAPI controller)
3289 {
3290 ScenePresence p = GetScenePresence(controller.AgentId);
3291 bool childagent = p != null && p.IsChildAgent;
3292 if (controller.AgentId != godID && !childagent)
3293 // Do we really want to kick the initiator of this madness?
3294 {
3295 controller.Close(true);
3296 }
3297 }
3298 );
3299 }
3300 else
3301 {
3302 m_sceneGraph.removeUserCount(!m_scenePresences[agentID].IsChildAgent);
3303
3304 m_scenePresences[agentID].ControllingClient.Kick(Utils.BytesToString(reason));
3305 m_scenePresences[agentID].ControllingClient.Close(true);
3306 }
3307 }
3308 else
3309 {
3310 m_dialogModule.SendAlertToUser(godID, "Kick request denied");
3311 }
3312 }
3313 }
3314 }
3315
3316 public void HandleObjectPermissionsUpdate(IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set)
3317 {
3318 // Check for spoofing.. since this is permissions we're talking about here!
3319 if ((controller.SessionId == sessionID) && (controller.AgentId == agentID))
3320 {
3321 // Tell the object to do permission update
3322 if (localId != 0)
3323 {
3324 SceneObjectGroup chObjectGroup = GetGroupByPrim(localId);
3325 if (chObjectGroup != null)
3326 {
3327 chObjectGroup.UpdatePermissions(agentID, field, localId, mask, set);
3328 }
3329 }
3330 }
3331 }
3332
3333 /// <summary>
3334 /// Handle an alert command from the console.
3335 /// FIXME: Command parsing code really shouldn't be in this core Scene class.
3336 /// </summary>
3337 /// <param name="commandParams"></param>
3338 public void HandleAlertCommand(string[] commandParams)
3339 {
3340 if (commandParams[0] == "general")
3341 {
3342 string message = CombineParams(commandParams, 1);
3343 m_dialogModule.SendGeneralAlert(message);
3344 }
3345 else
3346 {
3347 string message = CombineParams(commandParams, 2);
3348 m_dialogModule.SendAlertToUser(commandParams[0], commandParams[1], message, false);
3349 }
3350 }
3351
3352 private string CombineParams(string[] commandParams, int pos)
3353 {
3354 string result = String.Empty;
3355 for (int i = pos; i < commandParams.Length; i++)
3356 {
3357 result += commandParams[i] + " ";
3358 }
3359 return result;
3360 }
3361
3362 #endregion
3363
3364 /// <summary>
3365 /// Causes all clients to get a full object update on all of the objects in the scene.
3366 /// </summary>
3367 public void ForceClientUpdate()
3368 {
3369 List<EntityBase> EntityList = GetEntities();
3370
3371 foreach (EntityBase ent in EntityList)
3372 {
3373 if (ent is SceneObjectGroup)
3374 {
3375 ((SceneObjectGroup)ent).ScheduleGroupForFullUpdate();
3376 }
3377 }
3378 }
3379
3380 /// <summary>
3381 /// This is currently only used for scale (to scale to MegaPrim size)
3382 /// There is a console command that calls this in OpenSimMain
3383 /// </summary>
3384 /// <param name="cmdparams"></param>
3385 public void HandleEditCommand(string[] cmdparams)
3386 {
3387 Console.WriteLine("Searching for Primitive: '" + cmdparams[0] + "'");
3388
3389 List<EntityBase> EntityList = GetEntities();
3390
3391 foreach (EntityBase ent in EntityList)
3392 {
3393 if (ent is SceneObjectGroup)
3394 {
3395 SceneObjectPart part = ((SceneObjectGroup)ent).GetChildPart(((SceneObjectGroup)ent).UUID);
3396 if (part != null)
3397 {
3398 if (part.Name == cmdparams[0])
3399 {
3400 part.Resize(
3401 new Vector3(Convert.ToSingle(cmdparams[1]), Convert.ToSingle(cmdparams[2]),
3402 Convert.ToSingle(cmdparams[3])));
3403
3404 Console.WriteLine("Edited scale of Primitive: " + part.Name);
3405 }
3406 }
3407 }
3408 }
3409 }
3410
3411 public override void Show(string[] showParams)
3412 {
3413 base.Show(showParams);
3414
3415 switch (showParams[0])
3416 {
3417 case "users":
3418 m_log.Error("Current Region: " + RegionInfo.RegionName);
3419 m_log.ErrorFormat("{0,-16}{1,-16}{2,-25}{3,-25}{4,-16}{5,-16}{6,-16}", "Firstname", "Lastname",
3420 "Agent ID", "Session ID", "Circuit", "IP", "World");
3421
3422 foreach (ScenePresence scenePresence in GetAvatars())
3423 {
3424 m_log.ErrorFormat("{0,-16}{1,-16}{2,-25}{3,-25}{4,-16},{5,-16}{6,-16}",
3425 scenePresence.Firstname,
3426 scenePresence.Lastname,
3427 scenePresence.UUID,
3428 scenePresence.ControllingClient.AgentId,
3429 "Unknown",
3430 "Unknown",
3431 RegionInfo.RegionName);
3432 }
3433
3434 break;
3435 }
3436 }
3437
3438 #region Script Handling Methods
3439
3440 /// <summary>
3441 /// Console command handler to send script command to script engine.
3442 /// </summary>
3443 /// <param name="args"></param>
3444 public void SendCommandToPlugins(string[] args)
3445 {
3446 m_eventManager.TriggerOnPluginConsole(args);
3447 }
3448
3449 public double GetLandHeight(int x, int y)
3450 {
3451 return Heightmap[x, y];
3452 }
3453
3454 public UUID GetLandOwner(float x, float y)
3455 {
3456 ILandObject land = LandChannel.GetLandObject(x, y);
3457 if (land == null)
3458 {
3459 return UUID.Zero;
3460 }
3461 else
3462 {
3463 return land.landData.OwnerID;
3464 }
3465 }
3466
3467 public LandData GetLandData(float x, float y)
3468 {
3469 return LandChannel.GetLandObject(x, y).landData;
3470 }
3471
3472 public LandData GetLandData(uint x, uint y)
3473 {
3474 m_log.DebugFormat("[SCENE] returning land for {0},{1}", x, y);
3475 return LandChannel.GetLandObject((int)x, (int)y).landData;
3476 }
3477
3478 public void SetLandMusicURL(float x, float y, string url)
3479 {
3480 ILandObject land = LandChannel.GetLandObject(x, y);
3481 if (land == null)
3482 {
3483 return;
3484 }
3485 else
3486 {
3487 land.landData.MusicURL = url;
3488 land.sendLandUpdateToAvatarsOverMe();
3489 return;
3490 }
3491 }
3492
3493 public void SetLandMediaURL(float x, float y, string url)
3494 {
3495 ILandObject land = LandChannel.GetLandObject(x, y);
3496
3497 if (land == null)
3498 {
3499 return;
3500 }
3501
3502 else
3503 {
3504 land.landData.MediaURL = url;
3505 land.sendLandUpdateToAvatarsOverMe();
3506 return;
3507 }
3508 }
3509
3510 public RegionInfo RequestClosestRegion(string name)
3511 {
3512 return m_sceneGridService.RequestClosestRegion(name);
3513 }
3514
3515 #endregion
3516
3517 #region Script Engine
3518
3519 private List<ScriptEngineInterface> ScriptEngines = new List<ScriptEngineInterface>();
3520 public bool DumpAssetsToFile;
3521
3522 /// <summary>
3523 ///
3524 /// </summary>
3525 /// <param name="scriptEngine"></param>
3526 public void AddScriptEngine(ScriptEngineInterface scriptEngine)
3527 {
3528 ScriptEngines.Add(scriptEngine);
3529 scriptEngine.InitializeEngine(this);
3530 }
3531
3532 public void TriggerObjectChanged(uint localID, uint change)
3533 {
3534 m_eventManager.TriggerOnScriptChangedEvent(localID, change);
3535 }
3536
3537 public void TriggerAtTargetEvent(uint localID, uint handle, Vector3 targetpos, Vector3 currentpos)
3538 {
3539 m_eventManager.TriggerAtTargetEvent(localID, handle, targetpos, currentpos);
3540 }
3541
3542 public void TriggerNotAtTargetEvent(uint localID)
3543 {
3544 m_eventManager.TriggerNotAtTargetEvent(localID);
3545 }
3546
3547 private bool ScriptDanger(SceneObjectPart part,Vector3 pos)
3548 {
3549 ILandObject parcel = LandChannel.GetLandObject(pos.X, pos.Y);
3550 if (part != null)
3551 {
3552 if (parcel != null)
3553 {
3554 if ((parcel.landData.Flags & (uint)Parcel.ParcelFlags.AllowOtherScripts) != 0)
3555 {
3556 return true;
3557 }
3558 else if ((parcel.landData.Flags & (uint)Parcel.ParcelFlags.AllowGroupScripts) != 0)
3559 {
3560 if (part.OwnerID == parcel.landData.OwnerID || (parcel.landData.IsGroupOwned && part.GroupID == parcel.landData.GroupID) || Permissions.IsGod(part.OwnerID))
3561 {
3562 return true;
3563 }
3564 else
3565 {
3566 return false;
3567 }
3568 }
3569 else
3570 {
3571 if (part.OwnerID == parcel.landData.OwnerID)
3572 {
3573 return true;
3574 }
3575 else
3576 {
3577 return false;
3578 }
3579 }
3580 }
3581 else
3582 {
3583
3584 if (pos.X > 0f && pos.X < Constants.RegionSize && pos.Y > 0f && pos.Y < Constants.RegionSize)
3585 {
3586 // The only time parcel != null when an object is inside a region is when
3587 // there is nothing behind the landchannel. IE, no land plugin loaded.
3588 return true;
3589 }
3590 else
3591 {
3592 // The object is outside of this region. Stop piping events to it.
3593 return false;
3594 }
3595 }
3596 }
3597 else
3598 {
3599 return false;
3600 }
3601 }
3602
3603 public bool ScriptDanger(uint localID, Vector3 pos)
3604 {
3605 SceneObjectPart part = GetSceneObjectPart(localID);
3606 if (part != null)
3607 {
3608 return ScriptDanger(part, pos);
3609 }
3610 else
3611 {
3612 return false;
3613 }
3614 }
3615
3616 public bool PipeEventsForScript(uint localID)
3617 {
3618 SceneObjectPart part = GetSceneObjectPart(localID);
3619 if (part != null)
3620 {
3621 // Changed so that child prims of attachments return ScriptDanger for their parent, so that
3622 // their scripts will actually run.
3623 // -- Leaf, Tue Aug 12 14:17:05 EDT 2008
3624 SceneObjectPart parent = part.ParentGroup.RootPart;
3625 if (parent != null && parent.IsAttachment)
3626 return ScriptDanger(parent, parent.GetWorldPosition());
3627 else
3628 return ScriptDanger(part, part.GetWorldPosition());
3629 }
3630 else
3631 {
3632 return false;
3633 }
3634 }
3635
3636 #endregion
3637
3638 #region SceneGraph wrapper methods
3639
3640 /// <summary>
3641 ///
3642 /// </summary>
3643 /// <param name="localID"></param>
3644 /// <returns></returns>
3645 public UUID ConvertLocalIDToFullID(uint localID)
3646 {
3647 return m_sceneGraph.ConvertLocalIDToFullID(localID);
3648 }
3649
3650 public void SwapRootAgentCount(bool rootChildChildRootTF)
3651 {
3652 m_sceneGraph.SwapRootChildAgent(rootChildChildRootTF);
3653 }
3654
3655 public void AddPhysicalPrim(int num)
3656 {
3657 m_sceneGraph.AddPhysicalPrim(num);
3658 }
3659
3660 public void RemovePhysicalPrim(int num)
3661 {
3662 m_sceneGraph.RemovePhysicalPrim(num);
3663 }
3664
3665 //The idea is to have a group of method that return a list of avatars meeting some requirement
3666 // ie it could be all m_scenePresences within a certain range of the calling prim/avatar.
3667
3668 /// <summary>
3669 /// Return a list of all avatars in this region.
3670 /// This list is a new object, so it can be iterated over without locking.
3671 /// </summary>
3672 /// <returns></returns>
3673 public List<ScenePresence> GetAvatars()
3674 {
3675 return m_sceneGraph.GetAvatars();
3676 }
3677
3678 /// <summary>
3679 /// Return a list of all ScenePresences in this region. This returns child agents as well as root agents.
3680 /// This list is a new object, so it can be iterated over without locking.
3681 /// </summary>
3682 /// <returns></returns>
3683 public List<ScenePresence> GetScenePresences()
3684 {
3685 return m_sceneGraph.GetScenePresences();
3686 }
3687
3688 /// <summary>
3689 /// Request a filtered list of ScenePresences in this region.
3690 /// This list is a new object, so it can be iterated over without locking.
3691 /// </summary>
3692 /// <param name="filter"></param>
3693 /// <returns></returns>
3694 public List<ScenePresence> GetScenePresences(FilterAvatarList filter)
3695 {
3696 return m_sceneGraph.GetScenePresences(filter);
3697 }
3698
3699 /// <summary>
3700 /// Request a scene presence by UUID
3701 /// </summary>
3702 /// <param name="avatarID"></param>
3703 /// <returns></returns>
3704 public ScenePresence GetScenePresence(UUID avatarID)
3705 {
3706 return m_sceneGraph.GetScenePresence(avatarID);
3707 }
3708
3709 public override bool PresenceChildStatus(UUID avatarID)
3710 {
3711 ScenePresence cp = GetScenePresence(avatarID);
3712
3713 // FIXME: This is really crap - some logout code is relying on a NullReferenceException to halt its processing
3714 // This needs to be fixed properly by cleaning up the logout code.
3715 //if (cp != null)
3716 // return cp.IsChildAgent;
3717
3718 //return false;
3719
3720 return cp.IsChildAgent;
3721 }
3722
3723 /// <summary>
3724 ///
3725 /// </summary>
3726 /// <param name="action"></param>
3727 public void ForEachScenePresence(Action<ScenePresence> action)
3728 {
3729 // We don't want to try to send messages if there are no avatars.
3730 if (m_scenePresences != null)
3731 {
3732 try
3733 {
3734 List<ScenePresence> presenceList = GetScenePresences();
3735 foreach (ScenePresence presence in presenceList)
3736 {
3737 action(presence);
3738 }
3739 }
3740 catch (Exception e)
3741 {
3742 m_log.Info("[BUG]: " + e.ToString());
3743 }
3744 }
3745 }
3746
3747 /// <summary>
3748 ///
3749 /// </summary>
3750 /// <param name="action"></param>
3751 // public void ForEachObject(Action<SceneObjectGroup> action)
3752 // {
3753 // List<SceneObjectGroup> presenceList;
3754 //
3755 // lock (m_sceneObjects)
3756 // {
3757 // presenceList = new List<SceneObjectGroup>(m_sceneObjects.Values);
3758 // }
3759 //
3760 // foreach (SceneObjectGroup presence in presenceList)
3761 // {
3762 // action(presence);
3763 // }
3764 // }
3765
3766 /// <summary>
3767 /// Get a named prim contained in this scene (will return the first
3768 /// found, if there are more than one prim with the same name)
3769 /// </summary>
3770 /// <param name="name"></param>
3771 /// <returns></returns>
3772 public SceneObjectPart GetSceneObjectPart(string name)
3773 {
3774 return m_sceneGraph.GetSceneObjectPart(name);
3775 }
3776
3777 /// <summary>
3778 /// Get a prim via its local id
3779 /// </summary>
3780 /// <param name="localID"></param>
3781 /// <returns></returns>
3782 public SceneObjectPart GetSceneObjectPart(uint localID)
3783 {
3784 return m_sceneGraph.GetSceneObjectPart(localID);
3785 }
3786
3787 /// <summary>
3788 /// Get a prim via its UUID
3789 /// </summary>
3790 /// <param name="fullID"></param>
3791 /// <returns></returns>
3792 public SceneObjectPart GetSceneObjectPart(UUID fullID)
3793 {
3794 return m_sceneGraph.GetSceneObjectPart(fullID);
3795 }
3796
3797 public bool TryGetAvatar(UUID avatarId, out ScenePresence avatar)
3798 {
3799 return m_sceneGraph.TryGetAvatar(avatarId, out avatar);
3800 }
3801
3802 public bool TryGetAvatarByName(string avatarName, out ScenePresence avatar)
3803 {
3804 return m_sceneGraph.TryGetAvatarByName(avatarName, out avatar);
3805 }
3806
3807 public void ForEachClient(Action<IClientAPI> action)
3808 {
3809 m_sceneGraph.ForEachClient(action);
3810 }
3811
3812 /// <summary>
3813 /// Returns a list of the entities in the scene. This is a new list so operations perform on the list itself
3814 /// will not affect the original list of objects in the scene.
3815 /// </summary>
3816 /// <returns></returns>
3817 public List<EntityBase> GetEntities()
3818 {
3819 return m_sceneGraph.GetEntities();
3820 }
3821
3822 #endregion
3823
3824 #region Avatar Appearance Default
3825
3826 public static void GetDefaultAvatarAppearance(out AvatarWearable[] wearables, out byte[] visualParams)
3827 {
3828 visualParams = GetDefaultVisualParams();
3829 wearables = AvatarWearable.DefaultWearables;
3830 }
3831
3832 private static byte[] GetDefaultVisualParams()
3833 {
3834 byte[] visualParams;
3835 visualParams = new byte[218];
3836 for (int i = 0; i < 218; i++)
3837 {
3838 visualParams[i] = 100;
3839 }
3840 return visualParams;
3841 }
3842
3843 #endregion
3844
3845 public void ParcelMediaSetTime(float time)
3846 {
3847 //should be doing this by parcel, but as its only for testing
3848 // The use of Thread.Sleep here causes the following compiler error under mono 1.2.4
3849 // OpenSim/Region/Environment/Scenes/Scene.cs(3675,17): error CS0103: The name `Thread' does not exist
3850 // in the context of `<>c__CompilerGenerated17'
3851 // MW said it was okay to comment the body of this method out for now since the code is experimental
3852 // and will be replaced anyway
3853// ForEachClient(delegate(IClientAPI client)
3854// {
3855// client.SendParcelMediaCommand((uint)(2), ParcelMediaCommandEnum.Pause, 0);
3856// Thread.Sleep(10);
3857// client.SendParcelMediaCommand((uint)(64), ParcelMediaCommandEnum.Time, time);
3858// Thread.Sleep(200);
3859// client.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Play, 0);
3860// });
3861 }
3862
3863 public void RegionHandleRequest(IClientAPI client, UUID regionID)
3864 {
3865 RegionInfo info;
3866 if (regionID == RegionInfo.RegionID)
3867 info = RegionInfo;
3868 else
3869 info = CommsManager.GridService.RequestNeighbourInfo(regionID);
3870
3871 if (info != null)
3872 client.SendRegionHandle(regionID, info.RegionHandle);
3873 }
3874
3875 public void TerrainUnAcked(IClientAPI client, int patchX, int patchY)
3876 {
3877 //Console.WriteLine("Terrain packet unacked, resending patch: " + patchX + " , " + patchY);
3878 client.SendLayerData(patchX, patchY, Heightmap.GetFloatsSerialised());
3879 }
3880
3881 public void SetRootAgentScene(UUID agentID)
3882 {
3883 IInventoryTransferModule inv = RequestModuleInterface<IInventoryTransferModule>();
3884 if (inv == null)
3885 return;
3886
3887 inv.SetRootAgentScene(agentID, this);
3888
3889 EventManager.TriggerSetRootAgentScene(agentID, this);
3890 }
3891
3892 public bool NeedSceneCacheClear(UUID agentID)
3893 {
3894 IInventoryTransferModule inv = RequestModuleInterface<IInventoryTransferModule>();
3895 if (inv == null)
3896 return true;
3897
3898 return inv.NeedSceneCacheClear(agentID, this);
3899 }
3900
3901 public void ObjectSaleInfo(IClientAPI client, UUID agentID, UUID sessionID, uint localID, byte saleType, int salePrice)
3902 {
3903 SceneObjectPart part = GetSceneObjectPart(localID);
3904 if (part == null || part.ParentGroup == null)
3905 return;
3906
3907 if (part.ParentGroup.IsDeleted)
3908 return;
3909
3910 part = part.ParentGroup.RootPart;
3911
3912 part.ObjectSaleType = saleType;
3913 part.SalePrice = salePrice;
3914
3915 part.ParentGroup.HasGroupChanged = true;
3916
3917 part.GetProperties(client);
3918 }
3919
3920 public bool PerformObjectBuy(IClientAPI remoteClient, UUID categoryID,
3921 uint localID, byte saleType)
3922 {
3923 SceneObjectPart part = GetSceneObjectPart(localID);
3924
3925 if (part == null)
3926 return false;
3927
3928 if (part.ParentGroup == null)
3929 return false;
3930
3931 SceneObjectGroup group = part.ParentGroup;
3932
3933 switch (saleType)
3934 {
3935 case 1: // Sell as original (in-place sale)
3936 uint effectivePerms=group.GetEffectivePermissions();
3937
3938 if ((effectivePerms & (uint)PermissionMask.Transfer) == 0)
3939 {
3940 m_dialogModule.SendAlertToUser(remoteClient, "This item doesn't appear to be for sale");
3941 return false;
3942 }
3943
3944 group.SetOwnerId(remoteClient.AgentId);
3945 group.SetRootPartOwner(part, remoteClient.AgentId,
3946 remoteClient.ActiveGroupId);
3947
3948 List<SceneObjectPart> partList =
3949 new List<SceneObjectPart>(group.Children.Values);
3950
3951 if (Permissions.PropagatePermissions())
3952 {
3953 foreach (SceneObjectPart child in partList)
3954 {
3955 child.Inventory.ChangeInventoryOwner(remoteClient.AgentId);
3956 child.ApplyNextOwnerPermissions();
3957 }
3958 }
3959
3960 part.ObjectSaleType = 0;
3961 part.SalePrice = 10;
3962
3963 group.HasGroupChanged = true;
3964 part.GetProperties(remoteClient);
3965 part.ScheduleFullUpdate();
3966
3967 break;
3968
3969 case 2: // Sell a copy
3970 string sceneObjectXml = group.ToXmlString();
3971
3972 CachedUserInfo userInfo =
3973 CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
3974
3975 if (userInfo != null)
3976 {
3977 uint perms=group.GetEffectivePermissions();
3978
3979 if ((perms & (uint)PermissionMask.Transfer) == 0)
3980 {
3981 m_dialogModule.SendAlertToUser(remoteClient, "This item doesn't appear to be for sale");
3982 return false;
3983 }
3984
3985 AssetBase asset = CreateAsset(
3986 group.GetPartName(localID),
3987 group.GetPartDescription(localID),
3988 (sbyte)AssetType.Object,
3989 Utils.StringToBytes(sceneObjectXml));
3990 AssetCache.AddAsset(asset);
3991
3992 InventoryItemBase item = new InventoryItemBase();
3993 item.Creator = part.CreatorID;
3994
3995 item.ID = UUID.Random();
3996 item.Owner = remoteClient.AgentId;
3997 item.AssetID = asset.Metadata.FullID;
3998 item.Description = asset.Metadata.Description;
3999 item.Name = asset.Metadata.Name;
4000 item.AssetType = asset.Metadata.Type;
4001 item.InvType = (int)InventoryType.Object;
4002 item.Folder = categoryID;
4003
4004 uint nextPerms=(perms & 7) << 13;
4005 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
4006 perms &= ~(uint)PermissionMask.Copy;
4007 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
4008 perms &= ~(uint)PermissionMask.Transfer;
4009 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
4010 perms &= ~(uint)PermissionMask.Modify;
4011
4012 item.BasePermissions = perms & part.NextOwnerMask;
4013 item.CurrentPermissions = perms & part.NextOwnerMask;
4014 item.NextPermissions = part.NextOwnerMask;
4015 item.EveryOnePermissions = part.EveryoneMask &
4016 part.NextOwnerMask;
4017 item.GroupPermissions = part.GroupMask &
4018 part.NextOwnerMask;
4019 item.CurrentPermissions |= 8; // Slam!
4020 item.CreationDate = Util.UnixTimeSinceEpoch();
4021
4022 userInfo.AddItem(item);
4023 remoteClient.SendInventoryItemCreateUpdate(item);
4024 }
4025 else
4026 {
4027 m_dialogModule.SendAlertToUser(remoteClient, "Cannot buy now. Your inventory is unavailable");
4028 return false;
4029 }
4030 break;
4031
4032 case 3: // Sell contents
4033 List<UUID> invList = part.Inventory.GetInventoryList();
4034
4035 bool okToSell = true;
4036
4037 foreach (UUID invID in invList)
4038 {
4039 TaskInventoryItem item = part.Inventory.GetInventoryItem(invID);
4040 if ((item.CurrentPermissions &
4041 (uint)PermissionMask.Transfer) == 0)
4042 {
4043 okToSell = false;
4044 break;
4045 }
4046 }
4047
4048 if (!okToSell)
4049 {
4050 m_dialogModule.SendAlertToUser(
4051 remoteClient, "This item's inventory doesn't appear to be for sale");
4052 return false;
4053 }
4054
4055 if (invList.Count > 0)
4056 MoveTaskInventoryItems(remoteClient.AgentId, part.Name,
4057 part, invList);
4058 break;
4059 }
4060
4061 return true;
4062 }
4063
4064 public void CleanTempObjects()
4065 {
4066 List<EntityBase> objs = GetEntities();
4067
4068 foreach (EntityBase obj in objs)
4069 {
4070 if (obj is SceneObjectGroup)
4071 {
4072 SceneObjectGroup grp = (SceneObjectGroup)obj;
4073
4074 if (!grp.IsDeleted)
4075 {
4076 if ((grp.RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
4077 {
4078 if (grp.RootPart.Expires <= DateTime.Now)
4079 DeleteSceneObject(grp, false);
4080 }
4081 }
4082 }
4083 }
4084 }
4085
4086 public void DeleteFromStorage(UUID uuid)
4087 {
4088 m_storageManager.DataStore.RemoveObject(uuid, m_regInfo.RegionID);
4089 }
4090
4091 public int GetHealth()
4092 {
4093 int health=1; // Start at 1, means we're up
4094
4095 // A login in the last 4 mins? We can't be doing too badly
4096 //
4097 if ((System.Environment.TickCount - m_LastLogin) < 240000)
4098 health++;
4099
4100 return 0;
4101 }
4102
4103 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and
4104 // update non-physical objects like the joint proxy objects that represent the position
4105 // of the joints in the scene.
4106
4107 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene
4108 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called
4109 // from within the OdePhysicsScene.
4110
4111 protected internal void jointMoved(PhysicsJoint joint)
4112 {
4113 // m_parentScene.PhysicsScene.DumpJointInfo(); // non-thread-locked version; we should already be in a lock (OdeLock) when this callback is invoked
4114 // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
4115 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
4116 if (jointProxyObject == null)
4117 {
4118 jointErrorMessage(joint, "WARNING, joint proxy not found, name " + joint.ObjectNameInScene);
4119 return;
4120 }
4121
4122 // now update the joint proxy object in the scene to have the position of the joint as returned by the physics engine
4123 SceneObjectPart trackedBody = GetSceneObjectPart(joint.TrackedBodyName); // FIXME: causes a sequential lookup
4124 if (trackedBody == null) return; // the actor may have been deleted but the joint still lingers around a few frames waiting for deletion. during this time, trackedBody is NULL to prevent further motion of the joint proxy.
4125 jointProxyObject.Velocity = trackedBody.Velocity;
4126 jointProxyObject.RotationalVelocity = trackedBody.RotationalVelocity;
4127 switch (joint.Type)
4128 {
4129 case PhysicsJointType.Ball:
4130 {
4131 PhysicsVector jointAnchor = PhysicsScene.GetJointAnchor(joint);
4132 Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z);
4133 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
4134 }
4135 break;
4136
4137 case PhysicsJointType.Hinge:
4138 {
4139 PhysicsVector jointAnchor = PhysicsScene.GetJointAnchor(joint);
4140
4141 // Normally, we would just ask the physics scene to return the axis for the joint.
4142 // Unfortunately, ODE sometimes returns <0,0,0> for the joint axis, which should
4143 // never occur. Therefore we cannot rely on ODE to always return a correct joint axis.
4144 // Therefore the following call does not always work:
4145 //PhysicsVector phyJointAxis = _PhyScene.GetJointAxis(joint);
4146
4147 // instead we compute the joint orientation by saving the original joint orientation
4148 // relative to one of the jointed bodies, and applying this transformation
4149 // to the current position of the jointed bodies (the tracked body) to compute the
4150 // current joint orientation.
4151
4152 if (joint.TrackedBodyName == null)
4153 {
4154 jointErrorMessage(joint, "joint.TrackedBodyName is null, joint " + joint.ObjectNameInScene);
4155 }
4156
4157 Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z);
4158 Quaternion q = trackedBody.RotationOffset * joint.LocalRotation;
4159
4160 jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update
4161 jointProxyObject.ParentGroup.UpdateGroupRotation(q); // schedules the entire group for a terse update
4162 }
4163 break;
4164 }
4165 }
4166
4167 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and
4168 // update non-physical objects like the joint proxy objects that represent the position
4169 // of the joints in the scene.
4170
4171 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene
4172 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called
4173 // from within the OdePhysicsScene.
4174 protected internal void jointDeactivated(PhysicsJoint joint)
4175 {
4176 //m_log.Debug("[NINJA] SceneGraph.jointDeactivated, joint:" + joint.ObjectNameInScene);
4177 // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
4178 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
4179 if (jointProxyObject == null)
4180 {
4181 jointErrorMessage(joint, "WARNING, trying to deactivate (stop interpolation of) joint proxy, but not found, name " + joint.ObjectNameInScene);
4182 return;
4183 }
4184
4185 // turn the proxy non-physical, which also stops its client-side interpolation
4186 bool wasUsingPhysics = ((jointProxyObject.ObjectFlags & (uint)PrimFlags.Physics) != 0);
4187 if (wasUsingPhysics)
4188 {
4189 jointProxyObject.UpdatePrimFlags(false, false, true, false); // FIXME: possible deadlock here; check to make sure all the scene alterations set into motion here won't deadlock
4190 }
4191 }
4192
4193 // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and
4194 // alert the user of errors by using the debug channel in the same way that scripts alert
4195 // the user of compile errors.
4196
4197 // This routine is normally called from within a lock (OdeLock) from within the OdePhysicsScene
4198 // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called
4199 // from within the OdePhysicsScene.
4200 public void jointErrorMessage(PhysicsJoint joint, string message)
4201 {
4202 // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary
4203 if (joint != null)
4204 {
4205 if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages)
4206 return;
4207
4208 SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene);
4209 if (jointProxyObject != null)
4210 {
4211 SimChat(Utils.StringToBytes("[NINJA] " + message),
4212 ChatTypeEnum.DebugChannel,
4213 2147483647,
4214 jointProxyObject.AbsolutePosition,
4215 jointProxyObject.Name,
4216 jointProxyObject.UUID,
4217 false);
4218
4219 joint.ErrorMessageCount++;
4220
4221 if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages)
4222 {
4223 SimChat(Utils.StringToBytes("[NINJA] Too many messages for this joint, suppressing further messages."),
4224 ChatTypeEnum.DebugChannel,
4225 2147483647,
4226 jointProxyObject.AbsolutePosition,
4227 jointProxyObject.Name,
4228 jointProxyObject.UUID,
4229 false);
4230 }
4231 }
4232 else
4233 {
4234 // couldn't find the joint proxy object; the error message is silently suppressed
4235 }
4236 }
4237 }
4238 }
4239}
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs
new file mode 100644
index 0000000..6d61e9f
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs
@@ -0,0 +1,419 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Threading;
32using OpenMetaverse;
33using log4net;
34using OpenSim.Framework;
35using OpenSim.Framework.Communications.Cache;
36using OpenSim.Region.Framework.Interfaces;
37
38namespace OpenSim.Region.Framework.Scenes
39{
40 public abstract class SceneBase : IScene
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 #region Events
45
46 public event restart OnRestart;
47
48 #endregion
49
50 #region Fields
51
52 /// <value>
53 /// All the region modules attached to this scene.
54 /// </value>
55 public Dictionary<string, IRegionModule> Modules
56 {
57 get { return m_modules; }
58 }
59 protected Dictionary<string, IRegionModule> m_modules = new Dictionary<string, IRegionModule>();
60
61 /// <value>
62 /// The module interfaces available from this scene.
63 /// </value>
64 protected Dictionary<Type, List<object> > ModuleInterfaces = new Dictionary<Type, List<object> >();
65
66 protected Dictionary<string, object> ModuleAPIMethods = new Dictionary<string, object>();
67 protected Dictionary<string, ICommander> m_moduleCommanders = new Dictionary<string, ICommander>();
68
69 /// <value>
70 /// Registered classes that are capable of creating entities.
71 /// </value>
72 protected Dictionary<PCode, IEntityCreator> m_entityCreators = new Dictionary<PCode, IEntityCreator>();
73
74 //API module interfaces
75
76 /// <summary>
77 /// The last allocated local prim id. When a new local id is requested, the next number in the sequence is
78 /// dispensed.
79 /// </summary>
80 protected uint m_lastAllocatedLocalId = 720000;
81
82 private readonly Mutex _primAllocateMutex = new Mutex(false);
83
84 private readonly ClientManager m_clientManager = new ClientManager();
85
86 public ClientManager ClientManager
87 {
88 get { return m_clientManager; }
89 }
90
91 protected ulong m_regionHandle;
92 protected string m_regionName;
93 protected RegionInfo m_regInfo;
94
95 //public TerrainEngine Terrain;
96 public ITerrainChannel Heightmap;
97
98 /// <value>
99 /// Allows retrieval of land information for this scene.
100 /// </value>
101 public ILandChannel LandChannel;
102
103 /// <value>
104 /// Manage events that occur in this scene (avatar movement, script rez, etc.). Commonly used by region modules
105 /// to subscribe to scene events.
106 /// </value>
107 public EventManager EventManager
108 {
109 get { return m_eventManager; }
110 }
111 protected EventManager m_eventManager;
112
113 protected ScenePermissions m_permissions;
114 public ScenePermissions Permissions
115 {
116 get { return m_permissions; }
117 }
118
119 protected string m_datastore;
120
121 private AssetCache m_assetCache;
122
123 public AssetCache AssetCache
124 {
125 get { return m_assetCache; }
126 set { m_assetCache = value; }
127 }
128
129 protected RegionStatus m_regStatus;
130
131 public RegionStatus Region_Status
132 {
133 get { return m_regStatus; }
134 set { m_regStatus = value; }
135 }
136
137 #endregion
138
139 #region Update Methods
140
141 /// <summary>
142 /// Normally called once every frame/tick to let the world preform anything required (like running the physics simulation)
143 /// </summary>
144 public abstract void Update();
145
146 #endregion
147
148 #region Terrain Methods
149
150 /// <summary>
151 /// Loads the World heightmap
152 /// </summary>
153 public abstract void LoadWorldMap();
154
155 /// <summary>
156 /// Send the region heightmap to the client
157 /// </summary>
158 /// <param name="RemoteClient">Client to send to</param>
159 public virtual void SendLayerData(IClientAPI RemoteClient)
160 {
161 RemoteClient.SendLayerData(Heightmap.GetFloatsSerialised());
162 }
163
164 #endregion
165
166 #region Add/Remove Agent/Avatar
167
168 /// <summary>
169 /// Register the new client with the scene. The client starts off as a child agent - the later agent crossing
170 /// will promote it to a root agent during login.
171 /// </summary>
172 /// <param name="client"></param
173 public abstract void AddNewClient(IClientAPI client);
174
175 /// <summary>
176 /// Remove a client from the scene
177 /// </summary>
178 /// <param name="agentID"></param>
179 public abstract void RemoveClient(UUID agentID);
180
181 public abstract void CloseAllAgents(uint circuitcode);
182
183 #endregion
184
185 /// <summary>
186 ///
187 /// </summary>
188 /// <returns></returns>
189 public virtual RegionInfo RegionInfo
190 {
191 get { return m_regInfo; }
192 }
193
194 #region admin stuff
195
196 /// <summary>
197 /// Region Restart - Seconds till restart.
198 /// </summary>
199 /// <param name="seconds"></param>
200 public virtual void Restart(int seconds)
201 {
202 m_log.Error("[REGION]: passing Restart Message up the namespace");
203 restart handlerPhysicsCrash = OnRestart;
204 if (handlerPhysicsCrash != null)
205 handlerPhysicsCrash(RegionInfo);
206 }
207
208 public virtual bool PresenceChildStatus(UUID avatarID)
209 {
210 return false;
211 }
212
213 public abstract bool OtherRegionUp(RegionInfo thisRegion);
214
215 public virtual string GetSimulatorVersion()
216 {
217 return "OpenSimulator Server";
218 }
219
220 #endregion
221
222 #region Shutdown
223
224 /// <summary>
225 /// Tidy before shutdown
226 /// </summary>
227 public virtual void Close()
228 {
229 // Shut down all non shared modules.
230 foreach (IRegionModule module in Modules.Values)
231 {
232 if (!module.IsSharedModule)
233 {
234 module.Close();
235 }
236 }
237 Modules.Clear();
238
239 try
240 {
241 EventManager.TriggerShutdown();
242 }
243 catch (Exception e)
244 {
245 m_log.Error("[SCENE]: SceneBase.cs: Close() - Failed with exception " + e.ToString());
246 }
247 }
248
249 #endregion
250
251 /// <summary>
252 /// Returns a new unallocated local ID
253 /// </summary>
254 /// <returns>A brand new local ID</returns>
255 protected internal uint AllocateLocalId()
256 {
257 uint myID;
258
259 _primAllocateMutex.WaitOne();
260 myID = ++m_lastAllocatedLocalId;
261 _primAllocateMutex.ReleaseMutex();
262
263 return myID;
264 }
265
266 #region Module Methods
267
268 /// <summary>
269 /// Add a module to this scene.
270 /// </summary>
271 /// <param name="name"></param>
272 /// <param name="module"></param>
273 public void AddModule(string name, IRegionModule module)
274 {
275 if (!Modules.ContainsKey(name))
276 {
277 Modules.Add(name, module);
278 }
279 }
280
281 public void RegisterModuleCommander(ICommander commander)
282 {
283 lock (m_moduleCommanders)
284 {
285 m_moduleCommanders.Add(commander.Name, commander);
286 }
287 }
288
289 /// <summary>
290 /// Get a module commander
291 /// </summary>
292 /// <param name="name"></param>
293 /// <returns>The module commander, null if no module commander with that name was found</returns>
294 public ICommander GetCommander(string name)
295 {
296 lock (m_moduleCommanders)
297 {
298 if (m_moduleCommanders.ContainsKey(name))
299 return m_moduleCommanders[name];
300 }
301
302 return null;
303 }
304
305 public Dictionary<string, ICommander> GetCommanders()
306 {
307 return m_moduleCommanders;
308 }
309
310 /// <summary>
311 /// Register an interface to a region module. This allows module methods to be called directly as
312 /// well as via events. If there is already a module registered for this interface, it is not replaced
313 /// (is this the best behaviour?)
314 /// </summary>
315 /// <param name="mod"></param>
316 public void RegisterModuleInterface<M>(M mod)
317 {
318 if (!ModuleInterfaces.ContainsKey(typeof(M)))
319 {
320 List<Object> l = new List<Object>();
321 l.Add(mod);
322 ModuleInterfaces.Add(typeof(M), l);
323
324 if (mod is IEntityCreator)
325 {
326 IEntityCreator entityCreator = (IEntityCreator)mod;
327 foreach (PCode pcode in entityCreator.CreationCapabilities)
328 {
329 m_entityCreators[pcode] = entityCreator;
330 }
331 }
332 }
333 }
334
335 public void StackModuleInterface<M>(M mod)
336 {
337 List<Object> l;
338 if (ModuleInterfaces.ContainsKey(typeof(M)))
339 l = ModuleInterfaces[typeof(M)];
340 else
341 l = new List<Object>();
342
343 if (l.Contains(mod))
344 return;
345
346 l.Add(mod);
347
348 if (mod is IEntityCreator)
349 {
350 IEntityCreator entityCreator = (IEntityCreator)mod;
351 foreach (PCode pcode in entityCreator.CreationCapabilities)
352 {
353 m_entityCreators[pcode] = entityCreator;
354 }
355 }
356
357 ModuleInterfaces[typeof(M)] = l;
358 }
359
360 /// <summary>
361 /// For the given interface, retrieve the region module which implements it.
362 /// </summary>
363 /// <returns>null if there is no registered module implementing that interface</returns>
364 public T RequestModuleInterface<T>()
365 {
366 if (ModuleInterfaces.ContainsKey(typeof(T)))
367 {
368 return (T)ModuleInterfaces[typeof(T)][0];
369 }
370 else
371 {
372 return default(T);
373 }
374 }
375
376 /// <summary>
377 /// For the given interface, retrieve an array of region modules that implement it.
378 /// </summary>
379 /// <returns>an empty array if there are no registered modules implementing that interface</returns>
380 public T[] RequestModuleInterfaces<T>()
381 {
382 if (ModuleInterfaces.ContainsKey(typeof(T)))
383 {
384 List<T> ret = new List<T>();
385
386 foreach (Object o in ModuleInterfaces[typeof(T)])
387 ret.Add((T)o);
388 return ret.ToArray();
389 }
390 else
391 {
392 return new T[] { default(T) };
393 }
394 }
395
396 #endregion
397
398 /// <summary>
399 /// Shows various details about the sim based on the parameters supplied by the console command in openSimMain.
400 /// </summary>
401 /// <param name="showParams">What to show</param>
402 public virtual void Show(string[] showParams)
403 {
404 switch (showParams[0])
405 {
406 case "modules":
407 m_log.Error("The currently loaded modules in " + RegionInfo.RegionName + " are:");
408 foreach (IRegionModule module in Modules.Values)
409 {
410 if (!module.IsSharedModule)
411 {
412 m_log.Error("Region Module: " + module.Name);
413 }
414 }
415 break;
416 }
417 }
418 }
419}
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
new file mode 100644
index 0000000..a2b2537
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
@@ -0,0 +1,1095 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Reflection;
32using System.Threading;
33using OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using log4net;
36using OpenSim.Framework;
37using OpenSim.Framework.Communications;
38using OpenSim.Framework.Communications.Capabilities;
39using OpenSim.Region.Framework.Interfaces;
40using OSD = OpenMetaverse.StructuredData.OSD;
41
42namespace OpenSim.Region.Framework.Scenes
43{
44 public delegate void KiPrimitiveDelegate(uint localID);
45
46 public delegate void RemoveKnownRegionsFromAvatarList(UUID avatarID, List<ulong> regionlst);
47
48 public class SceneCommunicationService //one instance per region
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51
52 protected CommunicationsManager m_commsProvider;
53 protected IInterregionCommsOut m_interregionCommsOut;
54 protected RegionInfo m_regionInfo;
55
56 protected RegionCommsListener regionCommsHost;
57
58 protected List<UUID> m_agentsInTransit;
59
60 public event AgentCrossing OnAvatarCrossingIntoRegion;
61 public event ExpectUserDelegate OnExpectUser;
62 public event ExpectPrimDelegate OnExpectPrim;
63 public event CloseAgentConnection OnCloseAgentConnection;
64 public event PrimCrossing OnPrimCrossingIntoRegion;
65 public event RegionUp OnRegionUp;
66 public event ChildAgentUpdate OnChildAgentUpdate;
67 //public event RemoveKnownRegionsFromAvatarList OnRemoveKnownRegionFromAvatar;
68 public event LogOffUser OnLogOffUser;
69 public event GetLandData OnGetLandData;
70
71 private AgentCrossing handlerAvatarCrossingIntoRegion = null; // OnAvatarCrossingIntoRegion;
72 private ExpectUserDelegate handlerExpectUser = null; // OnExpectUser;
73 private ExpectPrimDelegate handlerExpectPrim = null; // OnExpectPrim;
74 private CloseAgentConnection handlerCloseAgentConnection = null; // OnCloseAgentConnection;
75 private PrimCrossing handlerPrimCrossingIntoRegion = null; // OnPrimCrossingIntoRegion;
76 private RegionUp handlerRegionUp = null; // OnRegionUp;
77 private ChildAgentUpdate handlerChildAgentUpdate = null; // OnChildAgentUpdate;
78 //private RemoveKnownRegionsFromAvatarList handlerRemoveKnownRegionFromAvatar = null; // OnRemoveKnownRegionFromAvatar;
79 private LogOffUser handlerLogOffUser = null;
80 private GetLandData handlerGetLandData = null; // OnGetLandData
81
82 public KiPrimitiveDelegate KiPrimitive;
83
84 public SceneCommunicationService(CommunicationsManager commsMan)
85 {
86 m_commsProvider = commsMan;
87 m_agentsInTransit = new List<UUID>();
88 }
89
90 /// <summary>
91 /// Register a region with the grid
92 /// </summary>
93 /// <param name="regionInfos"></param>
94 /// <exception cref="System.Exception">Thrown if region registration fails.</exception>
95 public void RegisterRegion(IInterregionCommsOut comms_out, RegionInfo regionInfos)
96 {
97 m_interregionCommsOut = comms_out;
98
99 m_regionInfo = regionInfos;
100 m_commsProvider.GridService.gdebugRegionName = regionInfos.RegionName;
101 m_commsProvider.InterRegion.rdebugRegionName = regionInfos.RegionName;
102 regionCommsHost = m_commsProvider.GridService.RegisterRegion(m_regionInfo);
103
104 if (regionCommsHost != null)
105 {
106 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: registered with gridservice and got" + regionCommsHost.ToString());
107
108 regionCommsHost.debugRegionName = regionInfos.RegionName;
109 regionCommsHost.OnExpectPrim += IncomingPrimCrossing;
110 regionCommsHost.OnExpectUser += NewUserConnection;
111 regionCommsHost.OnAvatarCrossingIntoRegion += AgentCrossing;
112 regionCommsHost.OnCloseAgentConnection += CloseConnection;
113 regionCommsHost.OnRegionUp += newRegionUp;
114 regionCommsHost.OnChildAgentUpdate += ChildAgentUpdate;
115 regionCommsHost.OnLogOffUser += GridLogOffUser;
116 regionCommsHost.OnGetLandData += FetchLandData;
117 }
118 else
119 {
120 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: registered with gridservice and got null");
121 }
122 }
123
124 public RegionInfo RequestClosestRegion(string name)
125 {
126 return m_commsProvider.GridService.RequestClosestRegion(name);
127 }
128
129 public void Close()
130 {
131 if (regionCommsHost != null)
132 {
133 regionCommsHost.OnLogOffUser -= GridLogOffUser;
134 regionCommsHost.OnChildAgentUpdate -= ChildAgentUpdate;
135 regionCommsHost.OnRegionUp -= newRegionUp;
136 regionCommsHost.OnExpectUser -= NewUserConnection;
137 regionCommsHost.OnExpectPrim -= IncomingPrimCrossing;
138 regionCommsHost.OnAvatarCrossingIntoRegion -= AgentCrossing;
139 regionCommsHost.OnCloseAgentConnection -= CloseConnection;
140 regionCommsHost.OnGetLandData -= FetchLandData;
141
142 try
143 {
144 m_commsProvider.GridService.DeregisterRegion(m_regionInfo);
145 }
146 catch (Exception e)
147 {
148 m_log.ErrorFormat(
149 "[GRID]: Deregistration of region {0} from the grid failed - {1}. Continuing",
150 m_regionInfo.RegionName, e);
151 }
152
153 regionCommsHost = null;
154 }
155 }
156
157 #region CommsManager Event handlers
158
159 /// <summary>
160 ///
161 /// </summary>
162 /// <param name="regionHandle"></param>
163 /// <param name="agent"></param>
164 ///
165 protected void NewUserConnection(AgentCircuitData agent)
166 {
167 handlerExpectUser = OnExpectUser;
168 if (handlerExpectUser != null)
169 {
170 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: OnExpectUser Fired for User:" + agent.firstname + " " + agent.lastname);
171 handlerExpectUser(agent);
172 }
173 }
174
175 protected void GridLogOffUser(UUID AgentID, UUID RegionSecret, string message)
176 {
177 handlerLogOffUser = OnLogOffUser;
178 if (handlerLogOffUser != null)
179 {
180 handlerLogOffUser(AgentID, RegionSecret, message);
181 }
182 }
183
184 protected bool newRegionUp(RegionInfo region)
185 {
186 handlerRegionUp = OnRegionUp;
187 if (handlerRegionUp != null)
188 {
189 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: newRegionUp Fired for User:" + region.RegionName);
190 handlerRegionUp(region);
191 }
192 return true;
193 }
194
195 protected bool ChildAgentUpdate(ChildAgentDataUpdate cAgentData)
196 {
197 handlerChildAgentUpdate = OnChildAgentUpdate;
198 if (handlerChildAgentUpdate != null)
199 handlerChildAgentUpdate(cAgentData);
200
201
202 return true;
203 }
204
205 protected void AgentCrossing(UUID agentID, Vector3 position, bool isFlying)
206 {
207 handlerAvatarCrossingIntoRegion = OnAvatarCrossingIntoRegion;
208 if (handlerAvatarCrossingIntoRegion != null)
209 {
210 handlerAvatarCrossingIntoRegion(agentID, position, isFlying);
211 }
212 }
213
214 protected bool IncomingPrimCrossing(UUID primID, String objXMLData, int XMLMethod)
215 {
216 handlerExpectPrim = OnExpectPrim;
217 if (handlerExpectPrim != null)
218 {
219 return handlerExpectPrim(primID, objXMLData, XMLMethod);
220 }
221 else
222 {
223 return false;
224 }
225
226 }
227
228 protected void PrimCrossing(UUID primID, Vector3 position, bool isPhysical)
229 {
230 handlerPrimCrossingIntoRegion = OnPrimCrossingIntoRegion;
231 if (handlerPrimCrossingIntoRegion != null)
232 {
233 handlerPrimCrossingIntoRegion(primID, position, isPhysical);
234 }
235 }
236
237 protected bool CloseConnection(UUID agentID)
238 {
239 m_log.Debug("[INTERREGION]: Incoming Agent Close Request for agent: " + agentID);
240
241 handlerCloseAgentConnection = OnCloseAgentConnection;
242 if (handlerCloseAgentConnection != null)
243 {
244 return handlerCloseAgentConnection(agentID);
245 }
246
247 return false;
248 }
249
250 protected LandData FetchLandData(uint x, uint y)
251 {
252 handlerGetLandData = OnGetLandData;
253 if (handlerGetLandData != null)
254 {
255 return handlerGetLandData(x, y);
256 }
257 return null;
258 }
259
260 #endregion
261
262 #region Inform Client of Neighbours
263
264 private delegate void InformClientOfNeighbourDelegate(
265 ScenePresence avatar, AgentCircuitData a, SimpleRegionInfo reg, IPEndPoint endPoint, bool newAgent);
266
267 private void InformClientOfNeighbourCompleted(IAsyncResult iar)
268 {
269 InformClientOfNeighbourDelegate icon = (InformClientOfNeighbourDelegate) iar.AsyncState;
270 icon.EndInvoke(iar);
271 }
272
273 /// <summary>
274 /// Async component for informing client of which neighbours exist
275 /// </summary>
276 /// <remarks>
277 /// This needs to run asynchronesously, as a network timeout may block the thread for a long while
278 /// </remarks>
279 /// <param name="remoteClient"></param>
280 /// <param name="a"></param>
281 /// <param name="regionHandle"></param>
282 /// <param name="endPoint"></param>
283 private void InformClientOfNeighbourAsync(ScenePresence avatar, AgentCircuitData a, SimpleRegionInfo reg,
284 IPEndPoint endPoint, bool newAgent)
285 {
286 // Let's wait just a little to give time to originating regions to catch up with closing child agents
287 // after a cross here
288 Thread.Sleep(500);
289
290 uint x, y;
291 Utils.LongToUInts(reg.RegionHandle, out x, out y);
292 x = x / Constants.RegionSize;
293 y = y / Constants.RegionSize;
294 m_log.Info("[INTERGRID]: Starting to inform client about neighbour " + x + ", " + y + "(" + endPoint.ToString() + ")");
295
296 string capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort
297 + "/CAPS/" + a.CapsPath + "0000/";
298
299 //bool regionAccepted = m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, a);
300 bool regionAccepted = m_interregionCommsOut.SendCreateChildAgent(reg.RegionHandle, a);
301
302 if (regionAccepted && newAgent)
303 {
304 IEventQueue eq = avatar.Scene.RequestModuleInterface<IEventQueue>();
305 if (eq != null)
306 {
307 eq.EnableSimulator(reg.RegionHandle, endPoint, avatar.UUID);
308 eq.EstablishAgentCommunication(avatar.UUID, endPoint, capsPath);
309 m_log.DebugFormat("[CAPS]: Sending new CAPS seed url {0} to client {1} in region {2}",
310 capsPath, avatar.UUID, avatar.Scene.RegionInfo.RegionName);
311 }
312 else
313 {
314 avatar.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint);
315 // TODO: make Event Queue disablable!
316 }
317
318 m_log.Info("[INTERGRID]: Completed inform client about neighbour " + endPoint.ToString());
319 }
320 }
321
322 public void RequestNeighbors(RegionInfo region)
323 {
324 // List<SimpleRegionInfo> neighbours =
325 m_commsProvider.GridService.RequestNeighbours(m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
326 //IPEndPoint blah = new IPEndPoint();
327
328 //blah.Address = region.RemotingAddress;
329 //blah.Port = region.RemotingPort;
330 }
331
332 /// <summary>
333 /// This informs all neighboring regions about agent "avatar".
334 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
335 /// </summary>
336 public void EnableNeighbourChildAgents(ScenePresence avatar, List<RegionInfo> lstneighbours)
337 {
338 List<SimpleRegionInfo> neighbours = new List<SimpleRegionInfo>();
339
340 //m_commsProvider.GridService.RequestNeighbours(m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
341 for (int i = 0; i < lstneighbours.Count; i++)
342 {
343 // We don't want to keep sending to regions that consistently fail on comms.
344 if (!(lstneighbours[i].commFailTF))
345 {
346 neighbours.Add(new SimpleRegionInfo(lstneighbours[i]));
347 }
348 }
349 // we're going to be using the above code once neighbour cache is correct. Currently it doesn't appear to be
350 // So we're temporarily going back to the old method of grabbing it from the Grid Server Every time :/
351 neighbours =
352 m_commsProvider.GridService.RequestNeighbours(m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
353
354 /// We need to find the difference between the new regions where there are no child agents
355 /// and the regions where there are already child agents. We only send notification to the former.
356 List<ulong> neighbourHandles = NeighbourHandles(neighbours); // on this region
357 neighbourHandles.Add(avatar.Scene.RegionInfo.RegionHandle); // add this region too
358 List<ulong> previousRegionNeighbourHandles
359 = new List<ulong>(avatar.Scene.CapsModule.GetChildrenSeeds(avatar.UUID).Keys);
360 List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
361 List<ulong> oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
362
363 //Dump("Current Neighbors", neighbourHandles);
364 //Dump("Previous Neighbours", previousRegionNeighbourHandles);
365 //Dump("New Neighbours", newRegions);
366 //Dump("Old Neighbours", oldRegions);
367
368 /// Update the scene presence's known regions here on this region
369 avatar.DropOldNeighbours(oldRegions);
370
371 /// Collect as many seeds as possible
372 Dictionary<ulong, string> seeds
373 = new Dictionary<ulong, string>(avatar.Scene.CapsModule.GetChildrenSeeds(avatar.UUID));
374
375 //Console.WriteLine(" !!! No. of seeds: " + seeds.Count);
376 if (!seeds.ContainsKey(avatar.Scene.RegionInfo.RegionHandle))
377 seeds.Add(avatar.Scene.RegionInfo.RegionHandle, avatar.ControllingClient.RequestClientInfo().CapsPath);
378
379 /// Create the necessary child agents
380 List<AgentCircuitData> cagents = new List<AgentCircuitData>();
381 foreach (SimpleRegionInfo neighbour in neighbours)
382 {
383 if (neighbour.RegionHandle != avatar.Scene.RegionInfo.RegionHandle)
384 {
385
386 AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo();
387 agent.BaseFolder = UUID.Zero;
388 agent.InventoryFolder = UUID.Zero;
389 agent.startpos = new Vector3(128, 128, 70);
390 agent.child = true;
391
392 if (newRegions.Contains(neighbour.RegionHandle))
393 {
394 agent.CapsPath = CapsUtil.GetRandomCapsObjectPath();
395 avatar.AddNeighbourRegion(neighbour.RegionHandle, agent.CapsPath);
396 seeds.Add(neighbour.RegionHandle, agent.CapsPath);
397 }
398 else
399 agent.CapsPath = avatar.Scene.CapsModule.GetChildSeed(avatar.UUID, neighbour.RegionHandle);
400
401 cagents.Add(agent);
402 }
403 }
404
405 /// Update all child agent with everyone's seeds
406 foreach (AgentCircuitData a in cagents)
407 {
408 a.ChildrenCapSeeds = new Dictionary<ulong, string>(seeds);
409 }
410 // These two are the same thing!
411 avatar.Scene.CapsModule.SetChildrenSeed(avatar.UUID, seeds);
412 avatar.KnownRegions = seeds;
413 //avatar.Scene.DumpChildrenSeeds(avatar.UUID);
414 //avatar.DumpKnownRegions();
415
416 bool newAgent = false;
417 int count = 0;
418 foreach (SimpleRegionInfo neighbour in neighbours)
419 {
420 // Don't do it if there's already an agent in that region
421 if (newRegions.Contains(neighbour.RegionHandle))
422 newAgent = true;
423 else
424 newAgent = false;
425
426 if (neighbour.RegionHandle != avatar.Scene.RegionInfo.RegionHandle)
427 {
428 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
429 try
430 {
431 d.BeginInvoke(avatar, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent,
432 InformClientOfNeighbourCompleted,
433 d);
434 }
435 catch (Exception e)
436 {
437 m_log.ErrorFormat(
438 "[REGIONINFO]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}",
439 neighbour.ExternalHostName,
440 neighbour.RegionHandle,
441 neighbour.RegionLocX,
442 neighbour.RegionLocY,
443 e);
444
445 // FIXME: Okay, even though we've failed, we're still going to throw the exception on,
446 // since I don't know what will happen if we just let the client continue
447
448 // XXX: Well, decided to swallow the exception instead for now. Let us see how that goes.
449 // throw e;
450
451 }
452 }
453 count++;
454 }
455 }
456
457 /// <summary>
458 /// This informs a single neighboring region about agent "avatar".
459 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
460 /// </summary>
461 public void InformNeighborChildAgent(ScenePresence avatar, SimpleRegionInfo region, List<RegionInfo> neighbours)
462 {
463 AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo();
464 agent.BaseFolder = UUID.Zero;
465 agent.InventoryFolder = UUID.Zero;
466 agent.startpos = new Vector3(128, 128, 70);
467 agent.child = true;
468
469 InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
470 d.BeginInvoke(avatar, agent, region, region.ExternalEndPoint, true,
471 InformClientOfNeighbourCompleted,
472 d);
473 }
474
475 #endregion
476
477 public delegate void InformNeighbourThatRegionUpDelegate(RegionInfo region, ulong regionhandle);
478
479 private void InformNeighborsThatRegionisUpCompleted(IAsyncResult iar)
480 {
481 InformNeighbourThatRegionUpDelegate icon = (InformNeighbourThatRegionUpDelegate) iar.AsyncState;
482 icon.EndInvoke(iar);
483 }
484
485 /// <summary>
486 /// Asynchronous call to information neighbouring regions that this region is up
487 /// </summary>
488 /// <param name="region"></param>
489 /// <param name="regionhandle"></param>
490 private void InformNeighboursThatRegionIsUpAsync(RegionInfo region, ulong regionhandle)
491 {
492 m_log.Info("[INTERGRID]: Starting to inform neighbors that I'm here");
493 //RegionUpData regiondata = new RegionUpData(region.RegionLocX, region.RegionLocY, region.ExternalHostName, region.InternalEndPoint.Port);
494
495 bool regionAccepted =
496 m_commsProvider.InterRegion.RegionUp(new SerializableRegionInfo(region), regionhandle);
497
498 if (regionAccepted)
499 {
500 m_log.Info("[INTERGRID]: Completed informing neighbors that I'm here");
501 handlerRegionUp = OnRegionUp;
502
503 // yes, we're notifying ourselves.
504 if (handlerRegionUp != null)
505 handlerRegionUp(region);
506 }
507 else
508 {
509 m_log.Warn("[INTERGRID]: Failed to inform neighbors that I'm here.");
510 }
511 }
512
513 /// <summary>
514 /// Called by scene when region is initialized (not always when it's listening for agents)
515 /// This is an inter-region message that informs the surrounding neighbors that the sim is up.
516 /// </summary>
517 public void InformNeighborsThatRegionisUp(RegionInfo region)
518 {
519 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName);
520
521
522 List<SimpleRegionInfo> neighbours = new List<SimpleRegionInfo>();
523 // This stays uncached because we don't already know about our neighbors at this point.
524 neighbours = m_commsProvider.GridService.RequestNeighbours(m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
525 if (neighbours != null)
526 {
527 for (int i = 0; i < neighbours.Count; i++)
528 {
529 InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync;
530
531 d.BeginInvoke(region, neighbours[i].RegionHandle,
532 InformNeighborsThatRegionisUpCompleted,
533 d);
534 }
535 }
536
537 //bool val = m_commsProvider.InterRegion.RegionUp(new SerializableRegionInfo(region));
538 }
539
540 public delegate void SendChildAgentDataUpdateDelegate(AgentPosition cAgentData, ulong regionHandle);
541
542 /// <summary>
543 /// This informs all neighboring regions about the settings of it's child agent.
544 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
545 ///
546 /// This contains information, such as, Draw Distance, Camera location, Current Position, Current throttle settings, etc.
547 ///
548 /// </summary>
549 private void SendChildAgentDataUpdateAsync(AgentPosition cAgentData, ulong regionHandle)
550 {
551 //m_log.Info("[INTERGRID]: Informing neighbors about my agent in " + m_regionInfo.RegionName);
552 try
553 {
554 //m_commsProvider.InterRegion.ChildAgentUpdate(regionHandle, cAgentData);
555 m_interregionCommsOut.SendChildAgentUpdate(regionHandle, cAgentData);
556 }
557 catch
558 {
559 // Ignore; we did our best
560 }
561
562 //if (regionAccepted)
563 //{
564 // //m_log.Info("[INTERGRID]: Completed sending a neighbor an update about my agent");
565 //}
566 //else
567 //{
568 // //m_log.Info("[INTERGRID]: Failed sending a neighbor an update about my agent");
569 //}
570
571 }
572
573 private void SendChildAgentDataUpdateCompleted(IAsyncResult iar)
574 {
575 SendChildAgentDataUpdateDelegate icon = (SendChildAgentDataUpdateDelegate) iar.AsyncState;
576 icon.EndInvoke(iar);
577 }
578
579 public void SendChildAgentDataUpdate(AgentPosition cAgentData, ScenePresence presence)
580 {
581 // This assumes that we know what our neighbors are.
582 try
583 {
584 foreach (ulong regionHandle in presence.KnownChildRegionHandles)
585 {
586 if (regionHandle != m_regionInfo.RegionHandle)
587 {
588 SendChildAgentDataUpdateDelegate d = SendChildAgentDataUpdateAsync;
589 d.BeginInvoke(cAgentData, regionHandle,
590 SendChildAgentDataUpdateCompleted,
591 d);
592 }
593 }
594 }
595 catch (InvalidOperationException)
596 {
597 // We're ignoring a collection was modified error because this data gets old and outdated fast.
598 }
599
600 }
601
602 public delegate void SendCloseChildAgentDelegate(UUID agentID, ulong regionHandle);
603
604 /// <summary>
605 /// This Closes child agents on neighboring regions
606 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
607 /// </summary>
608 protected void SendCloseChildAgentAsync(UUID agentID, ulong regionHandle)
609 {
610
611 m_log.Debug("[INTERGRID]: Sending close agent to " + regionHandle);
612 // let's do our best, but there's not much we can do if the neighbour doesn't accept.
613
614 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
615 m_interregionCommsOut.SendCloseAgent(regionHandle, agentID);
616 }
617
618 private void SendCloseChildAgentCompleted(IAsyncResult iar)
619 {
620 SendCloseChildAgentDelegate icon = (SendCloseChildAgentDelegate)iar.AsyncState;
621 icon.EndInvoke(iar);
622 }
623
624 public void SendCloseChildAgentConnections(UUID agentID, List<ulong> regionslst)
625 {
626 foreach (ulong handle in regionslst)
627 {
628 SendCloseChildAgentDelegate d = SendCloseChildAgentAsync;
629 d.BeginInvoke(agentID, handle,
630 SendCloseChildAgentCompleted,
631 d);
632 }
633 }
634
635 /// <summary>
636 /// Helper function to request neighbors from grid-comms
637 /// </summary>
638 /// <param name="regionHandle"></param>
639 /// <returns></returns>
640 public virtual RegionInfo RequestNeighbouringRegionInfo(ulong regionHandle)
641 {
642 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending Grid Services Request about neighbor " + regionHandle.ToString());
643 return m_commsProvider.GridService.RequestNeighbourInfo(regionHandle);
644 }
645
646 /// <summary>
647 /// Helper function to request neighbors from grid-comms
648 /// </summary>
649 /// <param name="regionID"></param>
650 /// <returns></returns>
651 public virtual RegionInfo RequestNeighbouringRegionInfo(UUID regionID)
652 {
653 //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending Grid Services Request about neighbor " + regionID);
654 return m_commsProvider.GridService.RequestNeighbourInfo(regionID);
655 }
656
657 /// <summary>
658 /// Requests map blocks in area of minX, maxX, minY, MaxY in world cordinates
659 /// </summary>
660 /// <param name="minX"></param>
661 /// <param name="minY"></param>
662 /// <param name="maxX"></param>
663 /// <param name="maxY"></param>
664 public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY)
665 {
666 List<MapBlockData> mapBlocks;
667 mapBlocks = m_commsProvider.GridService.RequestNeighbourMapBlocks(minX - 4, minY - 4, minX + 4, minY + 4);
668 remoteClient.SendMapBlock(mapBlocks, 0);
669 }
670
671 /// <summary>
672 /// Try to teleport an agent to a new region.
673 /// </summary>
674 /// <param name="remoteClient"></param>
675 /// <param name="RegionHandle"></param>
676 /// <param name="position"></param>
677 /// <param name="lookAt"></param>
678 /// <param name="flags"></param>
679 public virtual void RequestTeleportToLocation(ScenePresence avatar, ulong regionHandle, Vector3 position,
680 Vector3 lookAt, uint teleportFlags)
681 {
682 if (!avatar.Scene.Permissions.CanTeleport(avatar.UUID))
683 return;
684
685 bool destRegionUp = true;
686
687 IEventQueue eq = avatar.Scene.RequestModuleInterface<IEventQueue>();
688
689 if (regionHandle == m_regionInfo.RegionHandle)
690 {
691 m_log.DebugFormat(
692 "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation {0} within {1}",
693 position, m_regionInfo.RegionName);
694
695 // Teleport within the same region
696 if (position.X < 0 || position.X > Constants.RegionSize || position.Y < 0 || position.Y > Constants.RegionSize || position.Z < 0)
697 {
698 Vector3 emergencyPos = new Vector3(128, 128, 128);
699
700 m_log.WarnFormat(
701 "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}",
702 position, avatar.Name, avatar.UUID, emergencyPos);
703 position = emergencyPos;
704 }
705
706 // TODO: Get proper AVG Height
707 float localAVHeight = 1.56f;
708 float posZLimit = (float)avatar.Scene.GetLandHeight((int)position.X, (int)position.Y);
709 float newPosZ = posZLimit + localAVHeight;
710 if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
711 {
712 position.Z = newPosZ;
713 }
714
715 // Only send this if the event queue is null
716 if (eq == null)
717 avatar.ControllingClient.SendTeleportLocationStart();
718
719 avatar.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags);
720 avatar.Teleport(position);
721 }
722 else
723 {
724 RegionInfo reg = RequestNeighbouringRegionInfo(regionHandle);
725 if (reg != null)
726 {
727 m_log.DebugFormat(
728 "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation to {0} in {1}",
729 position, reg.RegionName);
730
731 if (eq == null)
732 avatar.ControllingClient.SendTeleportLocationStart();
733
734 // Let's do DNS resolution only once in this process, please!
735 // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field,
736 // it's actually doing a lot of work.
737 IPEndPoint endPoint = reg.ExternalEndPoint;
738 if (endPoint.Address == null)
739 {
740 // Couldn't resolve the name. Can't TP, because the viewer wants IP addresses.
741 destRegionUp = false;
742 }
743
744 if (destRegionUp)
745 {
746 uint newRegionX = (uint)(reg.RegionHandle >> 40);
747 uint newRegionY = (((uint)(reg.RegionHandle)) >> 8);
748 uint oldRegionX = (uint)(m_regionInfo.RegionHandle >> 40);
749 uint oldRegionY = (((uint)(m_regionInfo.RegionHandle)) >> 8);
750
751 // Fixing a bug where teleporting while sitting results in the avatar ending up removed from
752 // both regions
753 if (avatar.ParentID != (uint)0)
754 avatar.StandUp();
755
756 if (!avatar.ValidateAttachments())
757 {
758 avatar.ControllingClient.SendTeleportFailed("Inconsistent attachment state");
759 return;
760 }
761
762 // the avatar.Close below will clear the child region list. We need this below for (possibly)
763 // closing the child agents, so save it here (we need a copy as it is Clear()-ed).
764 //List<ulong> childRegions = new List<ulong>(avatar.GetKnownRegionList());
765 // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport
766 // failure at this point (unlike a border crossing failure). So perhaps this can never fail
767 // once we reach here...
768 //avatar.Scene.RemoveCapsHandler(avatar.UUID);
769
770 string capsPath = String.Empty;
771 AgentCircuitData agentCircuit = avatar.ControllingClient.RequestClientInfo();
772 agentCircuit.BaseFolder = UUID.Zero;
773 agentCircuit.InventoryFolder = UUID.Zero;
774 agentCircuit.startpos = position;
775 agentCircuit.child = true;
776
777 if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY))
778 {
779 // brand new agent, let's create a new caps seed
780 agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath();
781 }
782
783 // Let's create an agent there if one doesn't exist yet.
784 //if (!m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, agentCircuit))
785 if (!m_interregionCommsOut.SendCreateChildAgent(reg.RegionHandle, agentCircuit))
786 {
787 avatar.ControllingClient.SendTeleportFailed("Destination is not accepting teleports.");
788 return;
789 }
790
791 // OK, it got this agent. Let's close some child agents
792 avatar.CloseChildAgents(newRegionX, newRegionY);
793
794 if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY))
795 {
796 capsPath
797 = "http://"
798 + reg.ExternalHostName
799 + ":"
800 + reg.HttpPort
801 + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);
802
803 if (eq != null)
804 {
805 eq.EnableSimulator(reg.RegionHandle, endPoint, avatar.UUID);
806
807 // ES makes the client send a UseCircuitCode message to the destination,
808 // which triggers a bunch of things there.
809 // So let's wait
810 Thread.Sleep(2000);
811
812 eq.EstablishAgentCommunication(avatar.UUID, endPoint, capsPath);
813 }
814 else
815 {
816 avatar.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint);
817 }
818 }
819 else
820 {
821 agentCircuit.CapsPath = avatar.Scene.CapsModule.GetChildSeed(avatar.UUID, reg.RegionHandle);
822 capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort
823 + "/CAPS/" + agentCircuit.CapsPath + "0000/";
824 }
825
826 // Expect avatar crossing is a heavy-duty function at the destination.
827 // That is where MakeRoot is called, which fetches appearance and inventory.
828 // Plus triggers OnMakeRoot, which spawns a series of asynchronous updates.
829 //m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId,
830 // position, false);
831
832 //{
833 // avatar.ControllingClient.SendTeleportFailed("Problem with destination.");
834 // // We should close that agent we just created over at destination...
835 // List<ulong> lst = new List<ulong>();
836 // lst.Add(reg.RegionHandle);
837 // SendCloseChildAgentAsync(avatar.UUID, lst);
838 // return;
839 //}
840
841 SetInTransit(avatar.UUID);
842 // Let's send a full update of the agent. This is a synchronous call.
843 AgentData agent = new AgentData();
844 avatar.CopyTo(agent);
845 agent.Position = position;
846 agent.CallbackURI = "http://" + m_regionInfo.ExternalHostName + ":" + m_regionInfo.HttpPort +
847 "/agent/" + avatar.UUID.ToString() + "/" + avatar.Scene.RegionInfo.RegionHandle.ToString() + "/release/";
848
849 m_interregionCommsOut.SendChildAgentUpdate(reg.RegionHandle, agent);
850
851 m_log.DebugFormat(
852 "[CAPS]: Sending new CAPS seed url {0} to client {1}", capsPath, avatar.UUID);
853
854
855 if (eq != null)
856 {
857 eq.TeleportFinishEvent(reg.RegionHandle, 13, endPoint,
858 4, teleportFlags, capsPath, avatar.UUID);
859 }
860 else
861 {
862 avatar.ControllingClient.SendRegionTeleport(reg.RegionHandle, 13, endPoint, 4,
863 teleportFlags, capsPath);
864 }
865
866 // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
867 // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
868 // that the client contacted the destination before we send the attachments and close things here.
869 if (!WaitForCallback(avatar.UUID))
870 {
871 // Client never contacted destination. Let's restore everything back
872 avatar.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
873
874 ResetFromTransit(avatar.UUID);
875
876 // Yikes! We should just have a ref to scene here.
877 avatar.Scene.InformClientOfNeighbours(avatar);
878
879 // Finally, kill the agent we just created at the destination.
880 m_interregionCommsOut.SendCloseAgent(reg.RegionHandle, avatar.UUID);
881
882 return;
883 }
884
885 // Can't go back from here
886 if (KiPrimitive != null)
887 {
888 KiPrimitive(avatar.LocalId);
889 }
890
891 avatar.MakeChildAgent();
892
893 // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
894 avatar.CrossAttachmentsIntoNewRegion(reg.RegionHandle, true);
895
896 // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
897
898 if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY))
899 {
900 Thread.Sleep(5000);
901 avatar.Close();
902 CloseConnection(avatar.UUID);
903 }
904
905 // if (teleport success) // seems to be always success here
906 // the user may change their profile information in other region,
907 // so the userinfo in UserProfileCache is not reliable any more, delete it
908 if (avatar.Scene.NeedSceneCacheClear(avatar.UUID))
909 {
910 m_commsProvider.UserProfileCacheService.RemoveUser(avatar.UUID);
911 m_log.DebugFormat(
912 "[SCENE COMMUNICATION SERVICE]: User {0} is going to another region, profile cache removed",
913 avatar.UUID);
914 }
915 }
916 else
917 {
918 avatar.ControllingClient.SendTeleportFailed("Remote Region appears to be down");
919 }
920 }
921 else
922 {
923 // TP to a place that doesn't exist (anymore)
924 // Inform the viewer about that
925 avatar.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore");
926
927 // and set the map-tile to '(Offline)'
928 uint regX, regY;
929 Utils.LongToUInts(regionHandle, out regX, out regY);
930
931 MapBlockData block = new MapBlockData();
932 block.X = (ushort)(regX / Constants.RegionSize);
933 block.Y = (ushort)(regY / Constants.RegionSize);
934 block.Access = 254; // == not there
935
936 List<MapBlockData> blocks = new List<MapBlockData>();
937 blocks.Add(block);
938 avatar.ControllingClient.SendMapBlock(blocks, 0);
939 }
940 }
941 }
942
943 protected bool WaitForCallback(UUID id)
944 {
945 int count = 20;
946 while (m_agentsInTransit.Contains(id) && count-- > 0)
947 {
948 //Console.WriteLine(" >>> Waiting... " + count);
949 Thread.Sleep(1000);
950 }
951
952 if (count > 0)
953 return true;
954 else
955 return false;
956 }
957
958 public bool ReleaseAgent(UUID id)
959 {
960 //Console.WriteLine(" >>> ReleaseAgent called <<< ");
961 return ResetFromTransit(id);
962 }
963
964 protected void SetInTransit(UUID id)
965 {
966 lock (m_agentsInTransit)
967 {
968 if (!m_agentsInTransit.Contains(id))
969 m_agentsInTransit.Add(id);
970 }
971 }
972
973 protected bool ResetFromTransit(UUID id)
974 {
975 lock (m_agentsInTransit)
976 {
977 if (m_agentsInTransit.Contains(id))
978 {
979 m_agentsInTransit.Remove(id);
980 return true;
981 }
982 }
983 return false;
984 }
985
986 private List<ulong> NeighbourHandles(List<SimpleRegionInfo> neighbours)
987 {
988 List<ulong> handles = new List<ulong>();
989 foreach (SimpleRegionInfo reg in neighbours)
990 {
991 handles.Add(reg.RegionHandle);
992 }
993 return handles;
994 }
995
996 private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
997 {
998 return currentNeighbours.FindAll(delegate(ulong handle) { return !previousNeighbours.Contains(handle); });
999 }
1000
1001// private List<ulong> CommonNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
1002// {
1003// return currentNeighbours.FindAll(delegate(ulong handle) { return previousNeighbours.Contains(handle); });
1004// }
1005
1006 private List<ulong> OldNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
1007 {
1008 return previousNeighbours.FindAll(delegate(ulong handle) { return !currentNeighbours.Contains(handle); });
1009 }
1010 /// <summary>
1011 /// Inform a neighbouring region that an avatar is about to cross into it.
1012 /// </summary>
1013 /// <param name="regionhandle"></param>
1014 /// <param name="agentID"></param>
1015 /// <param name="position"></param>
1016 public bool CrossToNeighbouringRegion(ulong regionhandle, UUID agentID, Vector3 position, bool isFlying)
1017 {
1018 return m_commsProvider.InterRegion.ExpectAvatarCrossing(regionhandle, agentID, position, isFlying);
1019 }
1020
1021 public bool PrimCrossToNeighboringRegion(ulong regionhandle, UUID primID, string objData, int XMLMethod)
1022 {
1023 return m_commsProvider.InterRegion.InformRegionOfPrimCrossing(regionhandle, primID, objData, XMLMethod);
1024 }
1025
1026 public Dictionary<string, string> GetGridSettings()
1027 {
1028 return m_commsProvider.GridService.GetGridSettings();
1029 }
1030
1031 public void LogOffUser(UUID userid, UUID regionid, ulong regionhandle, Vector3 position, Vector3 lookat)
1032 {
1033 m_commsProvider.LogOffUser(userid, regionid, regionhandle, position, lookat);
1034 }
1035
1036 // deprecated as of 2008-08-27
1037 public void LogOffUser(UUID userid, UUID regionid, ulong regionhandle, float posx, float posy, float posz)
1038 {
1039 m_commsProvider.LogOffUser(userid, regionid, regionhandle, posx, posy, posz);
1040 }
1041
1042 public void ClearUserAgent(UUID avatarID)
1043 {
1044 m_commsProvider.UserService.ClearUserAgent(avatarID);
1045 }
1046
1047 public void AddNewUserFriend(UUID friendlistowner, UUID friend, uint perms)
1048 {
1049 m_commsProvider.AddNewUserFriend(friendlistowner, friend, perms);
1050 }
1051
1052 public void UpdateUserFriendPerms(UUID friendlistowner, UUID friend, uint perms)
1053 {
1054 m_commsProvider.UpdateUserFriendPerms(friendlistowner, friend, perms);
1055 }
1056
1057 public void RemoveUserFriend(UUID friendlistowner, UUID friend)
1058 {
1059 m_commsProvider.RemoveUserFriend(friendlistowner, friend);
1060 }
1061
1062 public List<FriendListItem> GetUserFriendList(UUID friendlistowner)
1063 {
1064 return m_commsProvider.GetUserFriendList(friendlistowner);
1065 }
1066
1067 public List<MapBlockData> RequestNeighbourMapBlocks(int minX, int minY, int maxX, int maxY)
1068 {
1069 return m_commsProvider.GridService.RequestNeighbourMapBlocks(minX, minY, maxX, maxY);
1070 }
1071
1072 public List<AvatarPickerAvatar> GenerateAgentPickerRequestResponse(UUID queryID, string query)
1073 {
1074 return m_commsProvider.GenerateAgentPickerRequestResponse(queryID, query);
1075 }
1076
1077 public List<RegionInfo> RequestNamedRegions(string name, int maxNumber)
1078 {
1079 return m_commsProvider.GridService.RequestNamedRegions(name, maxNumber);
1080 }
1081
1082// private void Dump(string msg, List<ulong> handles)
1083// {
1084// Console.WriteLine("-------------- HANDLE DUMP ({0}) ---------", msg);
1085// foreach (ulong handle in handles)
1086// {
1087// uint x, y;
1088// Utils.LongToUInts(handle, out x, out y);
1089// x = x / Constants.RegionSize;
1090// y = y / Constants.RegionSize;
1091// Console.WriteLine("({0}, {1})", x, y);
1092// }
1093// }
1094 }
1095}
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
new file mode 100644
index 0000000..2877dcd
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -0,0 +1,1814 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using OpenMetaverse.Packets;
33using log4net;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Scenes.Types;
36using OpenSim.Region.Physics.Manager;
37
38namespace OpenSim.Region.Framework.Scenes
39{
40 public delegate void PhysicsCrash();
41
42 public delegate void ObjectDuplicateDelegate(EntityBase original, EntityBase clone);
43
44 public delegate void ObjectCreateDelegate(EntityBase obj);
45
46 public delegate void ObjectDeleteDelegate(EntityBase obj);
47
48 /// <summary>
49 /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components
50 /// should be migrated out over time.
51 /// </summary>
52 public class SceneGraph
53 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55
56 #region Events
57
58 protected internal event PhysicsCrash UnRecoverableError;
59 private PhysicsCrash handlerPhysicsCrash = null;
60
61 public event ObjectDuplicateDelegate OnObjectDuplicate;
62 public event ObjectCreateDelegate OnObjectCreate;
63 public event ObjectDeleteDelegate OnObjectRemove;
64
65 #endregion
66
67 #region Fields
68
69 protected internal Dictionary<UUID, ScenePresence> ScenePresences = new Dictionary<UUID, ScenePresence>();
70 // SceneObjects is not currently populated or used.
71 //public Dictionary<UUID, SceneObjectGroup> SceneObjects;
72 protected internal EntityManager Entities = new EntityManager();
73// protected internal Dictionary<UUID, EntityBase> Entities = new Dictionary<UUID, EntityBase>();
74 protected internal Dictionary<UUID, ScenePresence> RestorePresences = new Dictionary<UUID, ScenePresence>();
75
76 protected internal BasicQuadTreeNode QuadTree;
77
78 protected RegionInfo m_regInfo;
79 protected Scene m_parentScene;
80 protected List<EntityBase> m_updateList = new List<EntityBase>();
81 protected int m_numRootAgents = 0;
82 protected int m_numPrim = 0;
83 protected int m_numChildAgents = 0;
84 protected int m_physicalPrim = 0;
85
86 protected int m_activeScripts = 0;
87 protected int m_scriptLPS = 0;
88
89 protected internal object m_syncRoot = new object();
90
91 protected internal PhysicsScene _PhyScene;
92
93 #endregion
94
95 protected internal SceneGraph(Scene parent, RegionInfo regInfo)
96 {
97 m_parentScene = parent;
98 m_regInfo = regInfo;
99 QuadTree = new BasicQuadTreeNode(null, "/0/", 0, 0, (short)Constants.RegionSize, (short)Constants.RegionSize);
100 QuadTree.Subdivide();
101 QuadTree.Subdivide();
102 }
103
104 public PhysicsScene PhysicsScene
105 {
106 get { return _PhyScene; }
107 set
108 {
109 // If we're not doing the initial set
110 // Then we've got to remove the previous
111 // event handler
112
113 if (_PhyScene != null)
114 _PhyScene.OnPhysicsCrash -= physicsBasedCrash;
115
116 _PhyScene = value;
117
118 if (_PhyScene != null)
119 _PhyScene.OnPhysicsCrash += physicsBasedCrash;
120 }
121 }
122
123 protected internal void Close()
124 {
125 lock (ScenePresences)
126 {
127 ScenePresences.Clear();
128 }
129
130 Entities.Clear();
131 }
132
133 #region Update Methods
134
135 protected internal void UpdatePreparePhysics()
136 {
137 // If we are using a threaded physics engine
138 // grab the latest scene from the engine before
139 // trying to process it.
140
141 // PhysX does this (runs in the background).
142
143 if (_PhyScene.IsThreaded)
144 {
145 _PhyScene.GetResults();
146 }
147 }
148
149 protected internal void UpdateEntities()
150 {
151 List<EntityBase> updateEntities = GetEntities();
152
153 foreach (EntityBase entity in updateEntities)
154 {
155 entity.Update();
156 }
157 }
158
159 protected internal void UpdatePresences()
160 {
161 List<ScenePresence> updateScenePresences = GetScenePresences();
162 foreach (ScenePresence pres in updateScenePresences)
163 {
164 pres.Update();
165 }
166 }
167
168 protected internal float UpdatePhysics(double elapsed)
169 {
170 lock (m_syncRoot)
171 {
172 // Here is where the Scene calls the PhysicsScene. This is a one-way
173 // interaction; the PhysicsScene cannot access the calling Scene directly.
174 // But with joints, we want a PhysicsActor to be able to influence a
175 // non-physics SceneObjectPart. In particular, a PhysicsActor that is connected
176 // with a joint should be able to move the SceneObjectPart which is the visual
177 // representation of that joint (for editing and serialization purposes).
178 // However the PhysicsActor normally cannot directly influence anything outside
179 // of the PhysicsScene, and the non-physical SceneObjectPart which represents
180 // the joint in the Scene does not exist in the PhysicsScene.
181 //
182 // To solve this, we have an event in the PhysicsScene that is fired when a joint
183 // has changed position (because one of its associated PhysicsActors has changed
184 // position).
185 //
186 // Therefore, JointMoved and JointDeactivated events will be fired as a result of the following Simulate().
187
188 return _PhyScene.Simulate((float)elapsed);
189 }
190 }
191
192 protected internal void UpdateEntityMovement()
193 {
194 List<EntityBase> moveEntities = GetEntities();
195
196 foreach (EntityBase entity in moveEntities)
197 {
198 //cfk. This throws occaisional exceptions on a heavily used region
199 //and I added this null check to try to preclude the exception.
200 if (entity != null)
201 entity.UpdateMovement();
202 }
203 }
204
205 #endregion
206
207 #region Entity Methods
208
209 /// <summary>
210 /// Add an object into the scene that has come from storage
211 /// </summary>
212 /// <param name="sceneObject"></param>
213 /// <param name="attachToBackup">
214 /// If true, changes to the object will be reflected in its persisted data
215 /// If false, the persisted data will not be changed even if the object in the scene is changed
216 /// </param>
217 /// <param name="alreadyPersisted">
218 /// If true, we won't persist this object until it changes
219 /// If false, we'll persist this object immediately
220 /// </param>
221 /// <returns>
222 /// true if the object was added, false if an object with the same uuid was already in the scene
223 /// </returns>
224 protected internal bool AddRestoredSceneObject(
225 SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted)
226 {
227 if (!alreadyPersisted)
228 {
229 sceneObject.ForceInventoryPersistence();
230 sceneObject.HasGroupChanged = true;
231 }
232
233 return AddSceneObject(sceneObject, attachToBackup);
234 }
235
236 /// <summary>
237 /// Add a newly created object to the scene. This will both update the scene, and send information about the
238 /// new object to all clients interested in the scene.
239 /// </summary>
240 /// <param name="sceneObject"></param>
241 /// <param name="attachToBackup">
242 /// If true, the object is made persistent into the scene.
243 /// If false, the object will not persist over server restarts
244 /// </param>
245 /// <returns>
246 /// true if the object was added, false if an object with the same uuid was already in the scene
247 /// </returns>
248 protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup)
249 {
250 // Ensure that we persist this new scene object
251 sceneObject.HasGroupChanged = true;
252
253 return AddSceneObject(sceneObject, attachToBackup);
254 }
255
256 /// <summary>
257 /// Add an object to the scene. This will both update the scene, and send information about the
258 /// new object to all clients interested in the scene.
259 /// </summary>
260 /// <param name="sceneObject"></param>
261 /// <param name="attachToBackup">
262 /// If true, the object is made persistent into the scene.
263 /// If false, the object will not persist over server restarts
264 /// </param>
265 /// <returns>true if the object was added, false if an object with the same uuid was already in the scene
266 /// </returns>
267 protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup)
268 {
269 if (sceneObject == null || sceneObject.RootPart == null || sceneObject.RootPart.UUID == UUID.Zero)
270 return false;
271
272 if (m_parentScene.m_clampPrimSize)
273 {
274 foreach (SceneObjectPart part in sceneObject.Children.Values)
275 {
276 Vector3 scale = part.Shape.Scale;
277
278 if (scale.X > m_parentScene.m_maxNonphys)
279 scale.X = m_parentScene.m_maxNonphys;
280 if (scale.Y > m_parentScene.m_maxNonphys)
281 scale.Y = m_parentScene.m_maxNonphys;
282 if (scale.Z > m_parentScene.m_maxNonphys)
283 scale.Z = m_parentScene.m_maxNonphys;
284
285 part.Shape.Scale = scale;
286 }
287 }
288
289 sceneObject.AttachToScene(m_parentScene);
290
291 lock (sceneObject)
292 {
293 if (!Entities.ContainsKey(sceneObject.UUID))
294 {
295 Entities.Add(sceneObject);
296 m_numPrim += sceneObject.Children.Count;
297
298 if (attachToBackup)
299 sceneObject.AttachToBackup();
300
301 if (OnObjectCreate != null)
302 OnObjectCreate(sceneObject);
303
304 return true;
305 }
306 }
307
308 return false;
309 }
310
311 /// <summary>
312 /// Delete an object from the scene
313 /// </summary>
314 /// <returns>true if the object was deleted, false if there was no object to delete</returns>
315 public bool DeleteSceneObject(UUID uuid, bool resultOfObjectLinked)
316 {
317 if (Entities.ContainsKey(uuid))
318 {
319 if (!resultOfObjectLinked)
320 {
321 m_numPrim -= ((SceneObjectGroup) Entities[uuid]).Children.Count;
322
323 if ((((SceneObjectGroup)Entities[uuid]).RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics)
324 {
325 RemovePhysicalPrim(((SceneObjectGroup)Entities[uuid]).Children.Count);
326 }
327 }
328
329 if (OnObjectRemove != null)
330 OnObjectRemove(Entities[uuid]);
331
332 Entities.Remove(uuid);
333 //SceneObjectGroup part;
334 //((part.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics)
335
336 return true;
337 }
338
339 return false;
340 }
341
342 /// <summary>
343 /// Add an entity to the list of prims to process on the next update
344 /// </summary>
345 /// <param name="obj">
346 /// A <see cref="EntityBase"/>
347 /// </param>
348 protected internal void AddToUpdateList(EntityBase obj)
349 {
350 lock (m_updateList)
351 {
352 if (!m_updateList.Contains(obj))
353 {
354 m_updateList.Add(obj);
355 }
356 }
357 }
358
359 /// <summary>
360 /// Process all pending updates
361 /// </summary>
362 protected internal void ProcessUpdates()
363 {
364 lock (m_updateList)
365 {
366 for (int i = 0; i < m_updateList.Count; i++)
367 {
368 EntityBase entity = m_updateList[i];
369
370 // Don't abort the whole update if one entity happens to give us an exception.
371 try
372 {
373 m_updateList[i].Update();
374 }
375 catch (Exception e)
376 {
377 m_log.ErrorFormat(
378 "[INNER SCENE]: Failed to update {0}, {1} - {2}", entity.Name, entity.UUID, e);
379 }
380 }
381
382 m_updateList.Clear();
383 }
384 }
385
386 protected internal void AddPhysicalPrim(int number)
387 {
388 m_physicalPrim++;
389 }
390
391 protected internal void RemovePhysicalPrim(int number)
392 {
393 m_physicalPrim--;
394 }
395
396 protected internal void AddToScriptLPS(int number)
397 {
398 m_scriptLPS += number;
399 }
400
401 protected internal void AddActiveScripts(int number)
402 {
403 m_activeScripts += number;
404 }
405
406 protected internal void DropObject(uint objectLocalID, IClientAPI remoteClient)
407 {
408 List<EntityBase> EntityList = GetEntities();
409
410 foreach (EntityBase obj in EntityList)
411 {
412 if (obj is SceneObjectGroup)
413 {
414 if (((SceneObjectGroup)obj).LocalId == objectLocalID)
415 {
416 SceneObjectGroup group = (SceneObjectGroup)obj;
417
418 m_parentScene.DetachSingleAttachmentToGround(group.UUID,remoteClient);
419 }
420 }
421 }
422 }
423
424 protected internal void DetachObject(uint objectLocalID, IClientAPI remoteClient)
425 {
426 List<EntityBase> EntityList = GetEntities();
427
428 foreach (EntityBase obj in EntityList)
429 {
430 if (obj is SceneObjectGroup)
431 {
432 if (((SceneObjectGroup)obj).LocalId == objectLocalID)
433 {
434 SceneObjectGroup group = (SceneObjectGroup)obj;
435
436 //group.DetachToGround();
437 m_parentScene.DetachSingleAttachmentToInv(group.GetFromAssetID(),remoteClient);
438 }
439 }
440 }
441 }
442
443 protected internal void HandleUndo(IClientAPI remoteClient, UUID primId)
444 {
445 if (primId != UUID.Zero)
446 {
447 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primId);
448 if (part != null)
449 part.Undo();
450 }
451 }
452
453 protected internal void HandleObjectGroupUpdate(
454 IClientAPI remoteClient, UUID GroupID, uint objectLocalID, UUID Garbage)
455 {
456 List<EntityBase> EntityList = GetEntities();
457
458 foreach (EntityBase obj in EntityList)
459 {
460 if (obj is SceneObjectGroup)
461 {
462 if (((SceneObjectGroup)obj).LocalId == objectLocalID)
463 {
464 SceneObjectGroup group = (SceneObjectGroup)obj;
465
466 if (group.OwnerID == remoteClient.AgentId)
467 group.SetGroup(GroupID, remoteClient);
468 }
469 }
470 }
471 }
472
473 /// <summary>
474 /// Event Handling routine for Attach Object
475 /// </summary>
476 /// <param name="remoteClient"></param>
477 /// <param name="objectLocalID"></param>
478 /// <param name="AttachmentPt"></param>
479 /// <param name="rot"></param>
480 protected internal void AttachObject(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, bool silent)
481 {
482 // If we can't take it, we can't attach it!
483 //
484 SceneObjectPart part = m_parentScene.GetSceneObjectPart(objectLocalID);
485 if (part == null)
486 return;
487
488 if (!m_parentScene.Permissions.CanTakeObject(
489 part.UUID, remoteClient.AgentId))
490 return;
491
492 // Calls attach with a Zero position
493 //
494 AttachObject(remoteClient, objectLocalID, AttachmentPt, rot, Vector3.Zero, false);
495 }
496
497 public SceneObjectGroup RezSingleAttachment(
498 IClientAPI remoteClient, UUID itemID, uint AttachmentPt)
499 {
500 SceneObjectGroup objatt = m_parentScene.RezObject(remoteClient,
501 itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
502 false, false, remoteClient.AgentId, true);
503
504
505 if (objatt != null)
506 {
507 bool tainted = false;
508 if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint())
509 tainted = true;
510
511 AttachObject(remoteClient, objatt.LocalId, AttachmentPt, Quaternion.Identity, objatt.AbsolutePosition, false);
512 objatt.ScheduleGroupForFullUpdate();
513 if (tainted)
514 objatt.HasGroupChanged = true;
515
516 // Fire after attach, so we don't get messy perms dialogs
517 //
518 objatt.CreateScriptInstances(0, true, m_parentScene.DefaultScriptEngine, 0);
519 }
520 return objatt;
521 }
522
523 // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards.
524 // To LocalId or UUID, *THAT* is the question. How now Brown UUID??
525 public void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient)
526 {
527 if (itemID == UUID.Zero) // If this happened, someone made a mistake....
528 return;
529
530 List<EntityBase> EntityList = GetEntities();
531
532 foreach (EntityBase obj in EntityList)
533 {
534 if (obj is SceneObjectGroup)
535 {
536 if (((SceneObjectGroup)obj).GetFromAssetID() == itemID)
537 {
538 SceneObjectGroup group = (SceneObjectGroup)obj;
539 group.DetachToInventoryPrep();
540 m_log.Debug("[DETACH]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString());
541 m_parentScene.updateKnownAsset(remoteClient, group, group.GetFromAssetID(), group.OwnerID);
542 m_parentScene.DeleteSceneObject(group, false);
543 }
544 }
545 }
546 }
547
548 protected internal void AttachObject(
549 IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, Quaternion rot, Vector3 attachPos, bool silent)
550 {
551 List<EntityBase> EntityList = GetEntities();
552 foreach (EntityBase obj in EntityList)
553 {
554 if (obj is SceneObjectGroup)
555 {
556 if (((SceneObjectGroup)obj).LocalId == objectLocalID)
557 {
558 SceneObjectGroup group = (SceneObjectGroup)obj;
559 if (m_parentScene.Permissions.CanTakeObject(obj.UUID, remoteClient.AgentId))
560 {
561 // If the attachment point isn't the same as the one previously used
562 // set it's offset position = 0 so that it appears on the attachment point
563 // and not in a weird location somewhere unknown.
564 if (AttachmentPt != 0 && AttachmentPt != (uint)group.GetAttachmentPoint())
565 {
566
567 attachPos = Vector3.Zero;
568 }
569
570 // AttachmentPt 0 means the client chose to 'wear' the attachment.
571 if (AttachmentPt == 0)
572 {
573
574 // Check object for stored attachment point
575 AttachmentPt = (uint)group.GetAttachmentPoint();
576
577
578 }
579
580 // if we still didn't find a suitable attachment point.......
581 if (AttachmentPt == 0)
582 {
583 // Stick it on left hand with Zero Offset from the attachment point.
584 AttachmentPt = (uint)AttachmentPoint.LeftHand;
585 attachPos = Vector3.Zero;
586 }
587
588 group.SetAttachmentPoint(Convert.ToByte(AttachmentPt));
589 group.AbsolutePosition = attachPos;
590
591 // Saves and gets assetID
592 UUID itemId;
593 if (group.GetFromAssetID() == UUID.Zero)
594 {
595 m_parentScene.attachObjectAssetStore(remoteClient, group, remoteClient.AgentId, out itemId);
596 }
597 else
598 {
599 itemId = group.GetFromAssetID();
600 }
601
602 m_parentScene.AttachObject(remoteClient, AttachmentPt, itemId, group);
603
604 group.AttachToAgent(remoteClient.AgentId, AttachmentPt, attachPos, silent);
605 // In case it is later dropped again, don't let
606 // it get cleaned up
607 //
608 group.RootPart.RemFlag(PrimFlags.TemporaryOnRez);
609 group.HasGroupChanged = false;
610 }
611 else
612 {
613 remoteClient.SendAgentAlertMessage("You don't have sufficient permissions to attach this object", false);
614 }
615
616 }
617 }
618 }
619 }
620
621 protected internal ScenePresence CreateAndAddChildScenePresence(IClientAPI client, AvatarAppearance appearance)
622 {
623 ScenePresence newAvatar = null;
624
625 newAvatar = new ScenePresence(client, m_parentScene, m_regInfo, appearance);
626 newAvatar.IsChildAgent = true;
627
628 AddScenePresence(newAvatar);
629
630 return newAvatar;
631 }
632
633 /// <summary>
634 /// Add a presence to the scene
635 /// </summary>
636 /// <param name="presence"></param>
637 protected internal void AddScenePresence(ScenePresence presence)
638 {
639 bool child = presence.IsChildAgent;
640
641 if (child)
642 {
643 m_numChildAgents++;
644 }
645 else
646 {
647 m_numRootAgents++;
648 presence.AddToPhysicalScene();
649 }
650
651 Entities[presence.UUID] = presence;
652
653 lock (ScenePresences)
654 {
655 ScenePresences[presence.UUID] = presence;
656 }
657 }
658
659 /// <summary>
660 /// Remove a presence from the scene
661 /// </summary>
662 protected internal void RemoveScenePresence(UUID agentID)
663 {
664 if (!Entities.Remove(agentID))
665 {
666 m_log.WarnFormat(
667 "[SCENE] Tried to remove non-existent scene presence with agent ID {0} from scene Entities list",
668 agentID);
669 }
670
671 lock (ScenePresences)
672 {
673 if (!ScenePresences.Remove(agentID))
674 {
675 m_log.WarnFormat("[SCENE] Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID);
676 }
677// else
678// {
679// m_log.InfoFormat("[SCENE] Removed scene presence {0} from scene presences list", agentID);
680// }
681 }
682 }
683
684 protected internal void SwapRootChildAgent(bool direction_RC_CR_T_F)
685 {
686 if (direction_RC_CR_T_F)
687 {
688 m_numRootAgents--;
689 m_numChildAgents++;
690 }
691 else
692 {
693 m_numChildAgents--;
694 m_numRootAgents++;
695 }
696 }
697
698 protected internal void removeUserCount(bool TypeRCTF)
699 {
700 if (TypeRCTF)
701 {
702 m_numRootAgents--;
703 }
704 else
705 {
706 m_numChildAgents--;
707 }
708 }
709
710 public void RecalculateStats()
711 {
712 List<ScenePresence> SPList = GetScenePresences();
713 int rootcount = 0;
714 int childcount = 0;
715
716 foreach (ScenePresence user in SPList)
717 {
718 if (user.IsChildAgent)
719 childcount++;
720 else
721 rootcount++;
722 }
723 m_numRootAgents = rootcount;
724 m_numChildAgents = childcount;
725
726 }
727
728 public int GetChildAgentCount()
729 {
730 // some network situations come in where child agents get closed twice.
731 if (m_numChildAgents < 0)
732 {
733 m_numChildAgents = 0;
734 }
735
736 return m_numChildAgents;
737 }
738
739 public int GetRootAgentCount()
740 {
741 return m_numRootAgents;
742 }
743
744 public int GetTotalObjectsCount()
745 {
746 return m_numPrim;
747 }
748
749 public int GetActiveObjectsCount()
750 {
751 return m_physicalPrim;
752 }
753
754 public int GetActiveScriptsCount()
755 {
756 return m_activeScripts;
757 }
758
759 public int GetScriptLPS()
760 {
761 int returnval = m_scriptLPS;
762 m_scriptLPS = 0;
763 return returnval;
764 }
765
766 #endregion
767
768 #region Get Methods
769
770 /// <summary>
771 /// Request a List of all scene presences in this scene. This is a new list, so no
772 /// locking is required to iterate over it.
773 /// </summary>
774 /// <returns></returns>
775 protected internal List<ScenePresence> GetScenePresences()
776 {
777 lock (ScenePresences)
778 {
779 return new List<ScenePresence>(ScenePresences.Values);
780 }
781 }
782
783 protected internal List<ScenePresence> GetAvatars()
784 {
785 List<ScenePresence> result =
786 GetScenePresences(delegate(ScenePresence scenePresence) { return !scenePresence.IsChildAgent; });
787
788 return result;
789 }
790
791 /// <summary>
792 /// Get the controlling client for the given avatar, if there is one.
793 ///
794 /// FIXME: The only user of the method right now is Caps.cs, in order to resolve a client API since it can't
795 /// use the ScenePresence. This could be better solved in a number of ways - we could establish an
796 /// OpenSim.Framework.IScenePresence, or move the caps code into a region package (which might be the more
797 /// suitable solution).
798 /// </summary>
799 /// <param name="agentId"></param>
800 /// <returns>null if either the avatar wasn't in the scene, or
801 /// they do not have a controlling client</returns>
802 /// <remarks>this used to be protected internal, but that
803 /// prevents CapabilitiesModule from accessing it</remarks>
804 public IClientAPI GetControllingClient(UUID agentId)
805 {
806 ScenePresence presence = GetScenePresence(agentId);
807
808 if (presence != null)
809 {
810 return presence.ControllingClient;
811 }
812
813 return null;
814 }
815
816 /// <summary>
817 /// Request a filtered list of m_scenePresences in this World
818 /// </summary>
819 /// <returns></returns>
820 protected internal List<ScenePresence> GetScenePresences(FilterAvatarList filter)
821 {
822 // No locking of scene presences here since we're passing back a list...
823
824 List<ScenePresence> result = new List<ScenePresence>();
825 List<ScenePresence> ScenePresencesList = GetScenePresences();
826
827 foreach (ScenePresence avatar in ScenePresencesList)
828 {
829 if (filter(avatar))
830 {
831 result.Add(avatar);
832 }
833 }
834
835 return result;
836 }
837
838 /// <summary>
839 /// Request a scene presence by UUID
840 /// </summary>
841 /// <param name="avatarID"></param>
842 /// <returns>null if the agent was not found</returns>
843 protected internal ScenePresence GetScenePresence(UUID agentID)
844 {
845 ScenePresence sp;
846
847 lock (ScenePresences)
848 {
849 ScenePresences.TryGetValue(agentID, out sp);
850 }
851
852 return sp;
853 }
854
855 /// <summary>
856 /// Get a scene object group that contains the prim with the given local id
857 /// </summary>
858 /// <param name="localID"></param>
859 /// <returns>null if no scene object group containing that prim is found</returns>
860 private SceneObjectGroup GetGroupByPrim(uint localID)
861 {
862 //m_log.DebugFormat("Entered GetGroupByPrim with localID {0}", localID);
863 List<EntityBase> EntityList = GetEntities();
864 foreach (EntityBase ent in EntityList)
865 {
866 //m_log.DebugFormat("Looking at entity {0}", ent.UUID);
867 if (ent is SceneObjectGroup)
868 {
869 if (((SceneObjectGroup)ent).HasChildPrim(localID))
870 return (SceneObjectGroup)ent;
871 }
872 }
873 return null;
874 }
875
876 /// <summary>
877 /// Get a scene object group that contains the prim with the given uuid
878 /// </summary>
879 /// <param name="fullID"></param>
880 /// <returns>null if no scene object group containing that prim is found</returns>
881 private SceneObjectGroup GetGroupByPrim(UUID fullID)
882 {
883 List<EntityBase> EntityList = GetEntities();
884
885 foreach (EntityBase ent in EntityList)
886 {
887 if (ent is SceneObjectGroup)
888 {
889 if (((SceneObjectGroup)ent).HasChildPrim(fullID))
890 return (SceneObjectGroup)ent;
891 }
892 }
893 return null;
894 }
895
896 protected internal EntityIntersection GetClosestIntersectingPrim(Ray hray, bool frontFacesOnly, bool faceCenters)
897 {
898 // Primitive Ray Tracing
899 float closestDistance = 280f;
900 EntityIntersection returnResult = new EntityIntersection();
901 List<EntityBase> EntityList = GetEntities();
902 foreach (EntityBase ent in EntityList)
903 {
904 if (ent is SceneObjectGroup)
905 {
906 SceneObjectGroup reportingG = (SceneObjectGroup)ent;
907 EntityIntersection result = reportingG.TestIntersection(hray, frontFacesOnly, faceCenters);
908 if (result.HitTF)
909 {
910 if (result.distance < closestDistance)
911 {
912 closestDistance = result.distance;
913 returnResult = result;
914 }
915 }
916 }
917 }
918 return returnResult;
919 }
920
921 /// <summary>
922 /// Get a part contained in this scene.
923 /// </summary>
924 /// <param name="localID"></param>
925 /// <returns>null if the part was not found</returns>
926 protected internal SceneObjectPart GetSceneObjectPart(uint localID)
927 {
928 SceneObjectGroup group = GetGroupByPrim(localID);
929
930 if (group != null)
931 return group.GetChildPart(localID);
932 else
933 return null;
934 }
935
936 /// <summary>
937 /// Get a named prim contained in this scene (will return the first
938 /// found, if there are more than one prim with the same name)
939 /// </summary>
940 /// <param name="name"></param>
941 /// <returns>null if the part was not found</returns>
942 protected internal SceneObjectPart GetSceneObjectPart(string name)
943 {
944 List<EntityBase> EntityList = GetEntities();
945
946 // FIXME: use a dictionary here
947 foreach (EntityBase ent in EntityList)
948 {
949 if (ent is SceneObjectGroup)
950 {
951 foreach (SceneObjectPart p in ((SceneObjectGroup) ent).GetParts())
952 {
953 if (p.Name==name)
954 {
955 return p;
956 }
957 }
958 }
959 }
960 return null;
961 }
962
963 /// <summary>
964 /// Get a part contained in this scene.
965 /// </summary>
966 /// <param name="fullID"></param>
967 /// <returns>null if the part was not found</returns>
968 protected internal SceneObjectPart GetSceneObjectPart(UUID fullID)
969 {
970 SceneObjectGroup group = GetGroupByPrim(fullID);
971
972 if (group != null)
973 return group.GetChildPart(fullID);
974 else
975 return null;
976 }
977
978 protected internal bool TryGetAvatar(UUID avatarId, out ScenePresence avatar)
979 {
980 ScenePresence presence;
981
982 lock (ScenePresences)
983 {
984 if (ScenePresences.TryGetValue(avatarId, out presence))
985 {
986 avatar = presence;
987 return true;
988
989 //if (!presence.IsChildAgent)
990 //{
991 // avatar = presence;
992 // return true;
993 //}
994 //else
995 //{
996 // m_log.WarnFormat(
997 // "[INNER SCENE]: Requested avatar {0} could not be found in scene {1} since it is only registered as a child agent!",
998 // avatarId, m_parentScene.RegionInfo.RegionName);
999 //}
1000 }
1001 }
1002
1003 avatar = null;
1004 return false;
1005 }
1006
1007 protected internal bool TryGetAvatarByName(string avatarName, out ScenePresence avatar)
1008 {
1009 lock (ScenePresences)
1010 {
1011 foreach (ScenePresence presence in ScenePresences.Values)
1012 {
1013 if (!presence.IsChildAgent)
1014 {
1015 string name = presence.ControllingClient.Name;
1016
1017 if (String.Compare(avatarName, name, true) == 0)
1018 {
1019 avatar = presence;
1020 return true;
1021 }
1022 }
1023 }
1024 }
1025
1026 avatar = null;
1027 return false;
1028 }
1029
1030 /// <summary>
1031 /// Returns a list of the entities in the scene. This is a new list so no locking is required to iterate over
1032 /// it
1033 /// </summary>
1034 /// <returns></returns>
1035 protected internal List<EntityBase> GetEntities()
1036 {
1037 return Entities.GetEntities();
1038 }
1039
1040 public Dictionary<uint, float> GetTopScripts()
1041 {
1042 Dictionary<uint, float> topScripts = new Dictionary<uint, float>();
1043
1044 List<EntityBase> EntityList = GetEntities();
1045 int limit = 0;
1046 foreach (EntityBase ent in EntityList)
1047 {
1048 if (ent is SceneObjectGroup)
1049 {
1050 SceneObjectGroup grp = (SceneObjectGroup)ent;
1051 if ((grp.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0)
1052 {
1053 if (grp.scriptScore >= 0.01)
1054 {
1055 topScripts.Add(grp.LocalId, grp.scriptScore);
1056 limit++;
1057 if (limit >= 100)
1058 {
1059 break;
1060 }
1061 }
1062 grp.scriptScore = 0;
1063 }
1064 }
1065 }
1066
1067 return topScripts;
1068 }
1069
1070 #endregion
1071
1072 #region Other Methods
1073
1074 protected internal void physicsBasedCrash()
1075 {
1076 handlerPhysicsCrash = UnRecoverableError;
1077 if (handlerPhysicsCrash != null)
1078 {
1079 handlerPhysicsCrash();
1080 }
1081 }
1082
1083 protected internal UUID ConvertLocalIDToFullID(uint localID)
1084 {
1085 SceneObjectGroup group = GetGroupByPrim(localID);
1086 if (group != null)
1087 return group.GetPartsFullID(localID);
1088 else
1089 return UUID.Zero;
1090 }
1091
1092 protected internal void ForEachClient(Action<IClientAPI> action)
1093 {
1094 List<ScenePresence> splist = GetScenePresences();
1095 foreach (ScenePresence presence in splist)
1096 {
1097 try
1098 {
1099 action(presence.ControllingClient);
1100 }
1101 catch (Exception e)
1102 {
1103 // Catch it and move on. This includes situations where splist has inconsistent info
1104 m_log.WarnFormat("[SCENE]: Problem processing action in ForEachClient: ", e.Message);
1105 }
1106 }
1107 }
1108
1109 #endregion
1110
1111 #region Client Event handlers
1112
1113 /// <summary>
1114 ///
1115 /// </summary>
1116 /// <param name="localID"></param>
1117 /// <param name="scale"></param>
1118 /// <param name="remoteClient"></param>
1119 protected internal void UpdatePrimScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1120 {
1121 SceneObjectGroup group = GetGroupByPrim(localID);
1122 if (group != null)
1123 {
1124 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1125 {
1126 group.Resize(scale, localID);
1127 }
1128 }
1129 }
1130
1131 protected internal void UpdatePrimGroupScale(uint localID, Vector3 scale, IClientAPI remoteClient)
1132 {
1133 SceneObjectGroup group = GetGroupByPrim(localID);
1134 if (group != null)
1135 {
1136 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1137 {
1138 group.GroupResize(scale, localID);
1139 }
1140 }
1141 }
1142
1143 /// <summary>
1144 /// This handles the nifty little tool tip that you get when you drag your mouse over an object
1145 /// Send to the Object Group to process. We don't know enough to service the request
1146 /// </summary>
1147 /// <param name="remoteClient"></param>
1148 /// <param name="AgentID"></param>
1149 /// <param name="RequestFlags"></param>
1150 /// <param name="ObjectID"></param>
1151 protected internal void RequestObjectPropertiesFamily(
1152 IClientAPI remoteClient, UUID AgentID, uint RequestFlags, UUID ObjectID)
1153 {
1154 SceneObjectGroup group = GetGroupByPrim(ObjectID);
1155 if (group != null)
1156 {
1157 group.ServiceObjectPropertiesFamilyRequest(remoteClient, AgentID, RequestFlags);
1158 }
1159 }
1160
1161 /// <summary>
1162 ///
1163 /// </summary>
1164 /// <param name="localID"></param>
1165 /// <param name="rot"></param>
1166 /// <param name="remoteClient"></param>
1167 protected internal void UpdatePrimSingleRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1168 {
1169 SceneObjectGroup group = GetGroupByPrim(localID);
1170 if (group != null)
1171 {
1172 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1173 {
1174 group.UpdateSingleRotation(rot, localID);
1175 }
1176 }
1177 }
1178
1179 /// <summary>
1180 ///
1181 /// </summary>
1182 /// <param name="localID"></param>
1183 /// <param name="rot"></param>
1184 /// <param name="remoteClient"></param>
1185 protected internal void UpdatePrimRotation(uint localID, Quaternion rot, IClientAPI remoteClient)
1186 {
1187 SceneObjectGroup group = GetGroupByPrim(localID);
1188 if (group != null)
1189 {
1190 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1191 {
1192 group.UpdateGroupRotation(rot);
1193 }
1194 }
1195 }
1196
1197 /// <summary>
1198 ///
1199 /// </summary>
1200 /// <param name="localID"></param>
1201 /// <param name="pos"></param>
1202 /// <param name="rot"></param>
1203 /// <param name="remoteClient"></param>
1204 protected internal void UpdatePrimRotation(uint localID, Vector3 pos, Quaternion rot, IClientAPI remoteClient)
1205 {
1206 SceneObjectGroup group = GetGroupByPrim(localID);
1207 if (group != null)
1208 {
1209 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))
1210 {
1211 group.UpdateGroupRotation(pos, rot);
1212 }
1213 }
1214 }
1215
1216 /// <summary>
1217 /// Update the position of the given part
1218 /// </summary>
1219 /// <param name="localID"></param>
1220 /// <param name="pos"></param>
1221 /// <param name="remoteClient"></param>
1222 protected internal void UpdatePrimSinglePosition(uint localID, Vector3 pos, IClientAPI remoteClient)
1223 {
1224 SceneObjectGroup group = GetGroupByPrim(localID);
1225 if (group != null)
1226 {
1227 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId) || group.IsAttachment)
1228 {
1229 group.UpdateSinglePosition(pos, localID);
1230 }
1231 }
1232 }
1233
1234 /// <summary>
1235 /// Update the position of the given part
1236 /// </summary>
1237 /// <param name="localID"></param>
1238 /// <param name="pos"></param>
1239 /// <param name="remoteClient"></param>
1240 protected internal void UpdatePrimPosition(uint localID, Vector3 pos, IClientAPI remoteClient)
1241 {
1242 SceneObjectGroup group = GetGroupByPrim(localID);
1243 if (group != null)
1244 {
1245
1246 // Vector3 oldPos = group.AbsolutePosition;
1247 if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
1248 {
1249 group.UpdateGroupPosition(pos);
1250 }
1251 else
1252 {
1253 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId) && m_parentScene.Permissions.CanObjectEntry(group.UUID, false, pos))
1254 {
1255 group.UpdateGroupPosition(pos);
1256 }
1257 }
1258 }
1259 }
1260
1261 /// <summary>
1262 ///
1263 /// </summary>
1264 /// <param name="localID"></param>
1265 /// <param name="texture"></param>
1266 /// <param name="remoteClient"></param>
1267 protected internal void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient)
1268 {
1269 SceneObjectGroup group = GetGroupByPrim(localID);
1270 if (group != null)
1271 {
1272 if (m_parentScene.Permissions.CanEditObject(group.UUID,remoteClient.AgentId))
1273 {
1274 group.UpdateTextureEntry(localID, texture);
1275 }
1276 }
1277 }
1278
1279 /// <summary>
1280 ///
1281 /// </summary>
1282 /// <param name="localID"></param>
1283 /// <param name="packet"></param>
1284 /// <param name="remoteClient"></param>
1285 /// This routine seems to get called when a user changes object settings in the viewer.
1286 /// If some one can confirm that, please change the comment according.
1287 protected internal void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, IClientAPI remoteClient)
1288 {
1289 SceneObjectGroup group = GetGroupByPrim(localID);
1290 if (group != null)
1291 {
1292 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1293 {
1294 group.UpdatePrimFlags(localID, UsePhysics, IsTemporary, IsPhantom, false); // VolumeDetect can't be set via UI and will always be off when a change is made there
1295 }
1296 }
1297 }
1298
1299 /// <summary>
1300 /// Move the given object
1301 /// </summary>
1302 /// <param name="objectID"></param>
1303 /// <param name="offset"></param>
1304 /// <param name="pos"></param>
1305 /// <param name="remoteClient"></param>
1306 protected internal void MoveObject(UUID objectID, Vector3 offset, Vector3 pos, IClientAPI remoteClient, List<SurfaceTouchEventArgs> surfaceArgs)
1307 {
1308 SceneObjectGroup group = GetGroupByPrim(objectID);
1309 if (group != null)
1310 {
1311 if (m_parentScene.Permissions.CanMoveObject(group.UUID, remoteClient.AgentId))// && PermissionsMngr.)
1312 {
1313 group.GrabMovement(offset, pos, remoteClient);
1314 }
1315 // This is outside the above permissions condition
1316 // so that if the object is locked the client moving the object
1317 // get's it's position on the simulator even if it was the same as before
1318 // This keeps the moving user's client in sync with the rest of the world.
1319 group.SendGroupTerseUpdate();
1320 }
1321 }
1322
1323 /// <summary>
1324 ///
1325 /// </summary>
1326 /// <param name="primLocalID"></param>
1327 /// <param name="description"></param>
1328 protected internal void PrimName(IClientAPI remoteClient, uint primLocalID, string name)
1329 {
1330 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1331 if (group != null)
1332 {
1333 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1334 {
1335 group.SetPartName(Util.CleanString(name), primLocalID);
1336 group.HasGroupChanged = true;
1337 }
1338 }
1339 }
1340
1341 /// <summary>
1342 ///
1343 /// </summary>
1344 /// <param name="primLocalID"></param>
1345 /// <param name="description"></param>
1346 protected internal void PrimDescription(IClientAPI remoteClient, uint primLocalID, string description)
1347 {
1348 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1349 if (group != null)
1350 {
1351 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1352 {
1353 group.SetPartDescription(Util.CleanString(description), primLocalID);
1354 group.HasGroupChanged = true;
1355 }
1356 }
1357 }
1358
1359 protected internal void PrimClickAction(IClientAPI remoteClient, uint primLocalID, string clickAction)
1360 {
1361 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1362 if (group != null)
1363 {
1364 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1365 {
1366 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1367 part.ClickAction = Convert.ToByte(clickAction);
1368 group.HasGroupChanged = true;
1369 }
1370 }
1371 }
1372
1373 protected internal void PrimMaterial(IClientAPI remoteClient, uint primLocalID, string material)
1374 {
1375 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1376 if (group != null)
1377 {
1378 if (m_parentScene.Permissions.CanEditObject(group.UUID, remoteClient.AgentId))
1379 {
1380 SceneObjectPart part = m_parentScene.GetSceneObjectPart(primLocalID);
1381 part.Material = Convert.ToByte(material);
1382 group.HasGroupChanged = true;
1383 }
1384 }
1385 }
1386
1387 protected internal void UpdateExtraParam(UUID agentID, uint primLocalID, ushort type, bool inUse, byte[] data)
1388 {
1389 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1390
1391 if (group != null)
1392 {
1393 if (m_parentScene.Permissions.CanEditObject(group.UUID,agentID))
1394 {
1395 group.UpdateExtraParam(primLocalID, type, inUse, data);
1396 }
1397 }
1398 }
1399
1400 /// <summary>
1401 ///
1402 /// </summary>
1403 /// <param name="primLocalID"></param>
1404 /// <param name="shapeBlock"></param>
1405 protected internal void UpdatePrimShape(UUID agentID, uint primLocalID, UpdateShapeArgs shapeBlock)
1406 {
1407 SceneObjectGroup group = GetGroupByPrim(primLocalID);
1408 if (group != null)
1409 {
1410 if (m_parentScene.Permissions.CanEditObject(group.GetPartsFullID(primLocalID), agentID))
1411 {
1412 ObjectShapePacket.ObjectDataBlock shapeData = new ObjectShapePacket.ObjectDataBlock();
1413 shapeData.ObjectLocalID = shapeBlock.ObjectLocalID;
1414 shapeData.PathBegin = shapeBlock.PathBegin;
1415 shapeData.PathCurve = shapeBlock.PathCurve;
1416 shapeData.PathEnd = shapeBlock.PathEnd;
1417 shapeData.PathRadiusOffset = shapeBlock.PathRadiusOffset;
1418 shapeData.PathRevolutions = shapeBlock.PathRevolutions;
1419 shapeData.PathScaleX = shapeBlock.PathScaleX;
1420 shapeData.PathScaleY = shapeBlock.PathScaleY;
1421 shapeData.PathShearX = shapeBlock.PathShearX;
1422 shapeData.PathShearY = shapeBlock.PathShearY;
1423 shapeData.PathSkew = shapeBlock.PathSkew;
1424 shapeData.PathTaperX = shapeBlock.PathTaperX;
1425 shapeData.PathTaperY = shapeBlock.PathTaperY;
1426 shapeData.PathTwist = shapeBlock.PathTwist;
1427 shapeData.PathTwistBegin = shapeBlock.PathTwistBegin;
1428 shapeData.ProfileBegin = shapeBlock.ProfileBegin;
1429 shapeData.ProfileCurve = shapeBlock.ProfileCurve;
1430 shapeData.ProfileEnd = shapeBlock.ProfileEnd;
1431 shapeData.ProfileHollow = shapeBlock.ProfileHollow;
1432
1433 group.UpdateShape(shapeData, primLocalID);
1434 }
1435 }
1436 }
1437
1438 /// <summary>
1439 /// Initial method invoked when we receive a link objects request from the client.
1440 /// </summary>
1441 /// <param name="client"></param>
1442 /// <param name="parentPrim"></param>
1443 /// <param name="childPrims"></param>
1444 protected internal void LinkObjects(IClientAPI client, uint parentPrim, List<uint> childPrims)
1445 {
1446 List<EntityBase> EntityList = GetEntities();
1447
1448 SceneObjectGroup parenPrim = null;
1449 foreach (EntityBase ent in EntityList)
1450 {
1451 if (ent is SceneObjectGroup)
1452 {
1453 if (((SceneObjectGroup)ent).LocalId == parentPrim)
1454 {
1455 parenPrim = (SceneObjectGroup)ent;
1456 break;
1457 }
1458 }
1459 }
1460
1461 List<SceneObjectGroup> children = new List<SceneObjectGroup>();
1462 if (parenPrim != null)
1463 {
1464 // We do this in reverse to get the link order of the prims correct
1465 for (int i = childPrims.Count - 1; i >= 0; i--)
1466 {
1467 foreach (EntityBase ent in EntityList)
1468 {
1469 if (ent is SceneObjectGroup)
1470 {
1471 if (((SceneObjectGroup)ent).LocalId == childPrims[i])
1472 {
1473 // Make sure no child prim is set for sale
1474 // So that, on delink, no prims are unwittingly
1475 // left for sale and sold off
1476 ((SceneObjectGroup)ent).RootPart.ObjectSaleType = 0;
1477 ((SceneObjectGroup)ent).RootPart.SalePrice = 10;
1478 children.Add((SceneObjectGroup)ent);
1479 }
1480 }
1481 }
1482 }
1483 }
1484 else
1485 {
1486 return; // parent is null so not in this region
1487 }
1488
1489 foreach (SceneObjectGroup sceneObj in children)
1490 {
1491 parenPrim.LinkToGroup(sceneObj);
1492
1493 // this is here so physics gets updated!
1494 // Don't remove! Bad juju! Stay away! or fix physics!
1495 sceneObj.AbsolutePosition = sceneObj.AbsolutePosition;
1496 }
1497
1498 // We need to explicitly resend the newly link prim's object properties since no other actions
1499 // occur on link to invoke this elsewhere (such as object selection)
1500 parenPrim.RootPart.AddFlag(PrimFlags.CreateSelected);
1501 parenPrim.TriggerScriptChangedEvent(Changed.LINK);
1502
1503 if (client != null)
1504 {
1505 parenPrim.GetProperties(client);
1506 }
1507 else
1508 {
1509 foreach (ScenePresence p in GetScenePresences())
1510 {
1511 parenPrim.GetProperties(p.ControllingClient);
1512 }
1513 }
1514 }
1515
1516 /// <summary>
1517 /// Delink a linkset
1518 /// </summary>
1519 /// <param name="prims"></param>
1520 protected internal void DelinkObjects(List<uint> primIds)
1521 {
1522 DelinkObjects(primIds, true);
1523 }
1524
1525 protected internal void DelinkObjects(List<uint> primIds, bool sendEvents)
1526 {
1527 SceneObjectGroup parenPrim = null;
1528
1529 // Need a list of the SceneObjectGroup local ids
1530 // XXX I'm anticipating that building this dictionary once is more efficient than
1531 // repeated scanning of the Entity.Values for a large number of primIds. However, it might
1532 // be more efficient yet to keep this dictionary permanently on hand.
1533
1534 Dictionary<uint, SceneObjectGroup> sceneObjects = new Dictionary<uint, SceneObjectGroup>();
1535
1536 List<EntityBase> EntityList = GetEntities();
1537 foreach (EntityBase ent in EntityList)
1538 {
1539 if (ent is SceneObjectGroup)
1540 {
1541 SceneObjectGroup obj = (SceneObjectGroup)ent;
1542 // Nasty one. Can't unlink anything in the sim
1543 // If a duplicate local ID sneaks in
1544 // So, check it here!
1545 //
1546 if (!sceneObjects.ContainsKey(obj.LocalId))
1547 sceneObjects.Add(obj.LocalId, obj);
1548
1549 }
1550 }
1551
1552 // Find the root prim among the prim ids we've been given
1553 for (int i = 0; i < primIds.Count; i++)
1554 {
1555
1556 if (sceneObjects.ContainsKey(primIds[i]))
1557 {
1558 parenPrim = sceneObjects[primIds[i]];
1559 primIds.RemoveAt(i);
1560 break;
1561 }
1562 }
1563
1564 if (parenPrim != null)
1565 {
1566 foreach (uint childPrimId in primIds)
1567 {
1568 parenPrim.DelinkFromGroup(childPrimId, sendEvents);
1569 }
1570
1571 if (parenPrim.Children.Count == 1)
1572 {
1573 // The link set has been completely torn down
1574 // This is the case if you select a link set and delink
1575 //
1576 parenPrim.RootPart.LinkNum = 0;
1577 if (sendEvents)
1578 parenPrim.TriggerScriptChangedEvent(Changed.LINK);
1579 }
1580 else
1581 {
1582 // The link set has prims remaining. This path is taken
1583 // when a subset of a link set's prims are selected
1584 // and the root prim is part of that selection
1585 //
1586 List<SceneObjectPart> parts = new List<SceneObjectPart>(parenPrim.Children.Values);
1587
1588 List<uint> unlink_ids = new List<uint>();
1589 foreach (SceneObjectPart unlink_part in parts)
1590 unlink_ids.Add(unlink_part.LocalId);
1591
1592 // Tear down the remaining link set
1593 //
1594 if (unlink_ids.Count == 2)
1595 {
1596 DelinkObjects(unlink_ids, true);
1597 return;
1598 }
1599
1600 DelinkObjects(unlink_ids, false);
1601
1602 // Send event to root prim, then we're done with it
1603 parenPrim.TriggerScriptChangedEvent(Changed.LINK);
1604
1605 unlink_ids.Remove(parenPrim.RootPart.LocalId);
1606
1607 foreach (uint localId in unlink_ids)
1608 {
1609 SceneObjectPart nr = GetSceneObjectPart(localId);
1610 nr.UpdateFlag = 0;
1611 }
1612
1613 uint newRoot = unlink_ids[0];
1614 unlink_ids.Remove(newRoot);
1615
1616 LinkObjects(null, newRoot, unlink_ids);
1617 }
1618 }
1619 else
1620 {
1621 // The selected prims were all child prims. Edit linked parts
1622 // without the root prim selected will get us here
1623 //
1624 List<SceneObjectGroup> parents = new List<SceneObjectGroup>();
1625
1626 // If the first scan failed, we need to do a /deep/ scan of the linkages. This is /really/ slow
1627 // We know that this is not the root prim now essentially, so we don't have to worry about remapping
1628 // which one is the root prim
1629 bool delinkedSomething = false;
1630 for (int i = 0; i < primIds.Count; i++)
1631 {
1632 foreach (SceneObjectGroup grp in sceneObjects.Values)
1633 {
1634 SceneObjectPart gPart = grp.GetChildPart(primIds[i]);
1635 if (gPart != null)
1636 {
1637 grp.DelinkFromGroup(primIds[i]);
1638 delinkedSomething = true;
1639 if (!parents.Contains(grp))
1640 parents.Add(grp);
1641 }
1642
1643 }
1644 }
1645 if (!delinkedSomething)
1646 {
1647 m_log.InfoFormat("[SCENE]: " +
1648 "DelinkObjects(): Could not find a root prim out of {0} as given to a delink request!",
1649 primIds);
1650 }
1651 else
1652 {
1653 foreach (SceneObjectGroup g in parents)
1654 {
1655 g.TriggerScriptChangedEvent(Changed.LINK);
1656 }
1657 }
1658 }
1659 }
1660
1661 protected internal void MakeObjectSearchable(IClientAPI remoteClient, bool IncludeInSearch, uint localID)
1662 {
1663 UUID user = remoteClient.AgentId;
1664 UUID objid = UUID.Zero;
1665 SceneObjectPart obj = null;
1666
1667 List<EntityBase> EntityList = GetEntities();
1668 foreach (EntityBase ent in EntityList)
1669 {
1670 if (ent is SceneObjectGroup)
1671 {
1672 foreach (KeyValuePair<UUID, SceneObjectPart> subent in ((SceneObjectGroup)ent).Children)
1673 {
1674 if (subent.Value.LocalId == localID)
1675 {
1676 objid = subent.Key;
1677 obj = subent.Value;
1678 }
1679 }
1680 }
1681 }
1682
1683 //Protip: In my day, we didn't call them searchable objects, we called them limited point-to-point joints
1684 //aka ObjectFlags.JointWheel = IncludeInSearch
1685
1686 //Permissions model: Object can be REMOVED from search IFF:
1687 // * User owns object
1688 //use CanEditObject
1689
1690 //Object can be ADDED to search IFF:
1691 // * User owns object
1692 // * Asset/DRM permission bit "modify" is enabled
1693 //use CanEditObjectPosition
1694
1695 // libomv will complain about PrimFlags.JointWheel being
1696 // deprecated, so we
1697 #pragma warning disable 0612
1698 if (IncludeInSearch && m_parentScene.Permissions.CanEditObject(objid, user))
1699 {
1700 obj.ParentGroup.RootPart.AddFlag(PrimFlags.JointWheel);
1701 obj.ParentGroup.HasGroupChanged = true;
1702 }
1703 else if (!IncludeInSearch && m_parentScene.Permissions.CanMoveObject(objid,user))
1704 {
1705 obj.ParentGroup.RootPart.RemFlag(PrimFlags.JointWheel);
1706 obj.ParentGroup.HasGroupChanged = true;
1707 }
1708 #pragma warning restore 0612
1709 }
1710
1711 /// <summary>
1712 /// Duplicate the given object, Fire and Forget, No rotation, no return wrapper
1713 /// </summary>
1714 /// <param name="originalPrim"></param>
1715 /// <param name="offset"></param>
1716 /// <param name="flags"></param>
1717 protected internal void DuplicateObject(uint originalPrim, Vector3 offset, uint flags, UUID AgentID, UUID GroupID)
1718 {
1719 //m_log.DebugFormat("[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", originalPrim, offset, AgentID);
1720
1721 // SceneObjectGroup dupe = DuplicateObject(originalPrim, offset, flags, AgentID, GroupID, Quaternion.Zero);
1722 DuplicateObject(originalPrim, offset, flags, AgentID, GroupID, Quaternion.Identity);
1723 }
1724
1725 /// <summary>
1726 /// Duplicate the given object.
1727 /// </summary>
1728 /// <param name="originalPrim"></param>
1729 /// <param name="offset"></param>
1730 /// <param name="flags"></param>
1731 protected internal SceneObjectGroup DuplicateObject(uint originalPrim, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot)
1732 {
1733 //m_log.DebugFormat("[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", originalPrim, offset, AgentID);
1734
1735 List<EntityBase> EntityList = GetEntities();
1736
1737 SceneObjectGroup originPrim = null;
1738 foreach (EntityBase ent in EntityList)
1739 {
1740 if (ent is SceneObjectGroup)
1741 {
1742 if (((SceneObjectGroup)ent).LocalId == originalPrim)
1743 {
1744 originPrim = (SceneObjectGroup)ent;
1745 break;
1746 }
1747 }
1748 }
1749
1750 if (originPrim != null)
1751 {
1752 if (m_parentScene.Permissions.CanDuplicateObject(originPrim.Children.Count, originPrim.UUID, AgentID, originPrim.AbsolutePosition))
1753 {
1754 SceneObjectGroup copy = originPrim.Copy(AgentID, GroupID, true);
1755 copy.AbsolutePosition = copy.AbsolutePosition + offset;
1756
1757 Entities.Add(copy);
1758
1759 // Since we copy from a source group that is in selected
1760 // state, but the copy is shown deselected in the viewer,
1761 // We need to clear the selection flag here, else that
1762 // prim never gets persisted at all. The client doesn't
1763 // think it's selected, so it will never send a deselect...
1764 copy.IsSelected = false;
1765
1766 m_numPrim += copy.Children.Count;
1767
1768 if (rot != Quaternion.Identity)
1769 {
1770 copy.UpdateGroupRotation(rot);
1771 }
1772
1773 copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 0);
1774 copy.HasGroupChanged = true;
1775 copy.ScheduleGroupForFullUpdate();
1776
1777 // required for physics to update it's position
1778 copy.AbsolutePosition = copy.AbsolutePosition;
1779
1780 if (OnObjectDuplicate != null)
1781 OnObjectDuplicate(originPrim, copy);
1782
1783 return copy;
1784 }
1785 }
1786 else
1787 {
1788 m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID);
1789 }
1790
1791 return null;
1792 }
1793
1794 /// <summary>
1795 /// Calculates the distance between two Vector3s
1796 /// </summary>
1797 /// <param name="v1"></param>
1798 /// <param name="v2"></param>
1799 /// <returns></returns>
1800 protected internal float Vector3Distance(Vector3 v1, Vector3 v2)
1801 {
1802 // We don't really need the double floating point precision...
1803 // so casting it to a single
1804
1805 return
1806 (float)
1807 Math.Sqrt((v1.X - v2.X) * (v1.X - v2.X) + (v1.Y - v2.Y) * (v1.Y - v2.Y) + (v1.Z - v2.Z) * (v1.Z - v2.Z));
1808 }
1809
1810 #endregion
1811
1812
1813 }
1814}
diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs
new file mode 100644
index 0000000..180f8a1
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs
@@ -0,0 +1,669 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Reflection;
32using OpenMetaverse;
33using log4net;
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36
37namespace OpenSim.Region.Framework.Scenes
38{
39 public delegate void RestartSim(RegionInfo thisregion);
40
41 /// <summary>
42 /// Manager for adding, closing and restarting scenes.
43 /// </summary>
44 public class SceneManager
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 public event RestartSim OnRestartSim;
49
50 private readonly List<Scene> m_localScenes;
51 private Scene m_currentScene = null;
52
53 public List<Scene> Scenes
54 {
55 get { return m_localScenes; }
56 }
57
58 public Scene CurrentScene
59 {
60 get { return m_currentScene; }
61 }
62
63 public Scene CurrentOrFirstScene
64 {
65 get
66 {
67 if (m_currentScene == null)
68 {
69 return m_localScenes[0];
70 }
71 else
72 {
73 return m_currentScene;
74 }
75 }
76 }
77
78 public SceneManager()
79 {
80 m_localScenes = new List<Scene>();
81 }
82
83 public void Close()
84 {
85 // collect known shared modules in sharedModules
86 Dictionary<string, IRegionModule> sharedModules = new Dictionary<string, IRegionModule>();
87 for (int i = 0; i < m_localScenes.Count; i++)
88 {
89 // extract known shared modules from scene
90 foreach (string k in m_localScenes[i].Modules.Keys)
91 {
92 if (m_localScenes[i].Modules[k].IsSharedModule &&
93 !sharedModules.ContainsKey(k))
94 sharedModules[k] = m_localScenes[i].Modules[k];
95 }
96 // close scene/region
97 m_localScenes[i].Close();
98 }
99
100 // all regions/scenes are now closed, we can now safely
101 // close all shared modules
102 foreach (IRegionModule mod in sharedModules.Values)
103 {
104 mod.Close();
105 }
106 }
107
108 public void Close(Scene cscene)
109 {
110 if (m_localScenes.Contains(cscene))
111 {
112 for (int i = 0; i < m_localScenes.Count; i++)
113 {
114 if (m_localScenes[i].Equals(cscene))
115 {
116 m_localScenes[i].Close();
117 }
118 }
119 }
120 }
121
122 public void Add(Scene scene)
123 {
124 scene.OnRestart += HandleRestart;
125 m_localScenes.Add(scene);
126 }
127
128 public void HandleRestart(RegionInfo rdata)
129 {
130 m_log.Error("[SCENEMANAGER]: Got Restart message for region:" + rdata.RegionName + " Sending up to main");
131 int RegionSceneElement = -1;
132 for (int i = 0; i < m_localScenes.Count; i++)
133 {
134 if (rdata.RegionName == m_localScenes[i].RegionInfo.RegionName)
135 {
136 RegionSceneElement = i;
137 }
138 }
139
140 // Now we make sure the region is no longer known about by the SceneManager
141 // Prevents duplicates.
142
143 if (RegionSceneElement >= 0)
144 {
145 m_localScenes.RemoveAt(RegionSceneElement);
146 }
147
148 // Send signal to main that we're restarting this sim.
149 OnRestartSim(rdata);
150 }
151
152 public void SendSimOnlineNotification(ulong regionHandle)
153 {
154 RegionInfo Result = null;
155
156 for (int i = 0; i < m_localScenes.Count; i++)
157 {
158 if (m_localScenes[i].RegionInfo.RegionHandle == regionHandle)
159 {
160 // Inform other regions to tell their avatar about me
161 Result = m_localScenes[i].RegionInfo;
162 }
163 }
164 if (Result != null)
165 {
166 for (int i = 0; i < m_localScenes.Count; i++)
167 {
168 if (m_localScenes[i].RegionInfo.RegionHandle != regionHandle)
169 {
170 // Inform other regions to tell their avatar about me
171 //m_localScenes[i].OtherRegionUp(Result);
172 }
173 }
174 }
175 else
176 {
177 m_log.Error("[REGION]: Unable to notify Other regions of this Region coming up");
178 }
179 }
180
181 /// <summary>
182 /// Save the prims in the current scene to an xml file in OpenSimulator's original 'xml' format
183 /// </summary>
184 /// <param name="filename"></param>
185 public void SaveCurrentSceneToXml(string filename)
186 {
187 IRegionSerialiserModule serialiser = CurrentOrFirstScene.RequestModuleInterface<IRegionSerialiserModule>();
188 if (serialiser != null)
189 serialiser.SavePrimsToXml(CurrentOrFirstScene, filename);
190 }
191
192 /// <summary>
193 /// Load an xml file of prims in OpenSimulator's original 'xml' file format to the current scene
194 /// </summary>
195 /// <param name="filename"></param>
196 /// <param name="generateNewIDs"></param>
197 /// <param name="loadOffset"></param>
198 public void LoadCurrentSceneFromXml(string filename, bool generateNewIDs, Vector3 loadOffset)
199 {
200 IRegionSerialiserModule serialiser = CurrentOrFirstScene.RequestModuleInterface<IRegionSerialiserModule>();
201 if (serialiser != null)
202 serialiser.LoadPrimsFromXml(CurrentOrFirstScene, filename, generateNewIDs, loadOffset);
203 }
204
205 /// <summary>
206 /// Save the prims in the current scene to an xml file in OpenSimulator's current 'xml2' format
207 /// </summary>
208 /// <param name="filename"></param>
209 public void SaveCurrentSceneToXml2(string filename)
210 {
211 IRegionSerialiserModule serialiser = CurrentOrFirstScene.RequestModuleInterface<IRegionSerialiserModule>();
212 if (serialiser != null)
213 serialiser.SavePrimsToXml2(CurrentOrFirstScene, filename);
214 }
215
216 public void SaveNamedPrimsToXml2(string primName, string filename)
217 {
218 IRegionSerialiserModule serialiser = CurrentOrFirstScene.RequestModuleInterface<IRegionSerialiserModule>();
219 if (serialiser != null)
220 serialiser.SaveNamedPrimsToXml2(CurrentOrFirstScene, primName, filename);
221 }
222
223 /// <summary>
224 /// Load an xml file of prims in OpenSimulator's current 'xml2' file format to the current scene
225 /// </summary>
226 public void LoadCurrentSceneFromXml2(string filename)
227 {
228 IRegionSerialiserModule serialiser = CurrentOrFirstScene.RequestModuleInterface<IRegionSerialiserModule>();
229 if (serialiser != null)
230 serialiser.LoadPrimsFromXml2(CurrentOrFirstScene, filename);
231 }
232
233 /// <summary>
234 /// Save the current scene to an OpenSimulator archive. This archive will eventually include the prim's assets
235 /// as well as the details of the prims themselves.
236 /// </summary>
237 /// <param name="filename"></param>
238 public void SaveCurrentSceneToArchive(string filename)
239 {
240 IRegionArchiverModule archiver = CurrentOrFirstScene.RequestModuleInterface<IRegionArchiverModule>();
241 if (archiver != null)
242 archiver.ArchiveRegion(filename);
243 }
244
245 /// <summary>
246 /// Load an OpenSim archive into the current scene. This will load both the shapes of the prims and upload
247 /// their assets to the asset service.
248 /// </summary>
249 /// <param name="filename"></param>
250 public void LoadArchiveToCurrentScene(string filename)
251 {
252 IRegionArchiverModule archiver = CurrentOrFirstScene.RequestModuleInterface<IRegionArchiverModule>();
253 if (archiver != null)
254 archiver.DearchiveRegion(filename);
255 }
256
257 public string SaveCurrentSceneMapToXmlString()
258 {
259 return CurrentOrFirstScene.Heightmap.SaveToXmlString();
260 }
261
262 public void LoadCurrenSceneMapFromXmlString(string mapData)
263 {
264 CurrentOrFirstScene.Heightmap.LoadFromXmlString(mapData);
265 }
266
267 public void SendCommandToPluginModules(string[] cmdparams)
268 {
269 ForEachCurrentScene(delegate(Scene scene) { scene.SendCommandToPlugins(cmdparams); });
270 }
271
272 public void SetBypassPermissionsOnCurrentScene(bool bypassPermissions)
273 {
274 ForEachCurrentScene(delegate(Scene scene) { scene.Permissions.SetBypassPermissions(bypassPermissions); });
275 }
276
277 private void ForEachCurrentScene(Action<Scene> func)
278 {
279 if (m_currentScene == null)
280 {
281 m_localScenes.ForEach(func);
282 }
283 else
284 {
285 func(m_currentScene);
286 }
287 }
288
289 public void RestartCurrentScene()
290 {
291 ForEachCurrentScene(delegate(Scene scene) { scene.RestartNow(); });
292 }
293
294 public void BackupCurrentScene()
295 {
296 ForEachCurrentScene(delegate(Scene scene) { scene.Backup(); });
297 }
298
299 public void HandleAlertCommandOnCurrentScene(string[] cmdparams)
300 {
301 ForEachCurrentScene(delegate(Scene scene) { scene.HandleAlertCommand(cmdparams); });
302 }
303
304 public void SendGeneralMessage(string msg)
305 {
306 ForEachCurrentScene(delegate(Scene scene) { scene.HandleAlertCommand(new string[] { "general", msg }); });
307 }
308
309 public bool TrySetCurrentScene(string regionName)
310 {
311 if ((String.Compare(regionName, "root") == 0)
312 || (String.Compare(regionName, "..") == 0)
313 || (String.Compare(regionName, "/") == 0))
314 {
315 m_currentScene = null;
316 return true;
317 }
318 else
319 {
320 foreach (Scene scene in m_localScenes)
321 {
322 if (String.Compare(scene.RegionInfo.RegionName, regionName, true) == 0)
323 {
324 m_currentScene = scene;
325 return true;
326 }
327 }
328
329 return false;
330 }
331 }
332
333 public bool TrySetCurrentScene(UUID regionID)
334 {
335 Console.WriteLine("Searching for Region: '{0}'", regionID.ToString());
336
337 foreach (Scene scene in m_localScenes)
338 {
339 if (scene.RegionInfo.RegionID == regionID)
340 {
341 m_currentScene = scene;
342 return true;
343 }
344 }
345
346 return false;
347 }
348
349 public bool TryGetScene(string regionName, out Scene scene)
350 {
351 foreach (Scene mscene in m_localScenes)
352 {
353 if (String.Compare(mscene.RegionInfo.RegionName, regionName, true) == 0)
354 {
355 scene = mscene;
356 return true;
357 }
358 }
359 scene = null;
360 return false;
361 }
362
363 public bool TryGetScene(UUID regionID, out Scene scene)
364 {
365 foreach (Scene mscene in m_localScenes)
366 {
367 if (mscene.RegionInfo.RegionID == regionID)
368 {
369 scene = mscene;
370 return true;
371 }
372 }
373
374 scene = null;
375 return false;
376 }
377
378 public bool TryGetScene(uint locX, uint locY, out Scene scene)
379 {
380 foreach (Scene mscene in m_localScenes)
381 {
382 if (mscene.RegionInfo.RegionLocX == locX &&
383 mscene.RegionInfo.RegionLocY == locY)
384 {
385 scene = mscene;
386 return true;
387 }
388 }
389
390 scene = null;
391 return false;
392 }
393
394 public bool TryGetScene(IPEndPoint ipEndPoint, out Scene scene)
395 {
396 foreach (Scene mscene in m_localScenes)
397 {
398 if ((mscene.RegionInfo.InternalEndPoint.Equals(ipEndPoint.Address)) &&
399 (mscene.RegionInfo.InternalEndPoint.Port == ipEndPoint.Port))
400 {
401 scene = mscene;
402 return true;
403 }
404 }
405
406 scene = null;
407 return false;
408 }
409
410 /// <summary>
411 /// Set the debug packet level on the current scene. This level governs which packets are printed out to the
412 /// console.
413 /// </summary>
414 /// <param name="newDebug"></param>
415 public void SetDebugPacketLevelOnCurrentScene(int newDebug)
416 {
417 ForEachCurrentScene(delegate(Scene scene)
418 {
419 List<ScenePresence> scenePresences = scene.GetScenePresences();
420
421 foreach (ScenePresence scenePresence in scenePresences)
422 {
423 if (!scenePresence.IsChildAgent)
424 {
425 m_log.ErrorFormat("Packet debug for {0} {1} set to {2}",
426 scenePresence.Firstname,
427 scenePresence.Lastname,
428 newDebug);
429
430 scenePresence.ControllingClient.SetDebugPacketLevel(newDebug);
431 }
432 }
433 });
434 }
435
436 public List<ScenePresence> GetCurrentSceneAvatars()
437 {
438 List<ScenePresence> avatars = new List<ScenePresence>();
439
440 ForEachCurrentScene(delegate(Scene scene)
441 {
442 List<ScenePresence> scenePresences = scene.GetScenePresences();
443
444 foreach (ScenePresence scenePresence in scenePresences)
445 {
446 if (!scenePresence.IsChildAgent)
447 {
448 avatars.Add(scenePresence);
449 }
450 }
451 });
452
453 return avatars;
454 }
455
456 public List<ScenePresence> GetCurrentScenePresences()
457 {
458 List<ScenePresence> presences = new List<ScenePresence>();
459
460 ForEachCurrentScene(delegate(Scene scene)
461 {
462 List<ScenePresence> scenePresences = scene.GetScenePresences();
463 presences.AddRange(scenePresences);
464 });
465
466 return presences;
467 }
468
469 public RegionInfo GetRegionInfo(ulong regionHandle)
470 {
471 foreach (Scene scene in m_localScenes)
472 {
473 if (scene.RegionInfo.RegionHandle == regionHandle)
474 {
475 return scene.RegionInfo;
476 }
477 }
478
479 return null;
480 }
481
482 public void ForceCurrentSceneClientUpdate()
483 {
484 ForEachCurrentScene(delegate(Scene scene) { scene.ForceClientUpdate(); });
485 }
486
487 public void HandleEditCommandOnCurrentScene(string[] cmdparams)
488 {
489 ForEachCurrentScene(delegate(Scene scene) { scene.HandleEditCommand(cmdparams); });
490 }
491
492 public bool TryGetAvatar(UUID avatarId, out ScenePresence avatar)
493 {
494 foreach (Scene scene in m_localScenes)
495 {
496 if (scene.TryGetAvatar(avatarId, out avatar))
497 {
498 return true;
499 }
500 }
501
502 avatar = null;
503 return false;
504 }
505
506 public bool TryGetAvatarsScene(UUID avatarId, out Scene scene)
507 {
508 ScenePresence avatar = null;
509 foreach (Scene mScene in m_localScenes)
510 {
511 if (mScene.TryGetAvatar(avatarId, out avatar))
512 {
513 scene = mScene;
514 return true;
515 }
516 }
517
518 scene = null;
519 return false;
520 }
521
522 public void CloseScene(Scene scene)
523 {
524 m_localScenes.Remove(scene);
525 scene.Close();
526 }
527
528 public bool TryGetAvatarByName(string avatarName, out ScenePresence avatar)
529 {
530 foreach (Scene scene in m_localScenes)
531 {
532 if (scene.TryGetAvatarByName(avatarName, out avatar))
533 {
534 return true;
535 }
536 }
537
538 avatar = null;
539 return false;
540 }
541
542 public void ForEachScene(Action<Scene> action)
543 {
544 m_localScenes.ForEach(action);
545 }
546
547 public void CacheJ2kDecode(int threads)
548 {
549 if (threads < 1) threads = 1;
550
551 IJ2KDecoder m_decoder = m_localScenes[0].RequestModuleInterface<IJ2KDecoder>();
552
553 List<UUID> assetRequestList = new List<UUID>();
554
555 #region AssetGathering!
556 foreach (Scene scene in m_localScenes)
557 {
558 List<EntityBase> entitles = scene.GetEntities();
559 foreach (EntityBase entity in entitles)
560 {
561 if (entity is SceneObjectGroup)
562 {
563 SceneObjectGroup sog = (SceneObjectGroup) entity;
564 foreach (SceneObjectPart part in sog.Children.Values)
565 {
566 if (part.Shape != null)
567 {
568 if (part.Shape.TextureEntry.Length > 0)
569 {
570 OpenMetaverse.Primitive.TextureEntry te =
571 new Primitive.TextureEntry(part.Shape.TextureEntry, 0,
572 part.Shape.TextureEntry.Length);
573 if (te.DefaultTexture != null) // this has been null for some reason...
574 {
575 if (te.DefaultTexture.TextureID != UUID.Zero)
576 assetRequestList.Add(te.DefaultTexture.TextureID);
577 }
578 for (int i=0; i<te.FaceTextures.Length; i++)
579 {
580 if (te.FaceTextures[i] != null)
581 {
582 if (te.FaceTextures[i].TextureID != UUID.Zero)
583 {
584 assetRequestList.Add(te.FaceTextures[i].TextureID);
585 }
586 }
587 }
588 }
589 if (part.Shape.SculptTexture != UUID.Zero)
590 {
591 assetRequestList.Add(part.Shape.SculptTexture);
592 }
593
594 }
595 }
596 }
597 }
598 }
599 #endregion
600
601 int entries_per_thread = (assetRequestList.Count / threads) + 1;
602
603 UUID[] arrAssetRequestList = assetRequestList.ToArray();
604
605 List<UUID[]> arrvalus = new List<UUID[]>();
606
607 //split into separate arrays
608 for (int j = 0; j < threads; j++)
609 {
610 List<UUID> val = new List<UUID>();
611
612 for (int k = j * entries_per_thread; k < ((j + 1) * entries_per_thread); k++)
613 {
614 if (k < arrAssetRequestList.Length)
615 {
616 val.Add(arrAssetRequestList[k]);
617 }
618
619 }
620 arrvalus.Add(val.ToArray());
621 }
622
623 for (int l = 0; l < arrvalus.Count; l++)
624 {
625 DecodeThreadContents threadworkItem = new DecodeThreadContents();
626 threadworkItem.sn = m_localScenes[0];
627 threadworkItem.j2kdecode = m_decoder;
628 threadworkItem.arrassets = arrvalus[l];
629
630 System.Threading.Thread decodethread =
631 new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(threadworkItem.run));
632
633 threadworkItem.SetThread(decodethread);
634
635 decodethread.Priority = System.Threading.ThreadPriority.Lowest;
636 decodethread.Name = "J2kCacheDecodeThread_" + l + 1;
637 ThreadTracker.Add(decodethread);
638 decodethread.Start();
639
640 }
641 }
642 }
643
644 public class DecodeThreadContents
645 {
646 public Scene sn;
647 public UUID[] arrassets;
648 public IJ2KDecoder j2kdecode;
649 private System.Threading.Thread thisthread;
650
651 public void run( object o)
652 {
653 for (int i=0;i<arrassets.Length;i++)
654 {
655 AssetBase ab = sn.AssetCache.GetAsset(arrassets[i], true);
656 if (ab != null && ab.Data != null)
657 {
658 j2kdecode.syncdecode(arrassets[i], ab.Data);
659 }
660 }
661 ThreadTracker.Remove(thisthread);
662 }
663
664 public void SetThread(System.Threading.Thread thr)
665 {
666 thisthread = thr;
667 }
668 }
669}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
new file mode 100644
index 0000000..5fa6609
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs
@@ -0,0 +1,401 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Reflection;
31using OpenMetaverse;
32using log4net;
33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
35using System.Collections.Generic;
36using System.Xml;
37
38namespace OpenSim.Region.Framework.Scenes
39{
40 public partial class SceneObjectGroup : EntityBase
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 /// <summary>
45 /// Force all task inventories of prims in the scene object to persist
46 /// </summary>
47 public void ForceInventoryPersistence()
48 {
49 lock (m_parts)
50 {
51 foreach (SceneObjectPart part in m_parts.Values)
52 {
53 part.Inventory.ForceInventoryPersistence();
54 }
55 }
56 }
57
58 /// <summary>
59 /// Start the scripts contained in all the prims in this group.
60 /// </summary>
61 public void CreateScriptInstances(int startParam, bool postOnRez,
62 string engine, int stateSource)
63 {
64 // Don't start scripts if they're turned off in the region!
65 if (!m_scene.RegionInfo.RegionSettings.DisableScripts)
66 {
67 foreach (SceneObjectPart part in m_parts.Values)
68 {
69 part.Inventory.CreateScriptInstances(startParam, postOnRez, engine, stateSource);
70 }
71 }
72 }
73
74 /// <summary>
75 /// Stop the scripts contained in all the prims in this group
76 /// </summary>
77 public void RemoveScriptInstances()
78 {
79 lock (m_parts)
80 {
81 foreach (SceneObjectPart part in m_parts.Values)
82 {
83 part.Inventory.RemoveScriptInstances();
84 }
85 }
86 }
87
88 /// <summary>
89 ///
90 /// </summary>
91 /// <param name="remoteClient"></param>
92 /// <param name="localID"></param>
93 public bool GetPartInventoryFileName(IClientAPI remoteClient, uint localID)
94 {
95 SceneObjectPart part = GetChildPart(localID);
96 if (part != null)
97 {
98 return part.Inventory.GetInventoryFileName(remoteClient, localID);
99 }
100 else
101 {
102 m_log.ErrorFormat(
103 "[PRIM INVENTORY]: " +
104 "Couldn't find part {0} in object group {1}, {2} to retreive prim inventory",
105 localID, Name, UUID);
106 }
107 return false;
108 }
109
110 /// <summary>
111 /// Return serialized inventory metadata for the given constituent prim
112 /// </summary>
113 /// <param name="localID"></param>
114 /// <param name="xferManager"></param>
115 public void RequestInventoryFile(IClientAPI client, uint localID, IXfer xferManager)
116 {
117 SceneObjectPart part = GetChildPart(localID);
118 if (part != null)
119 {
120 part.Inventory.RequestInventoryFile(client, xferManager);
121 }
122 else
123 {
124 m_log.ErrorFormat(
125 "[PRIM INVENTORY]: " +
126 "Couldn't find part {0} in object group {1}, {2} to request inventory data",
127 localID, Name, UUID);
128 }
129 }
130
131 /// <summary>
132 /// Add an inventory item to a prim in this group.
133 /// </summary>
134 /// <param name="remoteClient"></param>
135 /// <param name="localID"></param>
136 /// <param name="item"></param>
137 /// <param name="copyItemID">The item UUID that should be used by the new item.</param>
138 /// <returns></returns>
139 public bool AddInventoryItem(IClientAPI remoteClient, uint localID,
140 InventoryItemBase item, UUID copyItemID)
141 {
142 UUID newItemId = (copyItemID != UUID.Zero) ? copyItemID : item.ID;
143
144 SceneObjectPart part = GetChildPart(localID);
145 if (part != null)
146 {
147 TaskInventoryItem taskItem = new TaskInventoryItem();
148
149 taskItem.ItemID = newItemId;
150 taskItem.AssetID = item.AssetID;
151 taskItem.Name = item.Name;
152 taskItem.Description = item.Description;
153 taskItem.OwnerID = part.OwnerID; // Transfer ownership
154 taskItem.CreatorID = item.Creator;
155 taskItem.Type = item.AssetType;
156 taskItem.InvType = item.InvType;
157
158 if (remoteClient != null &&
159 remoteClient.AgentId != part.OwnerID &&
160 m_scene.Permissions.PropagatePermissions())
161 {
162 taskItem.BasePermissions = item.BasePermissions &
163 item.NextPermissions;
164 taskItem.CurrentPermissions = item.CurrentPermissions &
165 item.NextPermissions;
166 taskItem.EveryonePermissions = item.EveryOnePermissions &
167 item.NextPermissions;
168 taskItem.GroupPermissions = item.GroupPermissions &
169 item.NextPermissions;
170 taskItem.NextPermissions = item.NextPermissions;
171 taskItem.CurrentPermissions |= 8;
172 } else {
173 taskItem.BasePermissions = item.BasePermissions;
174 taskItem.CurrentPermissions = item.CurrentPermissions;
175 taskItem.CurrentPermissions |= 8;
176 taskItem.EveryonePermissions = item.EveryOnePermissions;
177 taskItem.GroupPermissions = item.GroupPermissions;
178 taskItem.NextPermissions = item.NextPermissions;
179 }
180
181 taskItem.Flags = item.Flags;
182 // TODO: These are pending addition of those fields to TaskInventoryItem
183// taskItem.SalePrice = item.SalePrice;
184// taskItem.SaleType = item.SaleType;
185 taskItem.CreationDate = (uint)item.CreationDate;
186
187 bool addFromAllowedDrop = false;
188 if (remoteClient!=null)
189 {
190 addFromAllowedDrop = remoteClient.AgentId != part.OwnerID;
191 }
192
193 part.Inventory.AddInventoryItem(taskItem, addFromAllowedDrop);
194
195 return true;
196 }
197 else
198 {
199 m_log.ErrorFormat(
200 "[PRIM INVENTORY]: " +
201 "Couldn't find prim local ID {0} in group {1}, {2} to add inventory item ID {3}",
202 localID, Name, UUID, newItemId);
203 }
204
205 return false;
206 }
207
208 /// <summary>
209 /// Returns an existing inventory item. Returns the original, so any changes will be live.
210 /// </summary>
211 /// <param name="primID"></param>
212 /// <param name="itemID"></param>
213 /// <returns>null if the item does not exist</returns>
214 public TaskInventoryItem GetInventoryItem(uint primID, UUID itemID)
215 {
216 SceneObjectPart part = GetChildPart(primID);
217 if (part != null)
218 {
219 return part.Inventory.GetInventoryItem(itemID);
220 }
221 else
222 {
223 m_log.ErrorFormat(
224 "[PRIM INVENTORY]: " +
225 "Couldn't find prim local ID {0} in prim {1}, {2} to get inventory item ID {3}",
226 primID, part.Name, part.UUID, itemID);
227 }
228
229 return null;
230 }
231
232 /// <summary>
233 /// Update an existing inventory item.
234 /// </summary>
235 /// <param name="item">The updated item. An item with the same id must already exist
236 /// in this prim's inventory</param>
237 /// <returns>false if the item did not exist, true if the update occurred succesfully</returns>
238 public bool UpdateInventoryItem(TaskInventoryItem item)
239 {
240 SceneObjectPart part = GetChildPart(item.ParentPartID);
241 if (part != null)
242 {
243 part.Inventory.UpdateInventoryItem(item);
244
245 return true;
246 }
247 else
248 {
249 m_log.ErrorFormat(
250 "[PRIM INVENTORY]: " +
251 "Couldn't find prim ID {0} to update item {1}, {2}",
252 item.ParentPartID, item.Name, item.ItemID);
253 }
254
255 return false;
256 }
257
258 public int RemoveInventoryItem(uint localID, UUID itemID)
259 {
260 SceneObjectPart part = GetChildPart(localID);
261 if (part != null)
262 {
263 int type = part.Inventory.RemoveInventoryItem(itemID);
264
265 return type;
266 }
267
268 return -1;
269 }
270
271 public uint GetEffectivePermissions()
272 {
273 uint perms=(uint)(PermissionMask.Modify |
274 PermissionMask.Copy |
275 PermissionMask.Move |
276 PermissionMask.Transfer) | 7;
277
278 uint ownerMask = 0x7ffffff;
279 foreach (SceneObjectPart part in m_parts.Values)
280 {
281 ownerMask &= part.OwnerMask;
282 perms &= part.Inventory.MaskEffectivePermissions();
283 }
284
285 if ((ownerMask & (uint)PermissionMask.Modify) == 0)
286 perms &= ~(uint)PermissionMask.Modify;
287 if ((ownerMask & (uint)PermissionMask.Copy) == 0)
288 perms &= ~(uint)PermissionMask.Copy;
289 if ((ownerMask & (uint)PermissionMask.Transfer) == 0)
290 perms &= ~(uint)PermissionMask.Transfer;
291
292 if ((ownerMask & RootPart.NextOwnerMask & (uint)PermissionMask.Modify) == 0)
293 perms &= ~((uint)PermissionMask.Modify >> 13);
294 if ((ownerMask & RootPart.NextOwnerMask & (uint)PermissionMask.Copy) == 0)
295 perms &= ~((uint)PermissionMask.Copy >> 13);
296 if ((ownerMask & RootPart.NextOwnerMask & (uint)PermissionMask.Transfer) == 0)
297 perms &= ~((uint)PermissionMask.Transfer >> 13);
298
299 return perms;
300 }
301
302 public void ApplyNextOwnerPermissions()
303 {
304 foreach (SceneObjectPart part in m_parts.Values)
305 {
306 part.ApplyNextOwnerPermissions();
307 }
308 }
309
310 public string GetStateSnapshot()
311 {
312 List<string> assemblies = new List<string>();
313 Dictionary<UUID, string> states = new Dictionary<UUID, string>();
314
315 foreach (SceneObjectPart part in m_parts.Values)
316 {
317 foreach (string a in part.Inventory.GetScriptAssemblies())
318 {
319 if (a != "" && !assemblies.Contains(a))
320 assemblies.Add(a);
321 }
322
323 foreach (KeyValuePair<UUID, string> s in part.Inventory.GetScriptStates())
324 {
325 states[s.Key] = s.Value;
326 }
327 }
328
329 if (states.Count < 1 || assemblies.Count < 1)
330 return "";
331
332 XmlDocument xmldoc = new XmlDocument();
333
334 XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
335 "", "");
336
337 xmldoc.AppendChild(xmlnode);
338 XmlElement rootElement = xmldoc.CreateElement("", "ScriptData",
339 "");
340
341 xmldoc.AppendChild(rootElement);
342
343 XmlElement wrapper = xmldoc.CreateElement("", "Assemblies",
344 "");
345
346 rootElement.AppendChild(wrapper);
347
348 foreach (string assembly in assemblies)
349 {
350 string fn = Path.GetFileName(assembly);
351 if (fn == String.Empty)
352 continue;
353
354 FileInfo fi = new FileInfo(assembly);
355
356 if (fi == null)
357 continue;
358
359 Byte[] data = new Byte[fi.Length];
360
361 FileStream fs = File.Open(assembly, FileMode.Open, FileAccess.Read);
362 fs.Read(data, 0, data.Length);
363 fs.Close();
364
365 XmlElement assemblyData = xmldoc.CreateElement("", "Assembly", "");
366 XmlAttribute assemblyName = xmldoc.CreateAttribute("", "Filename", "");
367 assemblyName.Value = fn;
368 assemblyData.Attributes.Append(assemblyName);
369
370 assemblyData.InnerText = System.Convert.ToBase64String(data);
371
372 wrapper.AppendChild(assemblyData);
373 }
374
375 wrapper = xmldoc.CreateElement("", "ScriptStates",
376 "");
377
378 rootElement.AppendChild(wrapper);
379
380 foreach (KeyValuePair<UUID, string> state in states)
381 {
382 XmlElement stateData = xmldoc.CreateElement("", "State", "");
383
384 XmlAttribute stateID = xmldoc.CreateAttribute("", "UUID", "");
385 stateID.Value = state.Key.ToString();
386 stateData.Attributes.Append(stateID);
387
388 XmlDocument sdoc = new XmlDocument();
389 sdoc.LoadXml(state.Value);
390 XmlNodeList rootL = sdoc.GetElementsByTagName("ScriptState");
391 XmlNode rootNode = rootL[0];
392
393 XmlNode newNode = xmldoc.ImportNode(rootNode, true);
394 stateData.AppendChild(newNode);
395 wrapper.AppendChild(stateData);
396 }
397
398 return xmldoc.InnerXml;
399 }
400 }
401}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
new file mode 100644
index 0000000..57d9ce4
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -0,0 +1,3012 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Drawing;
31using System.IO;
32using System.Xml;
33using System.Xml.Serialization;
34using OpenMetaverse;
35using OpenMetaverse.Packets;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Physics.Manager;
39
40namespace OpenSim.Region.Framework.Scenes
41{
42 [Flags]
43 public enum scriptEvents
44 {
45 None = 0,
46 attach = 1,
47 collision = 16,
48 collision_end = 32,
49 collision_start = 64,
50 control = 128,
51 dataserver = 256,
52 email = 512,
53 http_response = 1024,
54 land_collision = 2048,
55 land_collision_end = 4096,
56 land_collision_start = 8192,
57 at_target = 16384,
58 listen = 32768,
59 money = 65536,
60 moving_end = 131072,
61 moving_start = 262144,
62 not_at_rot_target = 524288,
63 not_at_target = 1048576,
64 remote_data = 8388608,
65 run_time_permissions = 268435456,
66 state_entry = 1073741824,
67 state_exit = 2,
68 timer = 4,
69 touch = 8,
70 touch_end = 536870912,
71 touch_start = 2097152,
72 object_rez = 4194304
73 }
74
75 struct scriptPosTarget
76 {
77 public Vector3 targetPos;
78 public float tolerance;
79 }
80
81 public delegate void PrimCountTaintedDelegate();
82
83 /// <summary>
84 /// A scene object group is conceptually an object in the scene. The object is constituted of SceneObjectParts
85 /// (often known as prims), one of which is considered the root part.
86 /// </summary>
87 public partial class SceneObjectGroup : EntityBase
88 {
89 // private PrimCountTaintedDelegate handlerPrimCountTainted = null;
90
91 /// <summary>
92 /// Signal whether the non-inventory attributes of any prims in the group have changed
93 /// since the group's last persistent backup
94 /// </summary>
95 private bool m_hasGroupChanged = false;
96 private long timeFirstChanged;
97 private long timeLastChanged;
98
99 public bool HasGroupChanged
100 {
101 set
102 {
103 if (value)
104 {
105 timeLastChanged = DateTime.Now.Ticks;
106 if (!m_hasGroupChanged)
107 timeFirstChanged = DateTime.Now.Ticks;
108 }
109 m_hasGroupChanged = value;
110 }
111
112 get { return m_hasGroupChanged; }
113 }
114
115 private bool isTimeToPersist()
116 {
117 if (IsSelected || IsDeleted || IsAttachment)
118 return false;
119 if (!m_hasGroupChanged)
120 return false;
121 if (m_scene.ShuttingDown)
122 return true;
123 long currentTime = DateTime.Now.Ticks;
124 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter)
125 return true;
126 return false;
127 }
128
129 /// <value>
130 /// Is this scene object acting as an attachment?
131 ///
132 /// We return false if the group has already been deleted.
133 ///
134 /// TODO: At the moment set must be done on the part itself. There may be a case for doing it here since I
135 /// presume either all or no parts in a linkset can be part of an attachment (in which
136 /// case the value would get proprogated down into all the descendent parts).
137 /// </value>
138 public bool IsAttachment
139 {
140 get
141 {
142 if (!IsDeleted)
143 return m_rootPart.IsAttachment;
144
145 return false;
146 }
147 }
148
149 public float scriptScore = 0f;
150
151 private Vector3 lastPhysGroupPos;
152 private Quaternion lastPhysGroupRot;
153
154 private bool m_isBackedUp = false;
155
156 /// <summary>
157 /// The constituent parts of this group
158 /// </summary>
159 protected Dictionary<UUID, SceneObjectPart> m_parts = new Dictionary<UUID, SceneObjectPart>();
160
161 protected ulong m_regionHandle;
162 protected SceneObjectPart m_rootPart;
163 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
164
165 private Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>();
166
167 private bool m_scriptListens_atTarget = false;
168 private bool m_scriptListens_notAtTarget = false;
169
170 #region Properties
171
172 /// <summary>
173 /// The name of an object grouping is always the same as its root part
174 /// </summary>
175 public override string Name
176 {
177 get {
178 if (RootPart == null)
179 return "";
180 return RootPart.Name;
181 }
182 set { RootPart.Name = value; }
183 }
184
185 /// <summary>
186 /// Added because the Parcel code seems to use it
187 /// but not sure a object should have this
188 /// as what does it tell us? that some avatar has selected it (but not what Avatar/user)
189 /// think really there should be a list (or whatever) in each scenepresence
190 /// saying what prim(s) that user has selected.
191 /// </summary>
192 protected bool m_isSelected = false;
193
194 /// <summary>
195 /// Number of prims in this group
196 /// </summary>
197 public int PrimCount
198 {
199 get { return m_parts.Count; }
200 }
201
202 public Quaternion GroupRotation
203 {
204 get { return m_rootPart.RotationOffset; }
205 }
206
207 public UUID GroupID
208 {
209 get { return m_rootPart.GroupID; }
210 set { m_rootPart.GroupID = value; }
211 }
212
213 public Dictionary<UUID, SceneObjectPart> Children
214 {
215 get { return m_parts; }
216 set { m_parts = value; }
217 }
218
219 /// <value>
220 /// The root part of this scene object
221 /// </value>
222 public SceneObjectPart RootPart
223 {
224 get { return m_rootPart; }
225 }
226
227 public ulong RegionHandle
228 {
229 get { return m_regionHandle; }
230 set
231 {
232 m_regionHandle = value;
233 lock (m_parts)
234 {
235 foreach (SceneObjectPart part in m_parts.Values)
236 {
237 part.RegionHandle = m_regionHandle;
238 }
239 }
240 }
241 }
242
243 /// <summary>
244 /// The absolute position of this scene object in the scene
245 /// </summary>
246 public override Vector3 AbsolutePosition
247 {
248 get
249 {
250 if (m_rootPart == null)
251 {
252 throw new NullReferenceException(
253 string.Format("[SCENE OBJECT GROUP]: Object {0} has no root part.", m_uuid));
254 }
255
256 return m_rootPart.GroupPosition;
257 }
258 set
259 {
260 Vector3 val = value;
261
262 if ((val.X > 257f || val.X < -1f || val.Y > 257f || val.Y < -1f) && !IsAttachment)
263 {
264 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
265 }
266
267 lock (m_parts)
268 {
269 foreach (SceneObjectPart part in m_parts.Values)
270 {
271 part.GroupPosition = val;
272 }
273 }
274
275 //if (m_rootPart.PhysActor != null)
276 //{
277 //m_rootPart.PhysActor.Position =
278 //new PhysicsVector(m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y,
279 //m_rootPart.GroupPosition.Z);
280 //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
281 //}
282 }
283 }
284
285 public override uint LocalId
286 {
287 get
288 {
289 if (m_rootPart == null)
290 {
291 m_log.Error("[SCENE OBJECT GROUP]: Unable to find the rootpart for a LocalId Request!");
292 return 0;
293 }
294
295 return m_rootPart.LocalId;
296 }
297 set { m_rootPart.LocalId = value; }
298 }
299
300 public override UUID UUID
301 {
302 get {
303 if (m_rootPart == null)
304 {
305 m_log.Error("Got a null rootpart while requesting UUID. Called from: ", new Exception());
306 return UUID.Zero;
307 }
308 else return m_rootPart.UUID;
309 }
310 set { m_rootPart.UUID = value; }
311 }
312
313 public UUID OwnerID
314 {
315 get
316 {
317 if (m_rootPart == null)
318 return UUID.Zero;
319
320 return m_rootPart.OwnerID;
321 }
322 set { m_rootPart.OwnerID = value; }
323 }
324
325 public Color Color
326 {
327 get { return m_rootPart.Color; }
328 set { m_rootPart.Color = value; }
329 }
330
331 public string Text
332 {
333 get {
334 string returnstr = m_rootPart.Text;
335 if (returnstr.Length > 255)
336 {
337 returnstr = returnstr.Substring(0, 255);
338 }
339 return returnstr;
340 }
341 set { m_rootPart.Text = value; }
342 }
343
344 protected virtual bool InSceneBackup
345 {
346 get { return true; }
347 }
348
349 public bool IsSelected
350 {
351 get { return m_isSelected; }
352 set
353 {
354 m_isSelected = value;
355 // Tell physics engine that group is selected
356 if (m_rootPart != null && m_rootPart.PhysActor != null)
357 {
358 m_rootPart.PhysActor.Selected = value;
359 // Pass it on to the children.
360 foreach (SceneObjectPart child in Children.Values)
361 {
362 if (child.PhysActor != null)
363 {
364 child.PhysActor.Selected = value;
365 }
366 }
367 }
368 }
369 }
370
371 // The UUID for the Region this Object is in.
372 public UUID RegionUUID
373 {
374 get
375 {
376 if (m_scene != null)
377 {
378 return m_scene.RegionInfo.RegionID;
379 }
380 return UUID.Zero;
381 }
382 }
383
384 #endregion
385
386 #region Constructors
387
388 /// <summary>
389 /// Constructor
390 /// </summary>
391 public SceneObjectGroup()
392 {
393 }
394
395 /// <summary>
396 /// This constructor creates a SceneObjectGroup using a pre-existing SceneObjectPart.
397 /// The original SceneObjectPart will be used rather than a copy, preserving
398 /// its existing localID and UUID.
399 /// </summary>
400 public SceneObjectGroup(SceneObjectPart part)
401 {
402 SetRootPart(part);
403 }
404
405 public SceneObjectGroup(string xmlData, bool isOriginalXmlFormat)
406 : this(UUID.Zero, xmlData, isOriginalXmlFormat)
407 {
408 }
409
410 /// <summary>
411 /// Create an object using serialized data in OpenSim's original xml format.
412 /// </summary>
413 /// <param name="fromUserInventoryItemID">
414 /// If applicable, the user inventory item id from which this object was rezzed. If not applicable then this
415 /// should be UUID.Zero
416 /// </param>
417 /// <param name="xmlData"></param>
418 /// <param name="isOriginalXmlFormat">
419 /// This parameter only exists to separate the two different xml constructors. In the future, versions should
420 /// be specified within the xml itself.
421 /// </param>
422 public SceneObjectGroup(UUID fromUserInventoryItemID, string xmlData, bool isOriginalXmlFormat)
423 {
424 if (!isOriginalXmlFormat)
425 throw new Exception("This constructor must specify the xml is in OpenSim's original format");
426
427 //m_log.DebugFormat("[SOG]: Starting deserialization of SOG");
428 int time = System.Environment.TickCount;
429
430 // libomv.types changes UUID to Guid
431 xmlData = xmlData.Replace("<UUID>", "<Guid>");
432 xmlData = xmlData.Replace("</UUID>", "</Guid>");
433
434 // Handle Nested <UUID><UUID> property
435 xmlData = xmlData.Replace("<Guid><Guid>", "<UUID><Guid>");
436 xmlData = xmlData.Replace("</Guid></Guid>", "</Guid></UUID>");
437 StringReader sr = new StringReader(xmlData);
438 XmlTextReader reader = new XmlTextReader(sr);
439
440 try
441 {
442 reader.Read();
443 reader.ReadStartElement("SceneObjectGroup");
444 reader.ReadStartElement("RootPart");
445 SetRootPart(SceneObjectPart.FromXml(fromUserInventoryItemID, reader));
446
447 reader.ReadEndElement();
448
449 while (reader.Read())
450 {
451 switch (reader.NodeType)
452 {
453 case XmlNodeType.Element:
454 if (reader.Name == "Part")
455 {
456 reader.Read();
457 SceneObjectPart part = SceneObjectPart.FromXml(reader);
458
459 // We reset the link number in order to make sure that the persisted linkset order is
460 int linkNum = part.LinkNum;
461 AddPart(part);
462 part.LinkNum = linkNum;
463
464 part.TrimPermissions();
465 part.StoreUndoState();
466 }
467 break;
468
469 case XmlNodeType.EndElement:
470 break;
471 }
472 }
473 }
474 catch (XmlException e)
475 {
476 m_log.ErrorFormat("[SCENE]: Deserialization of xml failed with {0}. xml was {1}", e, xmlData);
477 }
478
479 reader.Close();
480 sr.Close();
481 m_log.DebugFormat("[SOG]: Finished deserialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time);
482 }
483
484 /// <summary>
485 /// Create an object using serialized data in OpenSim's xml2 format.
486 /// </summary>
487 public SceneObjectGroup(string xmlData)
488 {
489 SetFromXml(xmlData);
490 }
491
492 protected void SetFromXml(string xmlData)
493 {
494 //m_log.DebugFormat("[SOG]: Starting deserialization of SOG");
495 //int time = System.Environment.TickCount;
496
497 // libomv.types changes UUID to Guid
498 xmlData = xmlData.Replace("<UUID>", "<Guid>");
499 xmlData = xmlData.Replace("</UUID>", "</Guid>");
500
501 // Handle Nested <UUID><UUID> property
502 xmlData = xmlData.Replace("<Guid><Guid>", "<UUID><Guid>");
503 xmlData = xmlData.Replace("</Guid></Guid>", "</Guid></UUID>");
504
505 StringReader sr = new StringReader(xmlData);
506 XmlTextReader reader = new XmlTextReader(sr);
507 reader.Read();
508
509 reader.ReadStartElement("SceneObjectGroup");
510 SetRootPart(CreatePartFromXml(reader));
511
512 reader.Read();
513 bool more = true;
514
515 while (more)
516 {
517 switch (reader.NodeType)
518 {
519 case XmlNodeType.Element:
520 if (reader.Name == "SceneObjectPart")
521 {
522 SceneObjectPart part = CreatePartFromXml(reader);
523 AddPart(part);
524 part.StoreUndoState();
525 }
526 else
527 {
528 Console.WriteLine("found unexpected element: " + reader.Name);
529 reader.Read();
530 }
531 break;
532 case XmlNodeType.EndElement:
533 reader.Read();
534 break;
535 }
536 more = !reader.EOF;
537 }
538
539 reader.Close();
540 sr.Close();
541
542 //m_log.DebugFormat("[SOG]: Finished deserialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time);
543 }
544
545 protected virtual SceneObjectPart CreatePartFromXml(XmlTextReader reader)
546 {
547 SceneObjectPart part = SceneObjectPart.FromXml(reader);
548 return part;
549 }
550
551 /// <summary>
552 /// Constructor. This object is added to the scene later via AttachToScene()
553 /// </summary>
554 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
555 {
556 Vector3 rootOffset = new Vector3(0, 0, 0);
557 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, rootOffset));
558 }
559
560 /// <summary>
561 /// Constructor.
562 /// </summary>
563 public SceneObjectGroup(UUID ownerID, Vector3 pos, PrimitiveBaseShape shape)
564 : this(ownerID, pos, Quaternion.Identity, shape)
565 {
566 }
567
568 public void SetFromAssetID(UUID AssetId)
569 {
570 lock (m_parts)
571 {
572 foreach (SceneObjectPart part in m_parts.Values)
573 {
574 part.FromAssetID = AssetId;
575 }
576 }
577 }
578
579 public UUID GetFromAssetID()
580 {
581 if (m_rootPart != null)
582 {
583 return m_rootPart.FromAssetID;
584 }
585 return UUID.Zero;
586 }
587
588 /// <summary>
589 /// Hooks this object up to the backup event so that it is persisted to the database when the update thread executes.
590 /// </summary>
591 public void AttachToBackup()
592 {
593 if (InSceneBackup)
594 {
595 //m_log.DebugFormat(
596 // "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID);
597
598 if (!m_isBackedUp)
599 m_scene.EventManager.OnBackup += ProcessBackup;
600
601 m_isBackedUp = true;
602 }
603 }
604
605 /// <summary>
606 /// Attach this object to a scene. It will also now appear to agents.
607 /// </summary>
608 /// <param name="scene"></param>
609 public void AttachToScene(Scene scene)
610 {
611 m_scene = scene;
612 RegionHandle = m_scene.RegionInfo.RegionHandle;
613
614 if (m_rootPart.Shape.PCode != 9 || m_rootPart.Shape.State == 0)
615 m_rootPart.ParentID = 0;
616 if (m_rootPart.LocalId==0)
617 m_rootPart.LocalId = m_scene.AllocateLocalId();
618
619 // No need to lock here since the object isn't yet in a scene
620 foreach (SceneObjectPart part in m_parts.Values)
621 {
622 if (Object.ReferenceEquals(part, m_rootPart))
623 continue;
624 if (part.LocalId==0)
625 part.LocalId = m_scene.AllocateLocalId();
626 part.ParentID = m_rootPart.LocalId;
627 //m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID);
628 }
629
630 ApplyPhysics(m_scene.m_physicalPrim);
631
632 ScheduleGroupForFullUpdate();
633 }
634
635 public Vector3 GroupScale()
636 {
637 Vector3 minScale = new Vector3(Constants.RegionSize,Constants.RegionSize,Constants.RegionSize);
638 Vector3 maxScale = new Vector3(0f,0f,0f);
639 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
640
641 lock (m_parts)
642 {
643 foreach (SceneObjectPart part in m_parts.Values)
644 {
645 Vector3 partscale = part.Scale;
646 Vector3 partoffset = part.OffsetPosition;
647
648 minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X;
649 minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.X + partoffset.Y : minScale.Y;
650 minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.X + partoffset.Z : minScale.Z;
651
652 maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X;
653 maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y;
654 maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z;
655 }
656 }
657 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X;
658 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y;
659 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z;
660 return finalScale;
661
662 }
663 public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters)
664 {
665 // We got a request from the inner_scene to raytrace along the Ray hRay
666 // We're going to check all of the prim in this group for intersection with the ray
667 // If we get a result, we're going to find the closest result to the origin of the ray
668 // and send back the intersection information back to the innerscene.
669
670 EntityIntersection returnresult = new EntityIntersection();
671
672 lock (m_parts)
673 {
674 foreach (SceneObjectPart part in m_parts.Values)
675 {
676 // Temporary commented to stop compiler warning
677 //Vector3 partPosition =
678 // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z);
679 Quaternion parentrotation = GroupRotation;
680
681 // Telling the prim to raytrace.
682 //EntityIntersection inter = part.TestIntersection(hRay, parentrotation);
683
684 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation,frontFacesOnly, faceCenters);
685
686 // This may need to be updated to the maximum draw distance possible..
687 // We might (and probably will) be checking for prim creation from other sims
688 // when the camera crosses the border.
689 float idist = Constants.RegionSize;
690
691
692 if (inter.HitTF)
693 {
694 // We need to find the closest prim to return to the testcaller along the ray
695 if (inter.distance < idist)
696 {
697 returnresult.HitTF = true;
698 returnresult.ipoint = inter.ipoint;
699 returnresult.obj = part;
700 returnresult.normal = inter.normal;
701 returnresult.distance = inter.distance;
702 }
703 }
704 }
705 }
706 return returnresult;
707 }
708
709 #endregion
710
711
712 public string ToXmlString()
713 {
714 using (StringWriter sw = new StringWriter())
715 {
716 using (XmlTextWriter writer = new XmlTextWriter(sw))
717 {
718 ToXml(writer);
719 }
720
721 return sw.ToString();
722 }
723 }
724
725 public void ToXml(XmlTextWriter writer)
726 {
727 m_log.DebugFormat("[SOG]: Starting serialization of {0}", Name);
728 int time = System.Environment.TickCount;
729
730 writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty);
731 writer.WriteStartElement(String.Empty, "RootPart", String.Empty);
732 m_rootPart.ToXml(writer);
733 writer.WriteEndElement();
734 writer.WriteStartElement(String.Empty, "OtherParts", String.Empty);
735
736 lock (m_parts)
737 {
738 foreach (SceneObjectPart part in m_parts.Values)
739 {
740 if (part.UUID != m_rootPart.UUID)
741 {
742 writer.WriteStartElement(String.Empty, "Part", String.Empty);
743 part.ToXml(writer);
744 writer.WriteEndElement();
745 }
746 }
747 }
748
749 writer.WriteEndElement();
750 writer.WriteEndElement();
751
752 m_log.DebugFormat("[SOG]: Finished serialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time);
753
754 }
755
756 public string ToXmlString2()
757 {
758 using (StringWriter sw = new StringWriter())
759 {
760 using (XmlTextWriter writer = new XmlTextWriter(sw))
761 {
762 ToXml2(writer);
763 }
764
765 return sw.ToString();
766 }
767 }
768
769 public void ToXml2(XmlTextWriter writer)
770 {
771 m_log.DebugFormat("[SOG]: Starting serialization of SOG {0} to XML2", Name);
772 int time = System.Environment.TickCount;
773
774 writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty);
775 m_rootPart.ToXml(writer);
776 writer.WriteStartElement(String.Empty, "OtherParts", String.Empty);
777
778 lock (m_parts)
779 {
780 foreach (SceneObjectPart part in m_parts.Values)
781 {
782 if (part.UUID != m_rootPart.UUID)
783 {
784 part.ToXml(writer);
785 }
786 }
787 }
788
789 writer.WriteEndElement();
790 writer.WriteEndElement();
791 m_log.DebugFormat("[SOG]: Finished serialization of SOG {0} to XML2, {1}ms", Name, System.Environment.TickCount - time);
792 }
793
794 /// <summary>
795 /// Attach this scene object to the given avatar.
796 /// </summary>
797 /// <param name="agentID"></param>
798 /// <param name="attachmentpoint"></param>
799 /// <param name="AttachOffset"></param>
800 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
801 {
802 ScenePresence avatar = m_scene.GetScenePresence(agentID);
803 if (avatar != null)
804 {
805 // don't attach attachments to child agents
806 if (avatar.IsChildAgent) return;
807
808 DetachFromBackup();
809
810 // Remove from database and parcel prim count
811 //
812 m_scene.DeleteFromStorage(UUID);
813 m_scene.EventManager.TriggerParcelPrimCountTainted();
814
815 m_rootPart.AttachedAvatar = agentID;
816
817 if (m_rootPart.PhysActor != null)
818 {
819 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
820 m_rootPart.PhysActor = null;
821 }
822
823 AbsolutePosition = AttachOffset;
824 m_rootPart.AttachedPos = AttachOffset;
825 m_rootPart.IsAttachment = true;
826
827 m_rootPart.SetParentLocalId(avatar.LocalId);
828 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
829
830 avatar.AddAttachment(this);
831
832 if (!silent)
833 {
834 // Killing it here will cause the client to deselect it
835 // It then reappears on the avatar, deselected
836 // through the full update below
837 //
838 if (IsSelected)
839 {
840 m_scene.SendKillObject(m_rootPart.LocalId);
841 }
842
843 IsSelected = false; // fudge....
844 ScheduleGroupForFullUpdate();
845 }
846 }
847 }
848
849 public byte GetAttachmentPoint()
850 {
851 if (m_rootPart != null)
852 {
853 return m_rootPart.Shape.State;
854 }
855 return (byte)0;
856 }
857
858 public void ClearPartAttachmentData()
859 {
860 SetAttachmentPoint((Byte)0);
861 }
862
863 public void DetachToGround()
864 {
865 ScenePresence avatar = m_scene.GetScenePresence(m_rootPart.AttachedAvatar);
866 if (avatar == null)
867 return;
868
869 avatar.RemoveAttachment(this);
870
871 Vector3 detachedpos = new Vector3(127f,127f,127f);
872 if (avatar == null)
873 return;
874
875 detachedpos = avatar.AbsolutePosition;
876
877 AbsolutePosition = detachedpos;
878 m_rootPart.AttachedAvatar = UUID.Zero;
879 m_rootPart.SetParentLocalId(0);
880 SetAttachmentPoint((byte)0);
881 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_scene.m_physicalPrim);
882 HasGroupChanged = true;
883 RootPart.Rezzed = DateTime.Now;
884 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
885 AttachToBackup();
886 m_scene.EventManager.TriggerParcelPrimCountTainted();
887 m_rootPart.ScheduleFullUpdate();
888 m_rootPart.ClearUndoState();
889 }
890
891 public void DetachToInventoryPrep()
892 {
893 ScenePresence avatar = m_scene.GetScenePresence(m_rootPart.AttachedAvatar);
894 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
895 if (avatar != null)
896 {
897 //detachedpos = avatar.AbsolutePosition;
898 avatar.RemoveAttachment(this);
899 }
900
901 m_rootPart.AttachedAvatar = UUID.Zero;
902 m_rootPart.SetParentLocalId(0);
903 //m_rootPart.SetAttachmentPoint((byte)0);
904 m_rootPart.IsAttachment = false;
905 AbsolutePosition = m_rootPart.AttachedPos;
906 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
907 //AttachToBackup();
908 //m_rootPart.ScheduleFullUpdate();
909
910 }
911 /// <summary>
912 ///
913 /// </summary>
914 /// <param name="part"></param>
915 private void SetPartAsNonRoot(SceneObjectPart part)
916 {
917 part.ParentID = m_rootPart.LocalId;
918 part.ClearUndoState();
919 }
920
921 public override void UpdateMovement()
922 {
923 lock (m_parts)
924 {
925 foreach (SceneObjectPart part in m_parts.Values)
926 {
927 part.UpdateMovement();
928 }
929 }
930 }
931
932 public float GetTimeDilation()
933 {
934 return m_scene.TimeDilation;
935 }
936
937 /// <summary>
938 /// Added as a way for the storage provider to reset the scene,
939 /// most likely a better way to do this sort of thing but for now...
940 /// </summary>
941 /// <param name="scene"></param>
942 public void SetScene(Scene scene)
943 {
944 m_scene = scene;
945 }
946
947 /// <summary>
948 /// Set a part to act as the root part for this scene object
949 /// </summary>
950 /// <param name="part"></param>
951 public void SetRootPart(SceneObjectPart part)
952 {
953 part.SetParent(this);
954 m_rootPart = part;
955 if (!IsAttachment)
956 part.ParentID = 0;
957 part.LinkNum = 0;
958
959 // No locking required since the SOG should not be in the scene yet - one can't change root parts after
960 // the scene object has been attached to the scene
961 m_parts.Add(m_rootPart.UUID, m_rootPart);
962 }
963
964 /// <summary>
965 /// Add a new part to this scene object. The part must already be correctly configured.
966 /// </summary>
967 /// <param name="part"></param>
968 public void AddPart(SceneObjectPart part)
969 {
970 lock (m_parts)
971 {
972 part.SetParent(this);
973 m_parts.Add(part.UUID, part);
974
975 part.LinkNum = m_parts.Count;
976
977 if (part.LinkNum == 2 && RootPart != null)
978 RootPart.LinkNum = 1;
979 }
980 }
981
982 /// <summary>
983 /// Make sure that every non root part has the proper parent root part local id
984 /// </summary>
985 private void UpdateParentIDs()
986 {
987 lock (m_parts)
988 {
989 foreach (SceneObjectPart part in m_parts.Values)
990 {
991 if (part.UUID != m_rootPart.UUID)
992 {
993 part.ParentID = m_rootPart.LocalId;
994 }
995 }
996 }
997 }
998
999 public void RegenerateFullIDs()
1000 {
1001 lock (m_parts)
1002 {
1003 foreach (SceneObjectPart part in m_parts.Values)
1004 {
1005 part.UUID = UUID.Random();
1006
1007 }
1008 }
1009 }
1010 // helper provided for parts.
1011 public int GetSceneMaxUndo()
1012 {
1013 if (m_scene != null)
1014 return m_scene.MaxUndoCount;
1015 return 5;
1016 }
1017
1018 // justincc: I don't believe this hack is needed any longer, especially since the physics
1019 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1020 // this method was preventing proper reload of scene objects.
1021 // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects
1022 // at region startup
1023 public void ResetChildPrimPhysicsPositions()
1024 {
1025 AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works?
1026 }
1027
1028 public UUID GetPartsFullID(uint localID)
1029 {
1030 SceneObjectPart part = GetChildPart(localID);
1031 if (part != null)
1032 {
1033 return part.UUID;
1034 }
1035 return UUID.Zero;
1036 }
1037
1038 public void ObjectGrabHandler(uint localId, Vector3 offsetPos, IClientAPI remoteClient)
1039 {
1040 if (m_rootPart.LocalId == localId)
1041 {
1042 OnGrabGroup(offsetPos, remoteClient);
1043 }
1044 else
1045 {
1046 SceneObjectPart part = GetChildPart(localId);
1047 OnGrabPart(part, offsetPos, remoteClient);
1048
1049 }
1050 }
1051
1052 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1053 {
1054 part.StoreUndoState();
1055 part.OnGrab(offsetPos, remoteClient);
1056 }
1057
1058 public virtual void OnGrabGroup(Vector3 offsetPos, IClientAPI remoteClient)
1059 {
1060 m_scene.EventManager.TriggerGroupGrab(UUID, offsetPos, remoteClient.AgentId);
1061 }
1062
1063 /// <summary>
1064 /// Delete this group from its scene and tell all the scene presences about that deletion.
1065 /// </summary>
1066 /// <param name="silent">Broadcast deletions to all clients.</param>
1067 public void DeleteGroup(bool silent)
1068 {
1069 // We need to keep track of this state in case this group is still queued for backup.
1070 m_isDeleted = true;
1071
1072 DetachFromBackup();
1073
1074 lock (m_parts)
1075 {
1076 foreach (SceneObjectPart part in m_parts.Values)
1077 {
1078// part.Inventory.RemoveScriptInstances();
1079
1080 List<ScenePresence> avatars = Scene.GetScenePresences();
1081 for (int i = 0; i < avatars.Count; i++)
1082 {
1083 if (avatars[i].ParentID == LocalId)
1084 {
1085 avatars[i].StandUp();
1086 }
1087
1088 if (!silent)
1089 {
1090 if (m_rootPart != null && part == m_rootPart)
1091 avatars[i].ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1092 }
1093 }
1094 }
1095 }
1096 }
1097
1098 public void AddScriptLPS(int count)
1099 {
1100 if (scriptScore + count >= float.MaxValue - count)
1101 scriptScore = 0;
1102
1103 scriptScore += (float)count;
1104 SceneGraph d = m_scene.m_sceneGraph;
1105 d.AddToScriptLPS(count);
1106 }
1107
1108 public void AddActiveScriptCount(int count)
1109 {
1110 SceneGraph d = m_scene.m_sceneGraph;
1111 d.AddActiveScripts(count);
1112 }
1113
1114 public void aggregateScriptEvents()
1115 {
1116 uint objectflagupdate=(uint)RootPart.GetEffectiveObjectFlags();
1117
1118 scriptEvents aggregateScriptEvents=0;
1119
1120 lock (m_parts)
1121 {
1122 foreach (SceneObjectPart part in m_parts.Values)
1123 {
1124 if (part == null)
1125 continue;
1126 if (part != RootPart)
1127 part.ObjectFlags = objectflagupdate;
1128 aggregateScriptEvents |= part.AggregateScriptEvents;
1129 }
1130 }
1131
1132 if ((aggregateScriptEvents & scriptEvents.at_target) != 0)
1133 {
1134 m_scriptListens_atTarget = true;
1135 }
1136 else
1137 {
1138 m_scriptListens_atTarget = false;
1139 }
1140
1141 if ((aggregateScriptEvents & scriptEvents.not_at_target) != 0)
1142 {
1143 m_scriptListens_notAtTarget = true;
1144 }
1145 else
1146 {
1147 m_scriptListens_notAtTarget = false;
1148 }
1149
1150 if (m_scriptListens_atTarget || m_scriptListens_notAtTarget)
1151 {
1152 }
1153 else
1154 {
1155 lock (m_targets)
1156 m_targets.Clear();
1157 }
1158
1159 ScheduleGroupForFullUpdate();
1160 }
1161
1162 public override void SetText(string text, Vector3 color, double alpha)
1163 {
1164 Color = Color.FromArgb(0xff - (int) (alpha * 0xff),
1165 (int) (color.X * 0xff),
1166 (int) (color.Y * 0xff),
1167 (int) (color.Z * 0xff));
1168 Text = text;
1169
1170 HasGroupChanged = true;
1171 m_rootPart.ScheduleFullUpdate();
1172 }
1173
1174 /// <summary>
1175 /// Apply physics to this group
1176 /// </summary>
1177 /// <param name="m_physicalPrim"></param>
1178 public void ApplyPhysics(bool m_physicalPrim)
1179 {
1180 lock (m_parts)
1181 {
1182 if (m_parts.Count > 1)
1183 {
1184 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1185 foreach (SceneObjectPart part in m_parts.Values)
1186 {
1187 if (part.LocalId != m_rootPart.LocalId)
1188 {
1189 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim);
1190 }
1191 }
1192
1193 // Hack to get the physics scene geometries in the right spot
1194 ResetChildPrimPhysicsPositions();
1195 }
1196 else
1197 {
1198 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1199 }
1200 }
1201 }
1202
1203 public void SetOwnerId(UUID userId)
1204 {
1205 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; });
1206 }
1207
1208 public void ForEachPart(Action<SceneObjectPart> whatToDo)
1209 {
1210 lock (m_parts)
1211 {
1212 foreach (SceneObjectPart part in m_parts.Values)
1213 {
1214 whatToDo(part);
1215 }
1216 }
1217 }
1218
1219 #region Events
1220
1221 /// <summary>
1222 /// Processes backup.
1223 /// </summary>
1224 /// <param name="datastore"></param>
1225 public void ProcessBackup(IRegionDataStore datastore, bool forcedBackup)
1226 {
1227 if (!m_isBackedUp)
1228 return;
1229
1230 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1231 // any exception propogate upwards.
1232
1233 if (IsDeleted || UUID == UUID.Zero)
1234 return;
1235
1236 try
1237 {
1238 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart
1239 {
1240 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1241 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
1242
1243 if (parcel != null && parcel.landData != null &&
1244 parcel.landData.OtherCleanTime != 0)
1245 {
1246 if (parcel.landData.OwnerID != OwnerID &&
1247 (parcel.landData.GroupID != GroupID ||
1248 parcel.landData.GroupID == UUID.Zero))
1249 {
1250 if ((DateTime.Now - RootPart.Rezzed).TotalMinutes >
1251 parcel.landData.OtherCleanTime)
1252 {
1253 DetachFromBackup();
1254 m_log.InfoFormat("[SCENE]: Returning object {0} due to parcel auto return", RootPart.UUID.ToString());
1255 m_scene.AddReturn(OwnerID, Name, AbsolutePosition, "parcel auto return");
1256 m_scene.DeRezObject(null, RootPart.LocalId,
1257 RootPart.GroupID, DeRezAction.Return, UUID.Zero);
1258
1259 return;
1260 }
1261 }
1262 }
1263 }
1264
1265 if (HasGroupChanged)
1266 {
1267 // don't backup while it's selected or you're asking for changes mid stream.
1268 if ((isTimeToPersist()) || (forcedBackup))
1269 {
1270 m_log.DebugFormat(
1271 "[SCENE]: Storing {0}, {1} in {2}",
1272 Name, UUID, m_scene.RegionInfo.RegionName);
1273
1274 SceneObjectGroup backup_group = Copy(OwnerID, GroupID, false);
1275 backup_group.RootPart.Velocity = RootPart.Velocity;
1276 backup_group.RootPart.Acceleration = RootPart.Acceleration;
1277 backup_group.RootPart.AngularVelocity = RootPart.AngularVelocity;
1278 backup_group.RootPart.ParticleSystem = RootPart.ParticleSystem;
1279 HasGroupChanged = false;
1280
1281 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1282
1283 backup_group.ForEachPart(delegate(SceneObjectPart part)
1284 {
1285 part.Inventory.ProcessInventoryBackup(datastore);
1286 });
1287
1288 backup_group = null;
1289 }
1290 // else
1291 // {
1292 // m_log.DebugFormat(
1293 // "[SCENE]: Did not update persistence of object {0} {1}, selected = {2}",
1294 // Name, UUID, IsSelected);
1295 // }
1296 }
1297 }
1298 catch (Exception e)
1299 {
1300 m_log.ErrorFormat(
1301 "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}\n\t{4}",
1302 Name, UUID, m_scene.RegionInfo.RegionName, e, e.StackTrace);
1303 }
1304 }
1305
1306 #endregion
1307
1308 #region Client Updating
1309
1310 public void SendFullUpdateToClient(IClientAPI remoteClient)
1311 {
1312 SendPartFullUpdate(remoteClient, RootPart, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID));
1313
1314 lock (m_parts)
1315 {
1316 foreach (SceneObjectPart part in m_parts.Values)
1317 {
1318 if (part != RootPart)
1319 SendPartFullUpdate(remoteClient, part, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID));
1320 }
1321 }
1322 }
1323
1324 /// <summary>
1325 /// Send a full update to the client for the given part
1326 /// </summary>
1327 /// <param name="remoteClient"></param>
1328 /// <param name="part"></param>
1329 internal void SendPartFullUpdate(IClientAPI remoteClient, SceneObjectPart part, uint clientFlags)
1330 {
1331 if (m_rootPart != null && m_rootPart.UUID == part.UUID)
1332 {
1333 if (IsAttachment)
1334 {
1335 part.SendFullUpdateToClient(remoteClient, m_rootPart.AttachedPos, clientFlags);
1336 }
1337 else
1338 {
1339 part.SendFullUpdateToClient(remoteClient, AbsolutePosition, clientFlags);
1340 }
1341 }
1342 else
1343 {
1344 part.SendFullUpdateToClient(remoteClient, clientFlags);
1345 }
1346 }
1347
1348 #endregion
1349
1350 #region Copying
1351
1352 /// <summary>
1353 /// Duplicates this object, including operations such as physics set up and attaching to the backup event.
1354 /// </summary>
1355 /// <returns></returns>
1356 public SceneObjectGroup Copy(UUID cAgentID, UUID cGroupID, bool userExposed)
1357 {
1358 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1359 dupe.m_isBackedUp = false;
1360 dupe.m_parts = new Dictionary<UUID, SceneObjectPart>();
1361 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1362
1363 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1364 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1365
1366 if (userExposed)
1367 dupe.m_rootPart.TrimPermissions();
1368
1369 /// may need to create a new Physics actor.
1370 if (dupe.RootPart.PhysActor != null && userExposed)
1371 {
1372 PrimitiveBaseShape pbs = dupe.RootPart.Shape;
1373
1374 dupe.RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape(
1375 dupe.RootPart.Name,
1376 pbs,
1377 new PhysicsVector(dupe.RootPart.AbsolutePosition.X, dupe.RootPart.AbsolutePosition.Y, dupe.RootPart.AbsolutePosition.Z),
1378 new PhysicsVector(dupe.RootPart.Scale.X, dupe.RootPart.Scale.Y, dupe.RootPart.Scale.Z),
1379 dupe.RootPart.RotationOffset,
1380 dupe.RootPart.PhysActor.IsPhysical);
1381
1382 dupe.RootPart.PhysActor.LocalID = dupe.RootPart.LocalId;
1383 dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true);
1384 }
1385
1386 // Now we've made a copy that replaces this one, we need to
1387 // switch the owner to the person who did the copying
1388 // Second Life copies an object and duplicates the first one in it's place
1389 // So, we have to make a copy of this one, set it in it's place then set the owner on this one
1390 if (userExposed)
1391 {
1392 SetRootPartOwner(m_rootPart, cAgentID, cGroupID);
1393 m_rootPart.ScheduleFullUpdate();
1394 }
1395
1396 List<SceneObjectPart> partList;
1397
1398 lock (m_parts)
1399 {
1400 partList = new List<SceneObjectPart>(m_parts.Values);
1401 }
1402
1403 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1404 {
1405 return p1.LinkNum.CompareTo(p2.LinkNum);
1406 }
1407 );
1408
1409 foreach (SceneObjectPart part in partList)
1410 {
1411 if (part.UUID != m_rootPart.UUID)
1412 {
1413 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1414
1415 newPart.LinkNum = part.LinkNum;
1416
1417 if (userExposed)
1418 {
1419 SetPartOwner(newPart, cAgentID, cGroupID);
1420 newPart.ScheduleFullUpdate();
1421 }
1422 }
1423 }
1424
1425 if (userExposed)
1426 {
1427 dupe.UpdateParentIDs();
1428 dupe.HasGroupChanged = true;
1429 dupe.AttachToBackup();
1430
1431 ScheduleGroupForFullUpdate();
1432 }
1433
1434 return dupe;
1435 }
1436
1437 /// <summary>
1438 ///
1439 /// </summary>
1440 /// <param name="part"></param>
1441 /// <param name="cAgentID"></param>
1442 /// <param name="cGroupID"></param>
1443 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1444 {
1445 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed));
1446 }
1447
1448 public void ScriptSetPhysicsStatus(bool UsePhysics)
1449 {
1450 bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
1451 bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
1452 bool IsVolumeDetect = RootPart.VolumeDetectActive;
1453 UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1454 }
1455
1456 public void ScriptSetTemporaryStatus(bool TemporaryStatus)
1457 {
1458 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1459 bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
1460 bool IsVolumeDetect = RootPart.VolumeDetectActive;
1461 UpdatePrimFlags(RootPart.LocalId, UsePhysics, TemporaryStatus, IsPhantom, IsVolumeDetect);
1462 }
1463
1464 public void ScriptSetPhantomStatus(bool PhantomStatus)
1465 {
1466 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1467 bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
1468 bool IsVolumeDetect = RootPart.VolumeDetectActive;
1469 UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, PhantomStatus, IsVolumeDetect);
1470 }
1471
1472 public void ScriptSetVolumeDetect(bool VDStatus)
1473 {
1474 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1475 bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
1476 bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
1477 UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom, VDStatus);
1478
1479 /*
1480 ScriptSetPhantomStatus(false); // What ever it was before, now it's not phantom anymore
1481
1482 if (PhysActor != null) // Should always be the case now
1483 {
1484 PhysActor.SetVolumeDetect(param);
1485 }
1486 if (param != 0)
1487 AddFlag(PrimFlags.Phantom);
1488
1489 ScheduleFullUpdate();
1490 */
1491 }
1492
1493 public void applyImpulse(PhysicsVector impulse)
1494 {
1495 // We check if rootpart is null here because scripts don't delete if you delete the host.
1496 // This means that unfortunately, we can pass a null physics actor to Simulate!
1497 // Make sure we don't do that!
1498 SceneObjectPart rootpart = m_rootPart;
1499 if (rootpart != null)
1500 {
1501 if (rootpart.PhysActor != null)
1502 {
1503 if (IsAttachment)
1504 {
1505 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1506 if (avatar != null)
1507 {
1508 avatar.PushForce(impulse);
1509 }
1510 }
1511 else
1512 {
1513 rootpart.PhysActor.AddForce(impulse,true);
1514 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
1515 }
1516 }
1517 }
1518 }
1519
1520 public void applyAngularImpulse(PhysicsVector impulse)
1521 {
1522 // We check if rootpart is null here because scripts don't delete if you delete the host.
1523 // This means that unfortunately, we can pass a null physics actor to Simulate!
1524 // Make sure we don't do that!
1525 SceneObjectPart rootpart = m_rootPart;
1526 if (rootpart != null)
1527 {
1528 if (rootpart.PhysActor != null)
1529 {
1530 if (!IsAttachment)
1531 {
1532 rootpart.PhysActor.AddAngularForce(impulse, true);
1533 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
1534 }
1535 }
1536 }
1537 }
1538
1539 public void setAngularImpulse(PhysicsVector impulse)
1540 {
1541 // We check if rootpart is null here because scripts don't delete if you delete the host.
1542 // This means that unfortunately, we can pass a null physics actor to Simulate!
1543 // Make sure we don't do that!
1544 SceneObjectPart rootpart = m_rootPart;
1545 if (rootpart != null)
1546 {
1547 if (rootpart.PhysActor != null)
1548 {
1549 if (!IsAttachment)
1550 {
1551 rootpart.PhysActor.Torque = impulse;
1552 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
1553 }
1554 }
1555 }
1556 }
1557
1558 public Vector3 GetTorque()
1559 {
1560 // We check if rootpart is null here because scripts don't delete if you delete the host.
1561 // This means that unfortunately, we can pass a null physics actor to Simulate!
1562 // Make sure we don't do that!
1563 SceneObjectPart rootpart = m_rootPart;
1564 if (rootpart != null)
1565 {
1566 if (rootpart.PhysActor != null)
1567 {
1568 if (!IsAttachment)
1569 {
1570 PhysicsVector torque = rootpart.PhysActor.Torque;
1571 return new Vector3(torque.X, torque.Y, torque.Z);
1572 }
1573 }
1574 }
1575 return Vector3.Zero;
1576 }
1577
1578 public void moveToTarget(Vector3 target, float tau)
1579 {
1580 SceneObjectPart rootpart = m_rootPart;
1581 if (rootpart != null)
1582 {
1583 if (rootpart.PhysActor != null)
1584 {
1585 rootpart.PhysActor.PIDTarget = new PhysicsVector(target.X, target.Y, target.Z);
1586 rootpart.PhysActor.PIDTau = tau;
1587 rootpart.PhysActor.PIDActive = true;
1588 }
1589 }
1590 }
1591
1592 public void stopMoveToTarget()
1593 {
1594 SceneObjectPart rootpart = m_rootPart;
1595 if (rootpart != null)
1596 {
1597 if (rootpart.PhysActor != null)
1598 {
1599 rootpart.PhysActor.PIDActive = false;
1600 }
1601 }
1602 }
1603
1604 /// <summary>
1605 /// Set the owner of the root part.
1606 /// </summary>
1607 /// <param name="part"></param>
1608 /// <param name="cAgentID"></param>
1609 /// <param name="cGroupID"></param>
1610 public void SetRootPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
1611 {
1612 part.LastOwnerID = part.OwnerID;
1613 part.OwnerID = cAgentID;
1614 part.GroupID = cGroupID;
1615
1616 if (part.OwnerID != cAgentID)
1617 {
1618 // Apply Next Owner Permissions if we're not bypassing permissions
1619 if (!m_scene.Permissions.BypassPermissions())
1620 ApplyNextOwnerPermissions();
1621 }
1622
1623 part.ScheduleFullUpdate();
1624 }
1625
1626 /// <summary>
1627 /// Make a copy of the given part.
1628 /// </summary>
1629 /// <param name="part"></param>
1630 /// <param name="cAgentID"></param>
1631 /// <param name="cGroupID"></param>
1632 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1633 {
1634 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
1635 newPart.SetParent(this);
1636
1637 lock (m_parts)
1638 {
1639 m_parts.Add(newPart.UUID, newPart);
1640 }
1641
1642 SetPartAsNonRoot(newPart);
1643
1644 return newPart;
1645 }
1646
1647 /// <summary>
1648 /// Reset the UUIDs for all the prims that make up this group.
1649 ///
1650 /// This is called by methods which want to add a new group to an existing scene, in order
1651 /// to ensure that there are no clashes with groups already present.
1652 /// </summary>
1653 public void ResetIDs()
1654 {
1655 // As this is only ever called for prims which are not currently part of the scene (and hence
1656 // not accessible by clients), there should be no need to lock
1657 List<SceneObjectPart> partsList = new List<SceneObjectPart>(m_parts.Values);
1658 m_parts.Clear();
1659 foreach (SceneObjectPart part in partsList)
1660 {
1661 part.ResetIDs(part.LinkNum); // Don't change link nums
1662 m_parts.Add(part.UUID, part);
1663 }
1664 }
1665
1666 /// <summary>
1667 ///
1668 /// </summary>
1669 /// <param name="part"></param>
1670 public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags)
1671 {
1672
1673 remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.ObjectOwner, RootPart.GroupID, RootPart.BaseMask,
1674 RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask,
1675 RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category,
1676 RootPart.CreatorID, RootPart.Name, RootPart.Description);
1677 }
1678
1679 public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
1680 {
1681 part.OwnerID = cAgentID;
1682 part.GroupID = cGroupID;
1683 }
1684
1685 #endregion
1686
1687 #region Scheduling
1688
1689 public override void Update()
1690 {
1691 // Check that the group was not deleted before the scheduled update
1692 // FIXME: This is merely a temporary measure to reduce the incidence of failure when
1693 // an object has been deleted from a scene before update was processed.
1694 // A more fundamental overhaul of the update mechanism is required to eliminate all
1695 // the race conditions.
1696 if (m_isDeleted)
1697 return;
1698
1699 // This is what happens when an orphanced link set child prim's
1700 // group was queued when it was linked
1701 //
1702 if (m_rootPart == null)
1703 return;
1704
1705 lock (m_parts)
1706 {
1707 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1708
1709 //if (IsAttachment)
1710 //{
1711 //foreach (SceneObjectPart part in m_parts.Values)
1712 //{
1713 //part.SendScheduledUpdates();
1714 //}
1715 //return;
1716 //}
1717
1718 if ((Util.GetDistanceTo(lastPhysGroupPos, AbsolutePosition) > 0.02) && UsePhysics)
1719 {
1720 m_rootPart.UpdateFlag = 1;
1721 lastPhysGroupPos = AbsolutePosition;
1722 }
1723 //foreach (SceneObjectPart part in m_parts.Values)
1724 //{
1725 //if (part.UpdateFlag == 0) part.UpdateFlag = 1;
1726 //}
1727
1728 checkAtTargets();
1729
1730 if (((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1)
1731 || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1)
1732 || (Math.Abs(lastPhysGroupRot.Y - GroupRotation.Y) > 0.1)
1733 || (Math.Abs(lastPhysGroupRot.Z - GroupRotation.Z) > 0.1))
1734 && UsePhysics)
1735 {
1736 m_rootPart.UpdateFlag = 1;
1737
1738 lastPhysGroupRot = GroupRotation;
1739 }
1740
1741 foreach (SceneObjectPart part in m_parts.Values)
1742 {
1743 part.SendScheduledUpdates();
1744 }
1745 }
1746 }
1747
1748 public void ScheduleFullUpdateToAvatar(ScenePresence presence)
1749 {
1750 RootPart.AddFullUpdateToAvatar(presence);
1751
1752 lock (m_parts)
1753 {
1754 foreach (SceneObjectPart part in m_parts.Values)
1755 {
1756 if (part != RootPart)
1757 part.AddFullUpdateToAvatar(presence);
1758 }
1759 }
1760 }
1761
1762 public void ScheduleTerseUpdateToAvatar(ScenePresence presence)
1763 {
1764 lock (m_parts)
1765 {
1766 foreach (SceneObjectPart part in m_parts.Values)
1767 {
1768 part.AddTerseUpdateToAvatar(presence);
1769 }
1770 }
1771 }
1772
1773 /// <summary>
1774 /// Schedule a full update for this scene object
1775 /// </summary>
1776 public void ScheduleGroupForFullUpdate()
1777 {
1778 checkAtTargets();
1779 RootPart.ScheduleFullUpdate();
1780
1781 lock (m_parts)
1782 {
1783 foreach (SceneObjectPart part in m_parts.Values)
1784 {
1785 if (part != RootPart)
1786 part.ScheduleFullUpdate();
1787 }
1788 }
1789 }
1790
1791 /// <summary>
1792 /// Schedule a terse update for this scene object
1793 /// </summary>
1794 public void ScheduleGroupForTerseUpdate()
1795 {
1796 lock (m_parts)
1797 {
1798 foreach (SceneObjectPart part in m_parts.Values)
1799 {
1800 part.ScheduleTerseUpdate();
1801 }
1802 }
1803 }
1804
1805 /// <summary>
1806 /// Immediately send a full update for this scene object.
1807 /// </summary>
1808 public void SendGroupFullUpdate()
1809 {
1810 if (IsDeleted)
1811 return;
1812
1813 RootPart.SendFullUpdateToAllClients();
1814
1815 lock (m_parts)
1816 {
1817 foreach (SceneObjectPart part in m_parts.Values)
1818 {
1819 if (part != RootPart)
1820 part.SendFullUpdateToAllClients();
1821 }
1822 }
1823 }
1824
1825 /// <summary>
1826 /// Immediately send an update for this scene object's root prim only.
1827 /// This is for updates regarding the object as a whole, and none of its parts in particular.
1828 /// Note: this may not be cused by opensim (it probably should) but it's used by
1829 /// external modules.
1830 /// </summary>
1831 public void SendGroupRootUpdate()
1832 {
1833 if (IsDeleted)
1834 return;
1835
1836 RootPart.SendFullUpdateToAllClients();
1837 }
1838
1839 public void QueueForUpdateCheck()
1840 {
1841 if (m_scene == null) // Need to check here as it's null during object creation
1842 return;
1843 m_scene.m_sceneGraph.AddToUpdateList(this);
1844 }
1845
1846 /// <summary>
1847 /// Immediately send a terse update for this scene object.
1848 /// </summary>
1849 public void SendGroupTerseUpdate()
1850 {
1851 if (IsDeleted)
1852 return;
1853
1854 lock (m_parts)
1855 {
1856 foreach (SceneObjectPart part in m_parts.Values)
1857 {
1858 part.SendTerseUpdateToAllClients();
1859 }
1860 }
1861 }
1862
1863 #endregion
1864
1865 #region SceneGroupPart Methods
1866
1867 /// <summary>
1868 /// Get the child part by LinkNum
1869 /// </summary>
1870 /// <param name="linknum"></param>
1871 /// <returns>null if no child part with that linknum or child part</returns>
1872 public SceneObjectPart GetLinkNumPart(int linknum)
1873 {
1874 lock (m_parts)
1875 {
1876 foreach (SceneObjectPart part in m_parts.Values)
1877 {
1878 if (part.LinkNum == linknum)
1879 {
1880 return part;
1881 }
1882 }
1883 }
1884
1885 return null;
1886 }
1887
1888 /// <summary>
1889 /// Get a child part with a given UUID
1890 /// </summary>
1891 /// <param name="primID"></param>
1892 /// <returns>null if a child part with the primID was not found</returns>
1893 public SceneObjectPart GetChildPart(UUID primID)
1894 {
1895 SceneObjectPart childPart = null;
1896 if (m_parts.ContainsKey(primID))
1897 {
1898 childPart = m_parts[primID];
1899 }
1900 return childPart;
1901 }
1902
1903 /// <summary>
1904 /// Get a child part with a given local ID
1905 /// </summary>
1906 /// <param name="localID"></param>
1907 /// <returns>null if a child part with the local ID was not found</returns>
1908 public SceneObjectPart GetChildPart(uint localID)
1909 {
1910 //m_log.DebugFormat("Entered looking for {0}", localID);
1911 lock (m_parts)
1912 {
1913 foreach (SceneObjectPart part in m_parts.Values)
1914 {
1915 //m_log.DebugFormat("Found {0}", part.LocalId);
1916 if (part.LocalId == localID)
1917 {
1918 return part;
1919 }
1920 }
1921 }
1922
1923 return null;
1924 }
1925
1926 /// <summary>
1927 /// Does this group contain the child prim
1928 /// should be able to remove these methods once we have a entity index in scene
1929 /// </summary>
1930 /// <param name="primID"></param>
1931 /// <returns></returns>
1932 public bool HasChildPrim(UUID primID)
1933 {
1934 if (m_parts.ContainsKey(primID))
1935 {
1936 return true;
1937 }
1938
1939 return false;
1940 }
1941
1942 /// <summary>
1943 /// Does this group contain the child prim
1944 /// should be able to remove these methods once we have a entity index in scene
1945 /// </summary>
1946 /// <param name="localID"></param>
1947 /// <returns></returns>
1948 public bool HasChildPrim(uint localID)
1949 {
1950 //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID);
1951 lock (m_parts)
1952 {
1953 foreach (SceneObjectPart part in m_parts.Values)
1954 {
1955 //m_log.DebugFormat("Found {0}", part.LocalId);
1956 if (part.LocalId == localID)
1957 {
1958 return true;
1959 }
1960 }
1961 }
1962
1963 return false;
1964 }
1965
1966 #endregion
1967
1968 #region Packet Handlers
1969
1970 /// <summary>
1971 /// Link the prims in a given group to this group
1972 /// </summary>
1973 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
1974 public void LinkToGroup(SceneObjectGroup objectGroup)
1975 {
1976 if (objectGroup.RootPart.UpdateFlag > 0)
1977 {
1978 // I've never actually seen this happen, though I think it's theoretically possible
1979 m_log.WarnFormat(
1980 "[SCENE OBJECT GROUP]: Aborted linking {0}, {1} to {2}, {3} as it has yet to finish delinking",
1981 objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
1982
1983 return;
1984 }
1985
1986// m_log.DebugFormat(
1987// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
1988// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
1989
1990 SceneObjectPart linkPart = objectGroup.m_rootPart;
1991
1992 Vector3 oldGroupPosition = linkPart.GroupPosition;
1993 Quaternion oldRootRotation = linkPart.RotationOffset;
1994
1995 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
1996 linkPart.GroupPosition = AbsolutePosition;
1997 Vector3 axPos = linkPart.OffsetPosition;
1998
1999 Quaternion parentRot = m_rootPart.RotationOffset;
2000 axPos *= Quaternion.Inverse(parentRot);
2001
2002 linkPart.OffsetPosition = axPos;
2003 Quaternion oldRot = linkPart.RotationOffset;
2004 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot;
2005 linkPart.RotationOffset = newRot;
2006
2007 linkPart.ParentID = m_rootPart.LocalId;
2008 if (m_rootPart.LinkNum == 0)
2009 m_rootPart.LinkNum = 1;
2010
2011 lock (m_parts)
2012 {
2013 m_parts.Add(linkPart.UUID, linkPart);
2014
2015 // Insert in terms of link numbers, the new links
2016 // before the current ones (with the exception of
2017 // the root prim. Shuffle the old ones up
2018 foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts)
2019 {
2020 if (kvp.Value.LinkNum != 1)
2021 {
2022 // Don't update root prim link number
2023 kvp.Value.LinkNum += objectGroup.PrimCount;
2024 }
2025 }
2026
2027 linkPart.LinkNum = 2;
2028
2029 linkPart.SetParent(this);
2030 linkPart.AddFlag(PrimFlags.CreateSelected);
2031
2032 //if (linkPart.PhysActor != null)
2033 //{
2034 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
2035
2036 //linkPart.PhysActor = null;
2037 //}
2038
2039 //TODO: rest of parts
2040 int linkNum = 3;
2041 foreach (SceneObjectPart part in objectGroup.Children.Values)
2042 {
2043 if (part.UUID != objectGroup.m_rootPart.UUID)
2044 {
2045 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2046 }
2047 part.ClearUndoState();
2048 }
2049 }
2050
2051 m_scene.UnlinkSceneObject(objectGroup.UUID, true);
2052 objectGroup.m_isDeleted = true;
2053
2054 lock (objectGroup.m_parts)
2055 {
2056 objectGroup.m_parts.Clear();
2057 }
2058
2059 // Can't do this yet since backup still makes use of the root part without any synchronization
2060// objectGroup.m_rootPart = null;
2061
2062 AttachToBackup();
2063 HasGroupChanged = true;
2064 ScheduleGroupForFullUpdate();
2065 }
2066
2067 /// <summary>
2068 /// Delink the given prim from this group. The delinked prim is established as
2069 /// an independent SceneObjectGroup.
2070 /// </summary>
2071 /// <param name="partID"></param>
2072 public void DelinkFromGroup(uint partID)
2073 {
2074 DelinkFromGroup(partID, true);
2075 }
2076
2077 /// <summary>
2078 /// Delink the given prim from this group. The delinked prim is established as
2079 /// an independent SceneObjectGroup.
2080 /// </summary>
2081 /// <param name="partID"></param>
2082 /// <param name="sendEvents"></param>
2083 public void DelinkFromGroup(uint partID, bool sendEvents)
2084 {
2085 SceneObjectPart linkPart = GetChildPart(partID);
2086
2087 if (null != linkPart)
2088 {
2089 linkPart.ClearUndoState();
2090// m_log.DebugFormat(
2091// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2092// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2093
2094 Quaternion worldRot = linkPart.GetWorldRotation();
2095
2096 // Remove the part from this object
2097 lock (m_parts)
2098 {
2099 m_parts.Remove(linkPart.UUID);
2100 }
2101
2102 if (m_parts.Count == 1 && RootPart != null) //Single prim is left
2103 RootPart.LinkNum = 0;
2104 else
2105 {
2106 foreach (SceneObjectPart p in m_parts.Values)
2107 {
2108 if (p.LinkNum > linkPart.LinkNum)
2109 p.LinkNum--;
2110 }
2111 }
2112
2113 linkPart.ParentID = 0;
2114 linkPart.LinkNum = 0;
2115
2116 if (linkPart.PhysActor != null)
2117 {
2118 m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
2119 }
2120
2121 // We need to reset the child part's position
2122 // ready for life as a separate object after being a part of another object
2123 Quaternion parentRot = m_rootPart.RotationOffset;
2124
2125 Vector3 axPos = linkPart.OffsetPosition;
2126
2127 axPos *= parentRot;
2128 linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z);
2129 linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition;
2130 linkPart.OffsetPosition = new Vector3(0, 0, 0);
2131
2132 linkPart.RotationOffset = worldRot;
2133
2134 SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart);
2135
2136 m_scene.AddNewSceneObject(objectGroup, true);
2137
2138 if (sendEvents)
2139 linkPart.TriggerScriptChangedEvent(Changed.LINK);
2140
2141 linkPart.Rezzed = RootPart.Rezzed;
2142
2143 HasGroupChanged = true;
2144 ScheduleGroupForFullUpdate();
2145 }
2146 else
2147 {
2148 m_log.InfoFormat("[SCENE OBJECT GROUP]: " +
2149 "DelinkFromGroup(): Child prim {0} not found in object {1}, {2}",
2150 partID, LocalId, UUID);
2151 }
2152 }
2153
2154 /// <summary>
2155 /// Stop this object from being persisted over server restarts.
2156 /// </summary>
2157 /// <param name="objectGroup"></param>
2158 public void DetachFromBackup()
2159 {
2160 if (m_isBackedUp)
2161 m_scene.EventManager.OnBackup -= ProcessBackup;
2162
2163 m_isBackedUp = false;
2164 }
2165
2166 private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum)
2167 {
2168
2169 Quaternion parentRot = oldGroupRotation;
2170 Quaternion oldRot = part.RotationOffset;
2171 Quaternion worldRot = parentRot * oldRot;
2172
2173 parentRot = oldGroupRotation;
2174
2175 Vector3 axPos = part.OffsetPosition;
2176
2177 axPos *= parentRot;
2178 part.OffsetPosition = axPos;
2179 part.GroupPosition = oldGroupPosition + part.OffsetPosition;
2180 part.OffsetPosition = Vector3.Zero;
2181 part.RotationOffset = worldRot;
2182
2183 part.SetParent(this);
2184 part.ParentID = m_rootPart.LocalId;
2185
2186 // Caller locks m_parts for us
2187 m_parts.Add(part.UUID, part);
2188
2189 part.LinkNum = linkNum;
2190
2191
2192 part.OffsetPosition = part.GroupPosition - AbsolutePosition;
2193
2194 Quaternion rootRotation = m_rootPart.RotationOffset;
2195
2196 Vector3 pos = part.OffsetPosition;
2197 pos *= Quaternion.Inverse(rootRotation);
2198 part.OffsetPosition = pos;
2199
2200 parentRot = m_rootPart.RotationOffset;
2201 oldRot = part.RotationOffset;
2202 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot;
2203 part.RotationOffset = newRot;
2204 }
2205
2206 /// <summary>
2207 /// If object is physical, apply force to move it around
2208 /// If object is not physical, just put it at the resulting location
2209 /// </summary>
2210 /// <param name="offset">Always seems to be 0,0,0, so ignoring</param>
2211 /// <param name="pos">New position. We do the math here to turn it into a force</param>
2212 /// <param name="remoteClient"></param>
2213 public void GrabMovement(Vector3 offset, Vector3 pos, IClientAPI remoteClient)
2214 {
2215 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2216 {
2217 if (m_rootPart.PhysActor != null)
2218 {
2219 if (m_rootPart.PhysActor.IsPhysical)
2220 {
2221 Vector3 llmoveforce = pos - AbsolutePosition;
2222 PhysicsVector grabforce = new PhysicsVector(llmoveforce.X, llmoveforce.Y, llmoveforce.Z);
2223 grabforce = (grabforce / 10) * m_rootPart.PhysActor.Mass;
2224 m_rootPart.PhysActor.AddForce(grabforce,true);
2225 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2226 }
2227 else
2228 {
2229 //NonPhysicalGrabMovement(pos);
2230 }
2231 }
2232 else
2233 {
2234 //NonPhysicalGrabMovement(pos);
2235 }
2236 }
2237 }
2238
2239 public void NonPhysicalGrabMovement(Vector3 pos)
2240 {
2241 AbsolutePosition = pos;
2242 m_rootPart.SendTerseUpdateToAllClients();
2243 }
2244
2245 /// <summary>
2246 /// Return metadata about a prim (name, description, sale price, etc.)
2247 /// </summary>
2248 /// <param name="client"></param>
2249 public void GetProperties(IClientAPI client)
2250 {
2251 m_rootPart.GetProperties(client);
2252 }
2253
2254 /// <summary>
2255 /// Set the name of a prim
2256 /// </summary>
2257 /// <param name="name"></param>
2258 /// <param name="localID"></param>
2259 public void SetPartName(string name, uint localID)
2260 {
2261 SceneObjectPart part = GetChildPart(localID);
2262 if (part != null)
2263 {
2264 part.Name = name;
2265 }
2266 }
2267
2268 public void SetPartDescription(string des, uint localID)
2269 {
2270 SceneObjectPart part = GetChildPart(localID);
2271 if (part != null)
2272 {
2273 part.Description = des;
2274 }
2275 }
2276
2277 public void SetPartText(string text, uint localID)
2278 {
2279 SceneObjectPart part = GetChildPart(localID);
2280 if (part != null)
2281 {
2282 part.SetText(text);
2283 }
2284 }
2285
2286 public void SetPartText(string text, UUID partID)
2287 {
2288 SceneObjectPart part = GetChildPart(partID);
2289 if (part != null)
2290 {
2291 part.SetText(text);
2292 }
2293 }
2294
2295 public string GetPartName(uint localID)
2296 {
2297 SceneObjectPart part = GetChildPart(localID);
2298 if (part != null)
2299 {
2300 return part.Name;
2301 }
2302 return String.Empty;
2303 }
2304
2305 public string GetPartDescription(uint localID)
2306 {
2307 SceneObjectPart part = GetChildPart(localID);
2308 if (part != null)
2309 {
2310 return part.Description;
2311 }
2312 return String.Empty;
2313 }
2314
2315 /// <summary>
2316 /// Update prim flags for this group.
2317 /// </summary>
2318 /// <param name="localID"></param>
2319 /// <param name="type"></param>
2320 /// <param name="inUse"></param>
2321 /// <param name="data"></param>
2322 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVolumeDetect)
2323 {
2324 SceneObjectPart selectionPart = GetChildPart(localID);
2325
2326 if (IsTemporary)
2327 {
2328 DetachFromBackup();
2329 // Remove from database and parcel prim count
2330 //
2331 m_scene.DeleteFromStorage(UUID);
2332 m_scene.EventManager.TriggerParcelPrimCountTainted();
2333 }
2334
2335 if (selectionPart != null)
2336 {
2337 lock (m_parts)
2338 {
2339 foreach (SceneObjectPart part in m_parts.Values)
2340 {
2341 if (part.Scale.X > 10.0 || part.Scale.Y > 10.0 || part.Scale.Z > 10.0)
2342 {
2343 UsePhysics = false; // Reset physics
2344 break;
2345 }
2346 }
2347
2348 foreach (SceneObjectPart part in m_parts.Values)
2349 {
2350 part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2351 }
2352 }
2353 }
2354 }
2355
2356 public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data)
2357 {
2358 SceneObjectPart part = GetChildPart(localID);
2359 if (part != null)
2360 {
2361 part.UpdateExtraParam(type, inUse, data);
2362 }
2363 }
2364
2365 /// <summary>
2366 /// Get the parts of this scene object
2367 /// </summary>
2368 /// <returns></returns>
2369 public SceneObjectPart[] GetParts()
2370 {
2371 int numParts = Children.Count;
2372 SceneObjectPart[] partArray = new SceneObjectPart[numParts];
2373 Children.Values.CopyTo(partArray, 0);
2374 return partArray;
2375 }
2376
2377 /// <summary>
2378 /// Update the texture entry for this part
2379 /// </summary>
2380 /// <param name="localID"></param>
2381 /// <param name="textureEntry"></param>
2382 public void UpdateTextureEntry(uint localID, byte[] textureEntry)
2383 {
2384 SceneObjectPart part = GetChildPart(localID);
2385 if (part != null)
2386 {
2387 part.UpdateTextureEntry(textureEntry);
2388 }
2389 }
2390
2391 public void UpdatePermissions(UUID AgentID, byte field, uint localID,
2392 uint mask, byte addRemTF)
2393 {
2394 foreach (SceneObjectPart part in m_parts.Values)
2395 part.UpdatePermissions(AgentID, field, localID, mask,
2396 addRemTF);
2397
2398 HasGroupChanged = true;
2399 }
2400
2401 #endregion
2402
2403 #region Shape
2404
2405 /// <summary>
2406 ///
2407 /// </summary>
2408 /// <param name="shapeBlock"></param>
2409 public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock, uint localID)
2410 {
2411 SceneObjectPart part = GetChildPart(localID);
2412 if (part != null)
2413 {
2414 part.UpdateShape(shapeBlock);
2415
2416 if (part.PhysActor != null)
2417 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2418 }
2419 }
2420
2421 #endregion
2422
2423 #region Resize
2424
2425 /// <summary>
2426 /// Resize the given part
2427 /// </summary>
2428 /// <param name="scale"></param>
2429 /// <param name="localID"></param>
2430 public void Resize(Vector3 scale, uint localID)
2431 {
2432 if (scale.X > m_scene.m_maxNonphys)
2433 scale.X = m_scene.m_maxNonphys;
2434 if (scale.Y > m_scene.m_maxNonphys)
2435 scale.Y = m_scene.m_maxNonphys;
2436 if (scale.Z > m_scene.m_maxNonphys)
2437 scale.Z = m_scene.m_maxNonphys;
2438
2439 SceneObjectPart part = GetChildPart(localID);
2440 if (part != null)
2441 {
2442 part.Resize(scale);
2443 if (part.PhysActor != null)
2444 {
2445 if (part.PhysActor.IsPhysical)
2446 {
2447 if (scale.X > m_scene.m_maxPhys)
2448 scale.X = m_scene.m_maxPhys;
2449 if (scale.Y > m_scene.m_maxPhys)
2450 scale.Y = m_scene.m_maxPhys;
2451 if (scale.Z > m_scene.m_maxPhys)
2452 scale.Z = m_scene.m_maxPhys;
2453 }
2454 part.PhysActor.Size =
2455 new PhysicsVector(scale.X, scale.Y, scale.Z);
2456 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2457 }
2458 //if (part.UUID != m_rootPart.UUID)
2459
2460 HasGroupChanged = true;
2461 ScheduleGroupForFullUpdate();
2462
2463 //if (part.UUID == m_rootPart.UUID)
2464 //{
2465 //if (m_rootPart.PhysActor != null)
2466 //{
2467 //m_rootPart.PhysActor.Size =
2468 //new PhysicsVector(m_rootPart.Scale.X, m_rootPart.Scale.Y, m_rootPart.Scale.Z);
2469 //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2470 //}
2471 //}
2472 }
2473 }
2474
2475 public void GroupResize(Vector3 scale, uint localID)
2476 {
2477 SceneObjectPart part = GetChildPart(localID);
2478 if (part != null)
2479 {
2480 if (scale.X > m_scene.m_maxNonphys)
2481 scale.X = m_scene.m_maxNonphys;
2482 if (scale.Y > m_scene.m_maxNonphys)
2483 scale.Y = m_scene.m_maxNonphys;
2484 if (scale.Z > m_scene.m_maxNonphys)
2485 scale.Z = m_scene.m_maxNonphys;
2486 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2487 {
2488 if (scale.X > m_scene.m_maxPhys)
2489 scale.X = m_scene.m_maxPhys;
2490 if (scale.Y > m_scene.m_maxPhys)
2491 scale.Y = m_scene.m_maxPhys;
2492 if (scale.Z > m_scene.m_maxPhys)
2493 scale.Z = m_scene.m_maxPhys;
2494 }
2495 float x = (scale.X / part.Scale.X);
2496 float y = (scale.Y / part.Scale.Y);
2497 float z = (scale.Z / part.Scale.Z);
2498
2499 lock (m_parts)
2500 {
2501 if (x > 1.0f || y > 1.0f || z > 1.0f)
2502 {
2503 foreach (SceneObjectPart obPart in m_parts.Values)
2504 {
2505 if (obPart.UUID != m_rootPart.UUID)
2506 {
2507 Vector3 oldSize = new Vector3(obPart.Scale);
2508
2509 float f = 1.0f;
2510 float a = 1.0f;
2511
2512 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2513 {
2514 if (oldSize.X*x > m_scene.m_maxPhys)
2515 {
2516 f = m_scene.m_maxPhys / oldSize.X;
2517 a = f / x;
2518 x *= a;
2519 y *= a;
2520 z *= a;
2521 }
2522 if (oldSize.Y*y > m_scene.m_maxPhys)
2523 {
2524 f = m_scene.m_maxPhys / oldSize.Y;
2525 a = f / y;
2526 x *= a;
2527 y *= a;
2528 z *= a;
2529 }
2530 if (oldSize.Z*z > m_scene.m_maxPhys)
2531 {
2532 f = m_scene.m_maxPhys / oldSize.Z;
2533 a = f / z;
2534 x *= a;
2535 y *= a;
2536 z *= a;
2537 }
2538 }
2539 else
2540 {
2541 if (oldSize.X*x > m_scene.m_maxNonphys)
2542 {
2543 f = m_scene.m_maxNonphys / oldSize.X;
2544 a = f / x;
2545 x *= a;
2546 y *= a;
2547 z *= a;
2548 }
2549 if (oldSize.Y*y > m_scene.m_maxNonphys)
2550 {
2551 f = m_scene.m_maxNonphys / oldSize.Y;
2552 a = f / y;
2553 x *= a;
2554 y *= a;
2555 z *= a;
2556 }
2557 if (oldSize.Z*z > m_scene.m_maxNonphys)
2558 {
2559 f = m_scene.m_maxNonphys / oldSize.Z;
2560 a = f / z;
2561 x *= a;
2562 y *= a;
2563 z *= a;
2564 }
2565 }
2566 }
2567 }
2568 }
2569 }
2570
2571 Vector3 prevScale = part.Scale;
2572 prevScale.X *= x;
2573 prevScale.Y *= y;
2574 prevScale.Z *= z;
2575 part.Resize(prevScale);
2576
2577 lock (m_parts)
2578 {
2579 foreach (SceneObjectPart obPart in m_parts.Values)
2580 {
2581 if (obPart.UUID != m_rootPart.UUID)
2582 {
2583 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2584 currentpos.X *= x;
2585 currentpos.Y *= y;
2586 currentpos.Z *= z;
2587 Vector3 newSize = new Vector3(obPart.Scale);
2588 newSize.X *= x;
2589 newSize.Y *= y;
2590 newSize.Z *= z;
2591 obPart.Resize(newSize);
2592 obPart.UpdateOffSet(currentpos);
2593 }
2594 }
2595 }
2596
2597 if (part.PhysActor != null)
2598 {
2599 part.PhysActor.Size =
2600 new PhysicsVector(prevScale.X, prevScale.Y, prevScale.Z);
2601 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2602 }
2603
2604 HasGroupChanged = true;
2605 ScheduleGroupForTerseUpdate();
2606 }
2607 }
2608
2609 #endregion
2610
2611 #region Position
2612
2613 /// <summary>
2614 /// Move this scene object
2615 /// </summary>
2616 /// <param name="pos"></param>
2617 public void UpdateGroupPosition(Vector3 pos)
2618 {
2619 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2620 {
2621 if (IsAttachment)
2622 {
2623 m_rootPart.AttachedPos = pos;
2624 }
2625
2626 AbsolutePosition = pos;
2627
2628 HasGroupChanged = true;
2629 }
2630
2631 //we need to do a terse update even if the move wasn't allowed
2632 // so that the position is reset in the client (the object snaps back)
2633 ScheduleGroupForTerseUpdate();
2634 }
2635
2636 /// <summary>
2637 /// Update the position of a single part of this scene object
2638 /// </summary>
2639 /// <param name="pos"></param>
2640 /// <param name="localID"></param>
2641 public void UpdateSinglePosition(Vector3 pos, uint localID)
2642 {
2643 SceneObjectPart part = GetChildPart(localID);
2644
2645 if (part != null)
2646 {
2647 if (part.UUID == m_rootPart.UUID)
2648 {
2649 UpdateRootPosition(pos);
2650 }
2651 else
2652 {
2653 part.UpdateOffSet(pos);
2654 }
2655
2656 HasGroupChanged = true;
2657 }
2658 }
2659
2660 /// <summary>
2661 ///
2662 /// </summary>
2663 /// <param name="pos"></param>
2664 private void UpdateRootPosition(Vector3 pos)
2665 {
2666 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2667 Vector3 oldPos =
2668 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
2669 AbsolutePosition.Y + m_rootPart.OffsetPosition.Y,
2670 AbsolutePosition.Z + m_rootPart.OffsetPosition.Z);
2671 Vector3 diff = oldPos - newPos;
2672 Vector3 axDiff = new Vector3(diff.X, diff.Y, diff.Z);
2673 Quaternion partRotation = m_rootPart.RotationOffset;
2674 axDiff *= Quaternion.Inverse(partRotation);
2675 diff = axDiff;
2676
2677 lock (m_parts)
2678 {
2679 foreach (SceneObjectPart obPart in m_parts.Values)
2680 {
2681 if (obPart.UUID != m_rootPart.UUID)
2682 {
2683 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2684 }
2685 }
2686 }
2687
2688 AbsolutePosition = newPos;
2689
2690 HasGroupChanged = true;
2691 ScheduleGroupForTerseUpdate();
2692 }
2693
2694 public void OffsetForNewRegion(Vector3 offset)
2695 {
2696 m_rootPart.GroupPosition = offset;
2697 }
2698
2699 #endregion
2700
2701 #region Rotation
2702
2703 /// <summary>
2704 ///
2705 /// </summary>
2706 /// <param name="rot"></param>
2707 public void UpdateGroupRotation(Quaternion rot)
2708 {
2709 m_rootPart.UpdateRotation(rot);
2710 if (m_rootPart.PhysActor != null)
2711 {
2712 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
2713 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2714 }
2715
2716 HasGroupChanged = true;
2717 ScheduleGroupForTerseUpdate();
2718 }
2719
2720 /// <summary>
2721 ///
2722 /// </summary>
2723 /// <param name="pos"></param>
2724 /// <param name="rot"></param>
2725 public void UpdateGroupRotation(Vector3 pos, Quaternion rot)
2726 {
2727 m_rootPart.UpdateRotation(rot);
2728 if (m_rootPart.PhysActor != null)
2729 {
2730 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
2731 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2732 }
2733 AbsolutePosition = pos;
2734
2735 HasGroupChanged = true;
2736 ScheduleGroupForTerseUpdate();
2737 }
2738
2739 /// <summary>
2740 ///
2741 /// </summary>
2742 /// <param name="rot"></param>
2743 /// <param name="localID"></param>
2744 public void UpdateSingleRotation(Quaternion rot, uint localID)
2745 {
2746 SceneObjectPart part = GetChildPart(localID);
2747 if (part != null)
2748 {
2749 if (part.UUID == m_rootPart.UUID)
2750 {
2751 UpdateRootRotation(rot);
2752 }
2753 else
2754 {
2755 part.UpdateRotation(rot);
2756 }
2757 }
2758 }
2759
2760 /// <summary>
2761 ///
2762 /// </summary>
2763 /// <param name="rot"></param>
2764 private void UpdateRootRotation(Quaternion rot)
2765 {
2766 Quaternion axRot = rot;
2767 Quaternion oldParentRot = m_rootPart.RotationOffset;
2768
2769 m_rootPart.UpdateRotation(rot);
2770 if (m_rootPart.PhysActor != null)
2771 {
2772 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
2773 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2774 }
2775
2776 lock (m_parts)
2777 {
2778 foreach (SceneObjectPart prim in m_parts.Values)
2779 {
2780 if (prim.UUID != m_rootPart.UUID)
2781 {
2782 Vector3 axPos = prim.OffsetPosition;
2783 axPos *= oldParentRot;
2784 axPos *= Quaternion.Inverse(axRot);
2785 prim.OffsetPosition = axPos;
2786 Quaternion primsRot = prim.RotationOffset;
2787 Quaternion newRot = primsRot * oldParentRot;
2788 newRot *= Quaternion.Inverse(axRot);
2789 prim.RotationOffset = newRot;
2790 prim.ScheduleTerseUpdate();
2791 }
2792 }
2793 }
2794
2795 m_rootPart.ScheduleTerseUpdate();
2796 }
2797
2798 #endregion
2799
2800 internal void SetAxisRotation(int axis, int rotate10)
2801 {
2802 bool setX = false;
2803 bool setY = false;
2804 bool setZ = false;
2805
2806 int xaxis = 2;
2807 int yaxis = 4;
2808 int zaxis = 8;
2809
2810 if (m_rootPart != null)
2811 {
2812 setX = ((axis & xaxis) != 0) ? true : false;
2813 setY = ((axis & yaxis) != 0) ? true : false;
2814 setZ = ((axis & zaxis) != 0) ? true : false;
2815
2816 float setval = (rotate10 > 0) ? 1f : 0f;
2817
2818 if (setX)
2819 m_rootPart.RotationAxis.X = setval;
2820 if (setY)
2821 m_rootPart.RotationAxis.Y = setval;
2822 if (setZ)
2823 m_rootPart.RotationAxis.Z = setval;
2824
2825 if (setX || setY || setZ)
2826 {
2827 m_rootPart.SetPhysicsAxisRotation();
2828 }
2829
2830 }
2831 }
2832
2833 public int registerTargetWaypoint(Vector3 target, float tolerance)
2834 {
2835 scriptPosTarget waypoint = new scriptPosTarget();
2836 waypoint.targetPos = target;
2837 waypoint.tolerance = tolerance;
2838 uint handle = m_scene.AllocateLocalId();
2839 lock (m_targets)
2840 {
2841 m_targets.Add(handle, waypoint);
2842 }
2843 return (int)handle;
2844 }
2845
2846 public void unregisterTargetWaypoint(int handle)
2847 {
2848 lock (m_targets)
2849 {
2850 if (m_targets.ContainsKey((uint)handle))
2851 m_targets.Remove((uint)handle);
2852 }
2853 }
2854
2855 private void checkAtTargets()
2856 {
2857 if (m_scriptListens_atTarget || m_scriptListens_notAtTarget)
2858 {
2859 if (m_targets.Count > 0)
2860 {
2861 bool at_target = false;
2862 //Vector3 targetPos;
2863 //uint targetHandle;
2864 Dictionary<uint, scriptPosTarget> atTargets = new Dictionary<uint, scriptPosTarget>();
2865 lock (m_targets)
2866 {
2867 foreach (uint idx in m_targets.Keys)
2868 {
2869 scriptPosTarget target = m_targets[idx];
2870 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
2871 {
2872 // trigger at_target
2873 if (m_scriptListens_atTarget)
2874 {
2875 // Reusing att.tolerance to hold the index of the target in the targets dictionary
2876 // to avoid deadlocking the sim.
2877 at_target = true;
2878 scriptPosTarget att = new scriptPosTarget();
2879 att.targetPos = target.targetPos;
2880 att.tolerance = (float)idx;
2881 atTargets.Add(idx, att);
2882 }
2883 }
2884 }
2885 }
2886 if (atTargets.Count > 0)
2887 {
2888 uint[] localids = new uint[0];
2889 lock (m_parts)
2890 {
2891 localids = new uint[m_parts.Count];
2892 int cntr = 0;
2893 foreach (SceneObjectPart part in m_parts.Values)
2894 {
2895 localids[cntr] = part.LocalId;
2896 cntr++;
2897 }
2898 }
2899 for (int ctr = 0; ctr < localids.Length; ctr++)
2900 {
2901 foreach (uint target in atTargets.Keys)
2902 {
2903 scriptPosTarget att = atTargets[target];
2904 // Reusing att.tolerance to hold the index of the target in the targets dictionary
2905 // to avoid deadlocking the sim.
2906 m_scene.TriggerAtTargetEvent(localids[ctr], (uint)att.tolerance, att.targetPos, m_rootPart.GroupPosition);
2907
2908
2909 }
2910 }
2911 return;
2912 }
2913 if (m_scriptListens_notAtTarget && !at_target)
2914 {
2915 //trigger not_at_target
2916 uint[] localids = new uint[0];
2917 lock (m_parts)
2918 {
2919 localids = new uint[m_parts.Count];
2920 int cntr = 0;
2921 foreach (SceneObjectPart part in m_parts.Values)
2922 {
2923 localids[cntr] = part.LocalId;
2924 cntr++;
2925 }
2926 }
2927 for (int ctr = 0; ctr < localids.Length; ctr++)
2928 {
2929 m_scene.TriggerNotAtTargetEvent(localids[ctr]);
2930 }
2931 }
2932 }
2933 }
2934 }
2935
2936 public float GetMass()
2937 {
2938 float retmass = 0f;
2939 lock (m_parts)
2940 {
2941 foreach (SceneObjectPart part in m_parts.Values)
2942 {
2943 retmass += part.GetMass();
2944 }
2945 }
2946 return retmass;
2947 }
2948
2949 public void CheckSculptAndLoad()
2950 {
2951 lock (m_parts)
2952 {
2953 if (!IsDeleted)
2954 {
2955 if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) == 0)
2956 {
2957 foreach (SceneObjectPart part in m_parts.Values)
2958 {
2959 if (part.Shape.SculptEntry && part.Shape.SculptTexture != UUID.Zero)
2960 {
2961 m_scene.AssetCache.GetAsset(part.Shape.SculptTexture, part.SculptTextureCallback, true);
2962 }
2963 }
2964 }
2965 }
2966 }
2967 }
2968
2969 /// <summary>
2970 /// Set the user group to which this scene object belongs.
2971 /// </summary>
2972 /// <param name="GroupID"></param>
2973 /// <param name="client"></param>
2974 public void SetGroup(UUID GroupID, IClientAPI client)
2975 {
2976 lock (m_parts)
2977 {
2978 foreach (SceneObjectPart part in m_parts.Values)
2979 {
2980 part.SetGroup(GroupID, client);
2981 part.Inventory.ChangeInventoryGroup(GroupID);
2982 }
2983
2984 HasGroupChanged = true;
2985 }
2986
2987 ScheduleGroupForFullUpdate();
2988 }
2989
2990 public void TriggerScriptChangedEvent(Changed val)
2991 {
2992 foreach (SceneObjectPart part in Children.Values)
2993 {
2994 part.TriggerScriptChangedEvent(val);
2995 }
2996 }
2997
2998 public override string ToString()
2999 {
3000 return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition);
3001 }
3002
3003 public void SetAttachmentPoint(byte point)
3004 {
3005 lock (m_parts)
3006 {
3007 foreach (SceneObjectPart part in m_parts.Values)
3008 part.SetAttachmentPoint(point);
3009 }
3010 }
3011 }
3012}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
new file mode 100644
index 0000000..dfa9318
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -0,0 +1,3826 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Drawing;
31using System.Reflection;
32using System.Runtime.Serialization;
33using System.Security.Permissions;
34using System.Xml;
35using System.Xml.Serialization;
36using log4net;
37using OpenMetaverse;
38using OpenMetaverse.Packets;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes.Scripting;
42using OpenSim.Region.Physics.Manager;
43
44namespace OpenSim.Region.Framework.Scenes
45{
46 #region Enumerations
47
48 [Flags]
49 public enum Changed : uint
50 {
51 INVENTORY = 1,
52 COLOR = 2,
53 SHAPE = 4,
54 SCALE = 8,
55 TEXTURE = 16,
56 LINK = 32,
57 ALLOWED_DROP = 64,
58 OWNER = 128,
59 REGION_RESTART = 256,
60 REGION = 512,
61 TELEPORT = 1024
62 }
63
64 // I don't really know where to put this except here.
65 // Can't access the OpenSim.Region.ScriptEngine.Common.LSL_BaseClass.Changed constants
66 [Flags]
67 public enum ExtraParamType
68 {
69 Something1 = 1,
70 Something2 = 2,
71 Something3 = 4,
72 Something4 = 8,
73 Flexible = 16,
74 Light = 32,
75 Sculpt = 48,
76 Something5 = 64,
77 Something6 = 128
78 }
79
80 [Flags]
81 public enum TextureAnimFlags : byte
82 {
83 NONE = 0x00,
84 ANIM_ON = 0x01,
85 LOOP = 0x02,
86 REVERSE = 0x04,
87 PING_PONG = 0x08,
88 SMOOTH = 0x10,
89 ROTATE = 0x20,
90 SCALE = 0x40
91 }
92
93 #endregion Enumerations
94
95 [Serializable]
96 public class SceneObjectPart : IScriptHost, ISerializable
97 {
98 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
99
100 // use only one serializer to give the runtime a chance to optimize it (it won't do that if you
101 // use a new instance every time)
102 private static XmlSerializer serializer = new XmlSerializer(typeof (SceneObjectPart));
103
104 #region Fields
105
106 [XmlIgnore]
107 public bool AllowedDrop = false;
108
109 [XmlIgnore]
110 public bool DIE_AT_EDGE = false;
111
112 // TODO: This needs to be persisted in next XML version update!
113 [XmlIgnore]
114 public int[] PayPrice = {-2,-2,-2,-2,-2};
115 [XmlIgnore]
116 public PhysicsActor PhysActor = null;
117
118 //Xantor 20080528 Sound stuff:
119 // Note: This isn't persisted in the database right now, as the fields for that aren't just there yet.
120 // Not a big problem as long as the script that sets it remains in the prim on startup.
121 // for SL compatibility it should be persisted though (set sound / displaytext / particlesystem, kill script)
122 [XmlIgnore]
123 public UUID Sound;
124
125 [XmlIgnore]
126 public byte SoundFlags;
127
128 [XmlIgnore]
129 public double SoundGain;
130
131 [XmlIgnore]
132 public double SoundRadius;
133
134 [XmlIgnore]
135 public uint TimeStampFull = 0;
136
137 [XmlIgnore]
138 public uint TimeStampLastActivity = 0; // Will be used for AutoReturn
139
140 [XmlIgnore]
141 public uint TimeStampTerse = 0;
142
143 [XmlIgnore]
144 public UUID FromAssetID = UUID.Zero;
145
146 /// <value>
147 /// The UUID of the user inventory item from which this object was rezzed if this is a root part.
148 /// If UUID.Zero then either this is not a root part or there is no connection with a user inventory item.
149 /// </value>
150 private UUID m_fromUserInventoryItemID = UUID.Zero;
151
152 [XmlIgnore]
153 public UUID FromUserInventoryItemID
154 {
155 get { return m_fromUserInventoryItemID; }
156 }
157
158 [XmlIgnore]
159 public bool IsAttachment = false;
160
161 [XmlIgnore]
162 public scriptEvents AggregateScriptEvents = 0;
163
164 [XmlIgnore]
165 public UUID AttachedAvatar = UUID.Zero;
166
167 [XmlIgnore]
168 public Vector3 AttachedPos = Vector3.Zero;
169
170 [XmlIgnore]
171 public uint AttachmentPoint = (byte)0;
172
173 [XmlIgnore]
174 public PhysicsVector RotationAxis = new PhysicsVector(1f,1f,1f);
175
176 [XmlIgnore]
177 public bool VolumeDetectActive = false; // XmlIgnore set to avoid problems with persistance until I come to care for this
178 // Certainly this must be a persistant setting finally
179
180 /// <summary>
181 /// This part's inventory
182 /// </summary>
183 [XmlIgnore]
184 public IEntityInventory Inventory
185 {
186 get { return m_inventory; }
187 }
188 protected SceneObjectPartInventory m_inventory;
189
190 [XmlIgnore]
191 public bool Undoing = false;
192
193 [XmlIgnore]
194 private PrimFlags LocalFlags = 0;
195 private byte[] m_TextureAnimation;
196 private byte m_clickAction = 0;
197 private Color m_color = Color.Black;
198 private string m_description = String.Empty;
199 private readonly List<uint> m_lastColliders = new List<uint>();
200 // private PhysicsVector m_lastRotationalVelocity = PhysicsVector.Zero;
201 private int m_linkNum = 0;
202 [XmlIgnore]
203 private int m_scriptAccessPin = 0;
204 [XmlIgnore]
205 private readonly Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
206 private string m_sitName = String.Empty;
207 private Quaternion m_sitTargetOrientation = Quaternion.Identity;
208 private Vector3 m_sitTargetPosition = Vector3.Zero;
209 private string m_sitAnimation = "SIT";
210 private string m_text = String.Empty;
211 private string m_touchName = String.Empty;
212 private readonly UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5);
213 private UUID _creatorID;
214
215 /// <summary>
216 /// Only used internally to schedule client updates.
217 /// 0 - no update is scheduled
218 /// 1 - terse update scheduled
219 /// 2 - full update scheduled
220 ///
221 /// TODO - This should be an enumeration
222 /// </summary>
223 private byte m_updateFlag;
224
225 protected Vector3 m_acceleration;
226 protected Vector3 m_angularVelocity;
227
228 //unkown if this will be kept, added as a way of removing the group position from the group class
229 protected Vector3 m_groupPosition;
230 protected uint m_localId;
231 protected Material m_material = (Material)3; // Wood
232 protected string m_name;
233 protected Vector3 m_offsetPosition;
234
235 // FIXME, TODO, ERROR: 'ParentGroup' can't be in here, move it out.
236 protected SceneObjectGroup m_parentGroup;
237 protected byte[] m_particleSystem = new byte[0];
238 protected ulong m_regionHandle;
239 protected Quaternion m_rotationOffset;
240 protected PrimitiveBaseShape m_shape = null;
241 protected UUID m_uuid;
242 protected Vector3 m_velocity;
243
244 // TODO: Those have to be changed into persistent properties at some later point,
245 // or sit-camera on vehicles will break on sim-crossing.
246 private Vector3 m_cameraEyeOffset = new Vector3(0.0f, 0.0f, 0.0f);
247 private Vector3 m_cameraAtOffset = new Vector3(0.0f, 0.0f, 0.0f);
248 private bool m_forceMouselook = false;
249
250 // TODO: Collision sound should have default.
251 private UUID m_collisionSound = UUID.Zero;
252 private float m_collisionSoundVolume = 0.0f;
253
254 #endregion Fields
255
256 #region Constructors
257
258 /// <summary>
259 /// No arg constructor called by region restore db code
260 /// </summary>
261 public SceneObjectPart()
262 {
263 // It's not necessary to persist this
264 m_TextureAnimation = new byte[0];
265 m_particleSystem = new byte[0];
266 Rezzed = DateTime.Now;
267
268 m_inventory = new SceneObjectPartInventory(this);
269 }
270
271 /// <summary>
272 /// Create a completely new SceneObjectPart (prim). This will need to be added separately to a SceneObjectGroup
273 /// </summary>
274 /// <param name="ownerID"></param>
275 /// <param name="shape"></param>
276 /// <param name="position"></param>
277 /// <param name="rotationOffset"></param>
278 /// <param name="offsetPosition"></param>
279 public SceneObjectPart(
280 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition,
281 Quaternion rotationOffset, Vector3 offsetPosition)
282 {
283 m_name = "Primitive";
284
285 Rezzed = DateTime.Now;
286 _creationDate = (Int32) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds;
287 _ownerID = ownerID;
288 _creatorID = _ownerID;
289 _lastOwnerID = UUID.Zero;
290 UUID = UUID.Random();
291 Shape = shape;
292 // Todo: Add More Object Parameter from above!
293 _ownershipCost = 0;
294 _objectSaleType = (byte) 0;
295 _salePrice = 0;
296 _category = (uint) 0;
297 _lastOwnerID = _creatorID;
298 // End Todo: ///
299 GroupPosition = groupPosition;
300 OffsetPosition = offsetPosition;
301 RotationOffset = rotationOffset;
302 Velocity = new Vector3(0, 0, 0);
303 AngularVelocity = new Vector3(0, 0, 0);
304 Acceleration = new Vector3(0, 0, 0);
305 m_TextureAnimation = new byte[0];
306 m_particleSystem = new byte[0];
307
308 // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol,
309 // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from
310 // the prim into an agent inventory (Linden client reports that the "Object not found for drop" in its log
311
312 _flags = 0;
313 _flags |= PrimFlags.CreateSelected;
314
315 TrimPermissions();
316 //m_undo = new UndoStack<UndoState>(ParentGroup.GetSceneMaxUndo());
317
318 m_inventory = new SceneObjectPartInventory(this);
319 }
320
321 protected SceneObjectPart(SerializationInfo info, StreamingContext context)
322 {
323 //System.Console.WriteLine("SceneObjectPart Deserialize BGN");
324 m_TextureAnimation = new byte[0];
325 m_particleSystem = new byte[0];
326 if (info == null)
327 {
328 throw new ArgumentNullException("info");
329 }
330
331 /*
332 m_queue = (Queue<SceneObjectPart>)info.GetValue("m_queue", typeof(Queue<SceneObjectPart>));
333 m_ids = (List<UUID>)info.GetValue("m_ids", typeof(List<UUID>));
334 */
335
336 //System.Console.WriteLine("SceneObjectPart Deserialize END");
337 Rezzed = DateTime.Now;
338
339 m_inventory = new SceneObjectPartInventory(this);
340 }
341
342 #endregion Constructors
343
344 #region XML Schema
345
346 private UUID _lastOwnerID;
347 private UUID _ownerID;
348 private UUID _groupID;
349 private int _ownershipCost;
350 private byte _objectSaleType;
351 private int _salePrice;
352 private uint _category;
353 private Int32 _creationDate;
354 private uint _parentID = 0;
355 private UUID m_sitTargetAvatar = UUID.Zero;
356 private uint _baseMask = (uint)PermissionMask.All;
357 private uint _ownerMask = (uint)PermissionMask.All;
358 private uint _groupMask = (uint)PermissionMask.None;
359 private uint _everyoneMask = (uint)PermissionMask.None;
360 private uint _nextOwnerMask = (uint)PermissionMask.All;
361 private PrimFlags _flags = 0;
362 private DateTime m_expires;
363 private DateTime m_rezzed;
364
365 public UUID CreatorID
366 {
367 get
368 {
369 return _creatorID;
370 }
371 set
372 {
373 _creatorID = value;
374 }
375 }
376
377 /// <summary>
378 /// Exposing this is not particularly good, but it's one of the least evils at the moment to see
379 /// folder id from prim inventory item data, since it's not (yet) actually stored with the prim.
380 /// </summary>
381 public UUID FolderID
382 {
383 get { return UUID; }
384 set { } // Don't allow assignment, or legacy prims wil b0rk
385 }
386
387 /// <value>
388 /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes
389 /// </value>
390 public uint InventorySerial
391 {
392 get { return m_inventory.Serial; }
393 set { m_inventory.Serial = value; }
394 }
395
396 /// <value>
397 /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes
398 /// </value>
399 public TaskInventoryDictionary TaskInventory
400 {
401 get { return m_inventory.Items; }
402 set { m_inventory.Items = value; }
403 }
404
405 public uint ObjectFlags
406 {
407 get { return (uint)_flags; }
408 set { _flags = (PrimFlags)value; }
409 }
410
411 public UUID UUID
412 {
413 get { return m_uuid; }
414 set { m_uuid = value; }
415 }
416
417 public uint LocalId
418 {
419 get { return m_localId; }
420 set { m_localId = value; }
421 }
422
423 public virtual string Name
424 {
425 get { return m_name; }
426 set
427 {
428 m_name = value;
429 if (PhysActor != null)
430 {
431 PhysActor.SOPName = value;
432 }
433 }
434 }
435
436 public byte Material
437 {
438 get { return (byte) m_material; }
439 set { m_material = (Material)value; }
440 }
441
442 public ulong RegionHandle
443 {
444 get { return m_regionHandle; }
445 set { m_regionHandle = value; }
446 }
447
448 public int ScriptAccessPin
449 {
450 get { return m_scriptAccessPin; }
451 set { m_scriptAccessPin = (int)value; }
452 }
453
454 [XmlIgnore]
455 public Byte[] TextureAnimation
456 {
457 get { return m_TextureAnimation; }
458 set { m_TextureAnimation = value; }
459 }
460
461 [XmlIgnore]
462 public Byte[] ParticleSystem
463 {
464 get { return m_particleSystem; }
465 set { m_particleSystem = value; }
466 }
467
468 [XmlIgnore]
469 public DateTime Expires
470 {
471 get { return m_expires; }
472 set { m_expires = value; }
473 }
474
475 [XmlIgnore]
476 public DateTime Rezzed
477 {
478 get { return m_rezzed; }
479 set { m_rezzed = value; }
480 }
481
482 /// <summary>
483 /// The position of the entire group that this prim belongs to.
484 /// </summary>
485 public Vector3 GroupPosition
486 {
487 get
488 {
489 // If this is a linkset, we don't want the physics engine mucking up our group position here.
490 if (PhysActor != null && _parentID == 0)
491 {
492 m_groupPosition.X = PhysActor.Position.X;
493 m_groupPosition.Y = PhysActor.Position.Y;
494 m_groupPosition.Z = PhysActor.Position.Z;
495 }
496
497 if (IsAttachment)
498 {
499 ScenePresence sp = m_parentGroup.Scene.GetScenePresence(AttachedAvatar);
500 if (sp != null)
501 {
502 return sp.AbsolutePosition;
503 }
504 }
505
506 return m_groupPosition;
507 }
508 set
509 {
510 StoreUndoState();
511
512 m_groupPosition = value;
513
514 if (PhysActor != null)
515 {
516 try
517 {
518 // Root prim actually goes at Position
519 if (_parentID == 0)
520 {
521 PhysActor.Position = new PhysicsVector(value.X, value.Y, value.Z);
522 }
523 else
524 {
525 // To move the child prim in respect to the group position and rotation we have to calculate
526 Vector3 resultingposition = GetWorldPosition();
527 PhysActor.Position = new PhysicsVector(resultingposition.X, resultingposition.Y, resultingposition.Z);
528 Quaternion resultingrot = GetWorldRotation();
529 PhysActor.Orientation = resultingrot;
530 }
531
532 // Tell the physics engines that this prim changed.
533 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
534 }
535 catch (Exception e)
536 {
537 Console.WriteLine("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message);
538 }
539 }
540
541 // TODO if we decide to do sitting in a more SL compatible way (multiple avatars per prim), this has to be fixed, too
542 if (m_sitTargetAvatar != UUID.Zero)
543 {
544 if (m_parentGroup != null) // TODO can there be a SOP without a SOG?
545 {
546 ScenePresence avatar;
547 if (m_parentGroup.Scene.TryGetAvatar(m_sitTargetAvatar, out avatar))
548 {
549 avatar.ParentPosition = GetWorldPosition();
550 }
551 }
552 }
553 }
554 }
555
556 public Vector3 OffsetPosition
557 {
558 get { return m_offsetPosition; }
559 set
560 {
561 StoreUndoState();
562 m_offsetPosition = value;
563
564 if (ParentGroup != null && !ParentGroup.IsDeleted)
565 {
566 if (_parentID != 0 && PhysActor != null)
567 {
568 Vector3 resultingposition = GetWorldPosition();
569 PhysActor.Position = new PhysicsVector(resultingposition.X, resultingposition.Y, resultingposition.Z);
570 Quaternion resultingrot = GetWorldRotation();
571 PhysActor.Orientation = resultingrot;
572
573 // Tell the physics engines that this prim changed.
574 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
575 }
576 }
577 }
578 }
579
580 public Quaternion RotationOffset
581 {
582 get
583 {
584 // We don't want the physics engine mucking up the rotations in a linkset
585 if ((_parentID == 0) && (Shape.PCode != 9 || Shape.State == 0) && (PhysActor != null))
586 {
587 if (PhysActor.Orientation.X != 0 || PhysActor.Orientation.Y != 0
588 || PhysActor.Orientation.Z != 0 || PhysActor.Orientation.W != 0)
589 {
590 m_rotationOffset = PhysActor.Orientation;
591 }
592 }
593 return m_rotationOffset;
594 }
595 set
596 {
597 StoreUndoState();
598 m_rotationOffset = value;
599
600 if (PhysActor != null)
601 {
602 try
603 {
604 // Root prim gets value directly
605 if (_parentID == 0)
606 {
607 PhysActor.Orientation = value;
608 //m_log.Info("[PART]: RO1:" + PhysActor.Orientation.ToString());
609 }
610 else
611 {
612 // Child prim we have to calculate it's world rotationwel
613 Quaternion resultingrotation = GetWorldRotation();
614 PhysActor.Orientation = resultingrotation;
615 //m_log.Info("[PART]: RO2:" + PhysActor.Orientation.ToString());
616 }
617 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
618 //}
619 }
620 catch (Exception ex)
621 {
622 Console.WriteLine("[SCENEOBJECTPART]: ROTATIONOFFSET" + ex.Message);
623 }
624 }
625
626 }
627 }
628
629 /// <summary></summary>
630 public Vector3 Velocity
631 {
632 get
633 {
634 //if (PhysActor.Velocity.X != 0 || PhysActor.Velocity.Y != 0
635 //|| PhysActor.Velocity.Z != 0)
636 //{
637 if (PhysActor != null)
638 {
639 if (PhysActor.IsPhysical)
640 {
641 m_velocity.X = PhysActor.Velocity.X;
642 m_velocity.Y = PhysActor.Velocity.Y;
643 m_velocity.Z = PhysActor.Velocity.Z;
644 }
645 }
646
647 return m_velocity;
648 }
649
650 set
651 {
652 m_velocity = value;
653 if (PhysActor != null)
654 {
655 if (PhysActor.IsPhysical)
656 {
657 PhysActor.Velocity = new PhysicsVector(value.X, value.Y, value.Z);
658 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
659 }
660 }
661 }
662 }
663
664 public Vector3 RotationalVelocity
665 {
666 get { return AngularVelocity; }
667 set { AngularVelocity = value; }
668 }
669
670 /// <summary></summary>
671 public Vector3 AngularVelocity
672 {
673 get
674 {
675 if ((PhysActor != null) && PhysActor.IsPhysical)
676 {
677 m_angularVelocity.FromBytes(PhysActor.RotationalVelocity.GetBytes(), 0);
678 }
679 return m_angularVelocity;
680 }
681 set { m_angularVelocity = value; }
682 }
683
684 /// <summary></summary>
685 public Vector3 Acceleration
686 {
687 get { return m_acceleration; }
688 set { m_acceleration = value; }
689 }
690
691 public string Description
692 {
693 get { return m_description; }
694 set
695 {
696 m_description = value;
697 if (PhysActor != null)
698 {
699 PhysActor.SOPDescription = value;
700 }
701 }
702 }
703
704 public Color Color
705 {
706 get { return m_color; }
707 set
708 {
709 m_color = value;
710 TriggerScriptChangedEvent(Changed.COLOR);
711
712 /* ScheduleFullUpdate() need not be called b/c after
713 * setting the color, the text will be set, so then
714 * ScheduleFullUpdate() will be called. */
715 //ScheduleFullUpdate();
716 }
717 }
718
719 public string Text
720 {
721 get
722 {
723 string returnstr = m_text;
724 if (returnstr.Length > 255)
725 {
726 returnstr = returnstr.Substring(0, 254);
727 }
728 return returnstr;
729 }
730 set
731 {
732 m_text = value;
733 }
734 }
735
736
737 public string SitName
738 {
739 get { return m_sitName; }
740 set { m_sitName = value; }
741 }
742
743 public string TouchName
744 {
745 get { return m_touchName; }
746 set { m_touchName = value; }
747 }
748
749 public int LinkNum
750 {
751 get { return m_linkNum; }
752 set { m_linkNum = value; }
753 }
754
755 public byte ClickAction
756 {
757 get { return m_clickAction; }
758 set
759 {
760 m_clickAction = value;
761 }
762 }
763
764 public PrimitiveBaseShape Shape
765 {
766 get { return m_shape; }
767 set
768 {
769 bool shape_changed = false;
770 // TODO: this should really be restricted to the right
771 // set of attributes on shape change. For instance,
772 // changing the lighting on a shape shouldn't cause
773 // this.
774 if (m_shape != null)
775 shape_changed = true;
776
777 m_shape = value;
778
779 if (shape_changed)
780 TriggerScriptChangedEvent(Changed.SHAPE);
781 }
782 }
783
784 public Vector3 Scale
785 {
786 get { return m_shape.Scale; }
787 set
788 {
789 StoreUndoState();
790if (m_shape != null) {
791 m_shape.Scale = value;
792
793 if (PhysActor != null && m_parentGroup != null)
794 {
795 if (m_parentGroup.Scene != null)
796 {
797 if (m_parentGroup.Scene.PhysicsScene != null)
798 {
799 PhysActor.Size = new PhysicsVector(m_shape.Scale.X, m_shape.Scale.Y, m_shape.Scale.Z);
800 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
801 }
802 }
803 }
804}
805 TriggerScriptChangedEvent(Changed.SCALE);
806 }
807 }
808 public byte UpdateFlag
809 {
810 get { return m_updateFlag; }
811 set { m_updateFlag = value; }
812 }
813
814 #endregion
815
816//---------------
817#region Public Properties with only Get
818
819 public Vector3 AbsolutePosition
820 {
821 get {
822 if (IsAttachment)
823 return GroupPosition;
824
825 return m_offsetPosition + m_groupPosition; }
826 }
827
828 public UUID ObjectCreator
829 {
830 get { return _creatorID; }
831 }
832
833 public UUID ObjectOwner
834 {
835 get { return _ownerID; }
836 }
837
838 public SceneObjectGroup ParentGroup
839 {
840 get { return m_parentGroup; }
841 }
842
843 public scriptEvents ScriptEvents
844 {
845 get { return AggregateScriptEvents; }
846 }
847
848
849 public Quaternion SitTargetOrientation
850 {
851 get { return m_sitTargetOrientation; }
852 set { m_sitTargetOrientation = value; }
853 }
854
855
856 public Vector3 SitTargetPosition
857 {
858 get { return m_sitTargetPosition; }
859 set { m_sitTargetPosition = value; }
860 }
861
862 // This sort of sucks, but I'm adding these in to make some of
863 // the mappings more consistant.
864 public Vector3 SitTargetPositionLL
865 {
866 get { return new Vector3(m_sitTargetPosition.X, m_sitTargetPosition.Y,m_sitTargetPosition.Z); }
867 set { m_sitTargetPosition = value; }
868 }
869
870 public Quaternion SitTargetOrientationLL
871 {
872 get
873 {
874 return new Quaternion(
875 m_sitTargetOrientation.X,
876 m_sitTargetOrientation.Y,
877 m_sitTargetOrientation.Z,
878 m_sitTargetOrientation.W
879 );
880 }
881
882 set { m_sitTargetOrientation = new Quaternion(value.X, value.Y, value.Z, value.W); }
883 }
884
885 public bool Stopped
886 {
887 get {
888 double threshold = 0.02;
889 return (Math.Abs(Velocity.X) < threshold &&
890 Math.Abs(Velocity.Y) < threshold &&
891 Math.Abs(Velocity.Z) < threshold &&
892 Math.Abs(AngularVelocity.X) < threshold &&
893 Math.Abs(AngularVelocity.Y) < threshold &&
894 Math.Abs(AngularVelocity.Z) < threshold);
895 }
896 }
897
898 public uint ParentID
899 {
900 get { return _parentID; }
901 set { _parentID = value; }
902 }
903
904 public int CreationDate
905 {
906 get { return _creationDate; }
907 set { _creationDate = value; }
908 }
909
910 public uint Category
911 {
912 get { return _category; }
913 set { _category = value; }
914 }
915
916 public int SalePrice
917 {
918 get { return _salePrice; }
919 set { _salePrice = value; }
920 }
921
922 public byte ObjectSaleType
923 {
924 get { return _objectSaleType; }
925 set { _objectSaleType = value; }
926 }
927
928 public int OwnershipCost
929 {
930 get { return _ownershipCost; }
931 set { _ownershipCost = value; }
932 }
933
934 public UUID GroupID
935 {
936 get { return _groupID; }
937 set { _groupID = value; }
938 }
939
940 public UUID OwnerID
941 {
942 get { return _ownerID; }
943 set { _ownerID = value; }
944 }
945
946 public UUID LastOwnerID
947 {
948 get { return _lastOwnerID; }
949 set { _lastOwnerID = value; }
950 }
951
952 public uint BaseMask
953 {
954 get { return _baseMask; }
955 set { _baseMask = value; }
956 }
957
958 public uint OwnerMask
959 {
960 get { return _ownerMask; }
961 set { _ownerMask = value; }
962 }
963
964 public uint GroupMask
965 {
966 get { return _groupMask; }
967 set { _groupMask = value; }
968 }
969
970 public uint EveryoneMask
971 {
972 get { return _everyoneMask; }
973 set { _everyoneMask = value; }
974 }
975
976 public uint NextOwnerMask
977 {
978 get { return _nextOwnerMask; }
979 set { _nextOwnerMask = value; }
980 }
981
982 public PrimFlags Flags
983 {
984 get { return _flags; }
985 set { _flags = value; }
986 }
987
988 [XmlIgnore]
989 public UUID SitTargetAvatar
990 {
991 get { return m_sitTargetAvatar; }
992 set { m_sitTargetAvatar = value; }
993 }
994
995 [XmlIgnore]
996 public virtual UUID RegionID
997 {
998 get
999 {
1000 if (ParentGroup != null && ParentGroup.Scene != null)
1001 return ParentGroup.Scene.RegionInfo.RegionID;
1002 else
1003 return UUID.Zero;
1004 }
1005 set {} // read only
1006 }
1007
1008 private UUID _parentUUID = UUID.Zero;
1009 [XmlIgnore]
1010 public UUID ParentUUID
1011 {
1012 get
1013 {
1014 if (ParentGroup != null)
1015 {
1016 _parentUUID = ParentGroup.UUID;
1017 }
1018 return _parentUUID;
1019 }
1020 set { _parentUUID = value; }
1021 }
1022
1023 [XmlIgnore]
1024 public string SitAnimation
1025 {
1026 get { return m_sitAnimation; }
1027 set { m_sitAnimation = value; }
1028 }
1029
1030 public UUID CollisionSound
1031 {
1032 get { return m_collisionSound; }
1033 set
1034 {
1035 m_collisionSound = value;
1036 aggregateScriptEvents();
1037 }
1038 }
1039
1040 public float CollisionSoundVolume
1041 {
1042 get { return m_collisionSoundVolume; }
1043 set { m_collisionSoundVolume = value; }
1044 }
1045
1046 #endregion Public Properties with only Get
1047
1048
1049
1050 #region Private Methods
1051
1052 private uint ApplyMask(uint val, bool set, uint mask)
1053 {
1054 if (set)
1055 {
1056 return val |= mask;
1057 }
1058 else
1059 {
1060 return val &= ~mask;
1061 }
1062 }
1063
1064 /// <summary>
1065 /// Clear all pending updates of parts to clients
1066 /// </summary>
1067 private void ClearUpdateSchedule()
1068 {
1069 m_updateFlag = 0;
1070 }
1071
1072 private void SendObjectPropertiesToClient(UUID AgentID)
1073 {
1074 List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences();
1075 for (int i = 0; i < avatars.Count; i++)
1076 {
1077 // Ugly reference :(
1078 if (avatars[i].UUID == AgentID)
1079 {
1080 m_parentGroup.GetProperties(avatars[i].ControllingClient);
1081 }
1082 }
1083 }
1084
1085 private void handleTimerAccounting(uint localID, double interval)
1086 {
1087 if (localID == LocalId)
1088 {
1089
1090 float sec = (float)interval;
1091 if (m_parentGroup != null)
1092 {
1093 if (sec == 0)
1094 {
1095 if (m_parentGroup.scriptScore + 0.001f >= float.MaxValue - 0.001)
1096 m_parentGroup.scriptScore = 0;
1097
1098 m_parentGroup.scriptScore += 0.001f;
1099 return;
1100 }
1101
1102 if (m_parentGroup.scriptScore + (0.001f / sec) >= float.MaxValue - (0.001f / sec))
1103 m_parentGroup.scriptScore = 0;
1104 m_parentGroup.scriptScore += (0.001f / sec);
1105 }
1106
1107 }
1108 }
1109
1110 #endregion Private Methods
1111
1112 #region Public Methods
1113
1114 public void ResetExpire()
1115 {
1116 Expires = DateTime.Now + new TimeSpan(600000000);
1117 }
1118
1119 public void AddFlag(PrimFlags flag)
1120 {
1121 // PrimFlags prevflag = Flags;
1122 if ((ObjectFlags & (uint) flag) == 0)
1123 {
1124 //Console.WriteLine("Adding flag: " + ((PrimFlags) flag).ToString());
1125 _flags |= flag;
1126
1127 if (flag == PrimFlags.TemporaryOnRez)
1128 ResetExpire();
1129 }
1130 // System.Console.WriteLine("Aprev: " + prevflag.ToString() + " curr: " + Flags.ToString());
1131 }
1132
1133 /// <summary>
1134 /// Tell all scene presences that they should send updates for this part to their clients
1135 /// </summary>
1136 public void AddFullUpdateToAllAvatars()
1137 {
1138 List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences();
1139 for (int i = 0; i < avatars.Count; i++)
1140 {
1141 avatars[i].QueuePartForUpdate(this);
1142 }
1143 }
1144
1145 public void AddFullUpdateToAvatar(ScenePresence presence)
1146 {
1147 presence.QueuePartForUpdate(this);
1148 }
1149
1150 public void AddNewParticleSystem(Primitive.ParticleSystem pSystem)
1151 {
1152 m_particleSystem = pSystem.GetBytes();
1153 }
1154
1155 public void RemoveParticleSystem()
1156 {
1157 m_particleSystem = new byte[0];
1158 }
1159
1160 /// Terse updates
1161 public void AddTerseUpdateToAllAvatars()
1162 {
1163 List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences();
1164 for (int i = 0; i < avatars.Count; i++)
1165 {
1166 avatars[i].QueuePartForUpdate(this);
1167 }
1168 }
1169
1170 public void AddTerseUpdateToAvatar(ScenePresence presence)
1171 {
1172 presence.QueuePartForUpdate(this);
1173 }
1174
1175 public void AddTextureAnimation(Primitive.TextureAnimation pTexAnim)
1176 {
1177 byte[] data = new byte[16];
1178 int pos = 0;
1179
1180 // The flags don't like conversion from uint to byte, so we have to do
1181 // it the crappy way. See the above function :(
1182
1183 data[pos] = ConvertScriptUintToByte((uint)pTexAnim.Flags); pos++;
1184 data[pos] = (byte)pTexAnim.Face; pos++;
1185 data[pos] = (byte)pTexAnim.SizeX; pos++;
1186 data[pos] = (byte)pTexAnim.SizeY; pos++;
1187
1188 Utils.FloatToBytes(pTexAnim.Start).CopyTo(data, pos);
1189 Utils.FloatToBytes(pTexAnim.Length).CopyTo(data, pos + 4);
1190 Utils.FloatToBytes(pTexAnim.Rate).CopyTo(data, pos + 8);
1191
1192 m_TextureAnimation = data;
1193 }
1194
1195 public void AdjustSoundGain(double volume)
1196 {
1197 if (volume > 1)
1198 volume = 1;
1199 if (volume < 0)
1200 volume = 0;
1201
1202 List<ScenePresence> avatarts = m_parentGroup.Scene.GetAvatars();
1203 foreach (ScenePresence p in avatarts)
1204 {
1205 p.ControllingClient.SendAttachedSoundGainChange(UUID, (float)volume);
1206 }
1207 }
1208
1209 /// <summary>
1210 /// hook to the physics scene to apply impulse
1211 /// This is sent up to the group, which then finds the root prim
1212 /// and applies the force on the root prim of the group
1213 /// </summary>
1214 /// <param name="impulsei">Vector force</param>
1215 /// <param name="localGlobalTF">true for the local frame, false for the global frame</param>
1216 public void ApplyImpulse(Vector3 impulsei, bool localGlobalTF)
1217 {
1218 PhysicsVector impulse = new PhysicsVector(impulsei.X, impulsei.Y, impulsei.Z);
1219
1220 if (localGlobalTF)
1221 {
1222 Quaternion grot = GetWorldRotation();
1223 Quaternion AXgrot = grot;
1224 Vector3 AXimpulsei = impulsei;
1225 Vector3 newimpulse = AXimpulsei * AXgrot;
1226 impulse = new PhysicsVector(newimpulse.X, newimpulse.Y, newimpulse.Z);
1227 }
1228
1229 if (m_parentGroup != null)
1230 {
1231 m_parentGroup.applyImpulse(impulse);
1232 }
1233 }
1234
1235
1236 /// <summary>
1237 /// hook to the physics scene to apply angular impulse
1238 /// This is sent up to the group, which then finds the root prim
1239 /// and applies the force on the root prim of the group
1240 /// </summary>
1241 /// <param name="impulsei">Vector force</param>
1242 /// <param name="localGlobalTF">true for the local frame, false for the global frame</param>
1243 public void ApplyAngularImpulse(Vector3 impulsei, bool localGlobalTF)
1244 {
1245 PhysicsVector impulse = new PhysicsVector(impulsei.X, impulsei.Y, impulsei.Z);
1246
1247 if (localGlobalTF)
1248 {
1249 Quaternion grot = GetWorldRotation();
1250 Quaternion AXgrot = grot;
1251 Vector3 AXimpulsei = impulsei;
1252 Vector3 newimpulse = AXimpulsei * AXgrot;
1253 impulse = new PhysicsVector(newimpulse.X, newimpulse.Y, newimpulse.Z);
1254 }
1255
1256 if (m_parentGroup != null)
1257 {
1258 m_parentGroup.applyAngularImpulse(impulse);
1259 }
1260 }
1261
1262 /// <summary>
1263 /// hook to the physics scene to apply angular impulse
1264 /// This is sent up to the group, which then finds the root prim
1265 /// and applies the force on the root prim of the group
1266 /// </summary>
1267 /// <param name="impulsei">Vector force</param>
1268 /// <param name="localGlobalTF">true for the local frame, false for the global frame</param>
1269 public void SetAngularImpulse(Vector3 impulsei, bool localGlobalTF)
1270 {
1271 PhysicsVector impulse = new PhysicsVector(impulsei.X, impulsei.Y, impulsei.Z);
1272
1273 if (localGlobalTF)
1274 {
1275 Quaternion grot = GetWorldRotation();
1276 Quaternion AXgrot = grot;
1277 Vector3 AXimpulsei = impulsei;
1278 Vector3 newimpulse = AXimpulsei * AXgrot;
1279 impulse = new PhysicsVector(newimpulse.X, newimpulse.Y, newimpulse.Z);
1280 }
1281
1282 if (m_parentGroup != null)
1283 {
1284 m_parentGroup.setAngularImpulse(impulse);
1285 }
1286 }
1287
1288 public Vector3 GetTorque()
1289 {
1290 if (m_parentGroup != null)
1291 {
1292 m_parentGroup.GetTorque();
1293 }
1294 return Vector3.Zero;
1295 }
1296
1297 /// <summary>
1298 /// Apply physics to this part.
1299 /// </summary>
1300 /// <param name="rootObjectFlags"></param>
1301 /// <param name="m_physicalPrim"></param>
1302 public void ApplyPhysics(uint rootObjectFlags, bool VolumeDetectActive, bool m_physicalPrim)
1303 {
1304 bool isPhysical = (((rootObjectFlags & (uint) PrimFlags.Physics) != 0) && m_physicalPrim);
1305 bool isPhantom = ((rootObjectFlags & (uint) PrimFlags.Phantom) != 0);
1306
1307 if (IsJoint())
1308 {
1309 DoPhysicsPropertyUpdate(isPhysical, true);
1310 }
1311 else
1312 {
1313 // Special case for VolumeDetection: If VolumeDetection is set, the phantom flag is locally ignored
1314 if (VolumeDetectActive)
1315 isPhantom = false;
1316
1317 // Added clarification.. since A rigid body is an object that you can kick around, etc.
1318 bool RigidBody = isPhysical && !isPhantom;
1319
1320 // The only time the physics scene shouldn't know about the prim is if it's phantom or an attachment, which is phantom by definition
1321 if (!isPhantom && !IsAttachment)
1322 {
1323 PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape(
1324 Name,
1325 Shape,
1326 new PhysicsVector(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z),
1327 new PhysicsVector(Scale.X, Scale.Y, Scale.Z),
1328 RotationOffset,
1329 RigidBody);
1330
1331 // Basic Physics returns null.. joy joy joy.
1332 if (PhysActor != null)
1333 {
1334 PhysActor.SOPName = this.Name; // save object name and desc into the PhysActor so ODE internals know the joint/body info
1335 PhysActor.SOPDescription = this.Description;
1336 PhysActor.LocalID = LocalId;
1337 DoPhysicsPropertyUpdate(RigidBody, true);
1338 PhysActor.SetVolumeDetect(VolumeDetectActive ? 1 : 0);
1339 }
1340 }
1341 }
1342 }
1343
1344 public void ClearUndoState()
1345 {
1346 lock (m_undo)
1347 {
1348 m_undo.Clear();
1349 }
1350 StoreUndoState();
1351 }
1352
1353 public byte ConvertScriptUintToByte(uint indata)
1354 {
1355 byte outdata = (byte)TextureAnimFlags.NONE;
1356 if ((indata & 1) != 0) outdata |= (byte)TextureAnimFlags.ANIM_ON;
1357 if ((indata & 2) != 0) outdata |= (byte)TextureAnimFlags.LOOP;
1358 if ((indata & 4) != 0) outdata |= (byte)TextureAnimFlags.REVERSE;
1359 if ((indata & 8) != 0) outdata |= (byte)TextureAnimFlags.PING_PONG;
1360 if ((indata & 16) != 0) outdata |= (byte)TextureAnimFlags.SMOOTH;
1361 if ((indata & 32) != 0) outdata |= (byte)TextureAnimFlags.ROTATE;
1362 if ((indata & 64) != 0) outdata |= (byte)TextureAnimFlags.SCALE;
1363 return outdata;
1364 }
1365
1366 /// <summary>
1367 /// Duplicates this part.
1368 /// </summary>
1369 /// <returns></returns>
1370 public SceneObjectPart Copy(uint localID, UUID AgentID, UUID GroupID, int linkNum, bool userExposed)
1371 {
1372 SceneObjectPart dupe = (SceneObjectPart) MemberwiseClone();
1373 dupe.m_shape = m_shape.Copy();
1374 dupe.m_regionHandle = m_regionHandle;
1375 if (userExposed)
1376 dupe.UUID = UUID.Random();
1377
1378 //memberwiseclone means it also clones the physics actor reference
1379 // This will make physical prim 'bounce' if not set to null.
1380 if (!userExposed)
1381 dupe.PhysActor = null;
1382
1383 dupe._ownerID = AgentID;
1384 dupe._groupID = GroupID;
1385 dupe.GroupPosition = GroupPosition;
1386 dupe.OffsetPosition = OffsetPosition;
1387 dupe.RotationOffset = RotationOffset;
1388 dupe.Velocity = new Vector3(0, 0, 0);
1389 dupe.Acceleration = new Vector3(0, 0, 0);
1390 dupe.AngularVelocity = new Vector3(0, 0, 0);
1391 dupe.ObjectFlags = ObjectFlags;
1392
1393 dupe._ownershipCost = _ownershipCost;
1394 dupe._objectSaleType = _objectSaleType;
1395 dupe._salePrice = _salePrice;
1396 dupe._category = _category;
1397 dupe.m_rezzed = m_rezzed;
1398
1399 dupe.m_inventory = new SceneObjectPartInventory(dupe);
1400 dupe.m_inventory.Items = (TaskInventoryDictionary)m_inventory.Items.Clone();
1401
1402 if (userExposed)
1403 {
1404 dupe.ResetIDs(linkNum);
1405 dupe.m_inventory.HasInventoryChanged = true;
1406 }
1407 else
1408 {
1409 dupe.m_inventory.HasInventoryChanged = m_inventory.HasInventoryChanged;
1410 }
1411
1412 // Move afterwards ResetIDs as it clears the localID
1413 dupe.LocalId = localID;
1414 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated.
1415 dupe._lastOwnerID = ObjectOwner;
1416
1417 byte[] extraP = new byte[Shape.ExtraParams.Length];
1418 Array.Copy(Shape.ExtraParams, extraP, extraP.Length);
1419 dupe.Shape.ExtraParams = extraP;
1420
1421 if (userExposed)
1422 {
1423 if (dupe.m_shape.SculptEntry && dupe.m_shape.SculptTexture != UUID.Zero)
1424 {
1425 m_parentGroup.Scene.AssetCache.GetAsset(dupe.m_shape.SculptTexture, dupe.SculptTextureCallback, true);
1426 }
1427 bool UsePhysics = ((dupe.ObjectFlags & (uint)PrimFlags.Physics) != 0);
1428 dupe.DoPhysicsPropertyUpdate(UsePhysics, true);
1429 }
1430
1431 return dupe;
1432 }
1433
1434 public static SceneObjectPart Create()
1435 {
1436 SceneObjectPart part = new SceneObjectPart();
1437 part.UUID = UUID.Random();
1438
1439 PrimitiveBaseShape shape = PrimitiveBaseShape.Create();
1440 part.Shape = shape;
1441
1442 part.Name = "Primitive";
1443 part._ownerID = UUID.Random();
1444
1445 return part;
1446 }
1447
1448 public void DoPhysicsPropertyUpdate(bool UsePhysics, bool isNew)
1449 {
1450 if (IsJoint())
1451 {
1452 if (UsePhysics)
1453 {
1454 // by turning a joint proxy object physical, we cause creation of a joint in the ODE scene.
1455 // note that, as a special case, joints have no bodies or geoms in the physics scene, even though they are physical.
1456
1457 PhysicsJointType jointType;
1458 if (IsHingeJoint())
1459 {
1460 jointType = PhysicsJointType.Hinge;
1461 }
1462 else if (IsBallJoint())
1463 {
1464 jointType = PhysicsJointType.Ball;
1465 }
1466 else
1467 {
1468 jointType = PhysicsJointType.Ball;
1469 }
1470
1471 List<string> bodyNames = new List<string>();
1472 string RawParams = Description;
1473 string[] jointParams = RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
1474 string trackedBodyName = null;
1475 if (jointParams.Length >= 2)
1476 {
1477 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1478 {
1479 string bodyName = jointParams[iBodyName];
1480 bodyNames.Add(bodyName);
1481 if (bodyName != "NULL")
1482 {
1483 if (trackedBodyName == null)
1484 {
1485 trackedBodyName = bodyName;
1486 }
1487 }
1488 }
1489 }
1490
1491 SceneObjectPart trackedBody = m_parentGroup.Scene.GetSceneObjectPart(trackedBodyName); // FIXME: causes a sequential lookup
1492 Quaternion localRotation = Quaternion.Identity;
1493 if (trackedBody != null)
1494 {
1495 localRotation = Quaternion.Inverse(trackedBody.RotationOffset) * this.RotationOffset;
1496 }
1497 else
1498 {
1499 // error, output it below
1500 }
1501
1502 PhysicsJoint joint;
1503
1504 joint = m_parentGroup.Scene.PhysicsScene.RequestJointCreation(Name, jointType,
1505 new PhysicsVector(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z),
1506 this.RotationOffset,
1507 Description,
1508 bodyNames,
1509 trackedBodyName,
1510 localRotation);
1511
1512 if (trackedBody == null)
1513 {
1514 ParentGroup.Scene.jointErrorMessage(joint, "warning: tracked body name not found! joint location will not be updated properly. joint: " + Name);
1515 }
1516
1517 }
1518 else
1519 {
1520 if (isNew)
1521 {
1522 // if the joint proxy is new, and it is not physical, do nothing. There is no joint in ODE to
1523 // delete, and if we try to delete it, due to asynchronous processing, the deletion request
1524 // will get processed later at an indeterminate time, which could cancel a later-arriving
1525 // joint creation request.
1526 }
1527 else
1528 {
1529 // here we turn off the joint object, so remove the joint from the physics scene
1530 m_parentGroup.Scene.PhysicsScene.RequestJointDeletion(Name); // FIXME: what if the name changed?
1531
1532 // make sure client isn't interpolating the joint proxy object
1533 Velocity = new Vector3(0, 0, 0);
1534 RotationalVelocity = new Vector3(0, 0, 0);
1535 Acceleration = new Vector3(0, 0, 0);
1536 }
1537 }
1538 }
1539 else
1540 {
1541 if (PhysActor != null)
1542 {
1543 if (UsePhysics != PhysActor.IsPhysical || isNew)
1544 {
1545 if (PhysActor.IsPhysical) // implies UsePhysics==false for this block
1546 {
1547 if (!isNew)
1548 ParentGroup.Scene.RemovePhysicalPrim(1);
1549
1550 PhysActor.OnRequestTerseUpdate -= PhysicsRequestingTerseUpdate;
1551 PhysActor.OnOutOfBounds -= PhysicsOutOfBounds;
1552 PhysActor.delink();
1553
1554 if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints && (!isNew))
1555 {
1556 // destroy all joints connected to this now deactivated body
1557 m_parentGroup.Scene.PhysicsScene.RemoveAllJointsConnectedToActorThreadLocked(PhysActor);
1558 }
1559
1560 // stop client-side interpolation of all joint proxy objects that have just been deleted
1561 // this is done because RemoveAllJointsConnectedToActor invokes the OnJointDeactivated callback,
1562 // which stops client-side interpolation of deactivated joint proxy objects.
1563 }
1564
1565 if (!UsePhysics && !isNew)
1566 {
1567 // reset velocity to 0 on physics switch-off. Without that, the client thinks the
1568 // prim still has velocity and continues to interpolate its position along the old
1569 // velocity-vector.
1570 Velocity = new Vector3(0, 0, 0);
1571 Acceleration = new Vector3(0, 0, 0);
1572 AngularVelocity = new Vector3(0, 0, 0);
1573 //RotationalVelocity = new Vector3(0, 0, 0);
1574 }
1575
1576 PhysActor.IsPhysical = UsePhysics;
1577
1578
1579 // If we're not what we're supposed to be in the physics scene, recreate ourselves.
1580 //m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor);
1581 /// that's not wholesome. Had to make Scene public
1582 //PhysActor = null;
1583
1584 if ((ObjectFlags & (uint)PrimFlags.Phantom) == 0)
1585 {
1586 if (UsePhysics)
1587 {
1588 ParentGroup.Scene.AddPhysicalPrim(1);
1589
1590 PhysActor.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate;
1591 PhysActor.OnOutOfBounds += PhysicsOutOfBounds;
1592 if (_parentID != 0 && _parentID != LocalId)
1593 {
1594 if (ParentGroup.RootPart.PhysActor != null)
1595 {
1596 PhysActor.link(ParentGroup.RootPart.PhysActor);
1597 }
1598 }
1599 }
1600 }
1601 }
1602 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
1603 }
1604 }
1605 }
1606
1607 /// <summary>
1608 /// Restore this part from the serialized xml representation.
1609 /// </summary>
1610 /// <param name="xmlReader"></param>
1611 /// <returns></returns>
1612 public static SceneObjectPart FromXml(XmlReader xmlReader)
1613 {
1614 return FromXml(UUID.Zero, xmlReader);
1615 }
1616
1617 /// <summary>
1618 /// Restore this part from the serialized xml representation.
1619 /// </summary>
1620 /// <param name="fromUserInventoryItemId">The inventory id from which this part came, if applicable</param>
1621 /// <param name="xmlReader"></param>
1622 /// <returns></returns>
1623 public static SceneObjectPart FromXml(UUID fromUserInventoryItemId, XmlReader xmlReader)
1624 {
1625 SceneObjectPart part = (SceneObjectPart)serializer.Deserialize(xmlReader);
1626 part.m_fromUserInventoryItemID = fromUserInventoryItemId;
1627
1628 // for tempOnRez objects, we have to fix the Expire date.
1629 if ((part.Flags & PrimFlags.TemporaryOnRez) != 0) part.ResetExpire();
1630
1631 return part;
1632 }
1633
1634 public UUID GetAvatarOnSitTarget()
1635 {
1636 return m_sitTargetAvatar;
1637 }
1638
1639 public bool GetDieAtEdge()
1640 {
1641 if (m_parentGroup == null)
1642 return false;
1643 if (m_parentGroup.IsDeleted)
1644 return false;
1645
1646 return m_parentGroup.RootPart.DIE_AT_EDGE;
1647 }
1648
1649 public double GetDistanceTo(Vector3 a, Vector3 b)
1650 {
1651 float dx = a.X - b.X;
1652 float dy = a.Y - b.Y;
1653 float dz = a.Z - b.Z;
1654 return Math.Sqrt(dx * dx + dy * dy + dz * dz);
1655 }
1656
1657 public uint GetEffectiveObjectFlags()
1658 {
1659 PrimFlags f = _flags;
1660 if (m_parentGroup == null || m_parentGroup.RootPart == this)
1661 f &= ~(PrimFlags.Touch | PrimFlags.Money);
1662
1663 return (uint)_flags | (uint)LocalFlags;
1664 }
1665
1666 public Vector3 GetGeometricCenter()
1667 {
1668 if (PhysActor != null)
1669 {
1670 return new Vector3(PhysActor.CenterOfMass.X, PhysActor.CenterOfMass.Y, PhysActor.CenterOfMass.Z);
1671 }
1672 else
1673 {
1674 return new Vector3(0, 0, 0);
1675 }
1676 }
1677
1678 public float GetMass()
1679 {
1680 if (PhysActor != null)
1681 {
1682 return PhysActor.Mass;
1683 }
1684 else
1685 {
1686 return 0;
1687 }
1688 }
1689
1690 public PhysicsVector GetForce()
1691 {
1692 if (PhysActor != null)
1693 return PhysActor.Force;
1694 else
1695 return new PhysicsVector();
1696 }
1697
1698 [SecurityPermission(SecurityAction.LinkDemand,
1699 Flags = SecurityPermissionFlag.SerializationFormatter)]
1700 public virtual void GetObjectData(
1701 SerializationInfo info, StreamingContext context)
1702 {
1703 if (info == null)
1704 {
1705 throw new ArgumentNullException("info");
1706 }
1707
1708 info.AddValue("m_inventoryFileName", Inventory.GetInventoryFileName());
1709 info.AddValue("m_folderID", UUID);
1710 info.AddValue("PhysActor", PhysActor);
1711
1712 Dictionary<Guid, TaskInventoryItem> TaskInventory_work = new Dictionary<Guid, TaskInventoryItem>();
1713
1714 foreach (UUID id in TaskInventory.Keys)
1715 {
1716 TaskInventory_work.Add(id.Guid, TaskInventory[id]);
1717 }
1718
1719 info.AddValue("TaskInventory", TaskInventory_work);
1720
1721 info.AddValue("LastOwnerID", _lastOwnerID.Guid);
1722 info.AddValue("OwnerID", _ownerID.Guid);
1723 info.AddValue("GroupID", _groupID.Guid);
1724
1725 info.AddValue("OwnershipCost", _ownershipCost);
1726 info.AddValue("ObjectSaleType", _objectSaleType);
1727 info.AddValue("SalePrice", _salePrice);
1728 info.AddValue("Category", _category);
1729
1730 info.AddValue("CreationDate", _creationDate);
1731 info.AddValue("ParentID", _parentID);
1732
1733 info.AddValue("OwnerMask", _ownerMask);
1734 info.AddValue("NextOwnerMask", _nextOwnerMask);
1735 info.AddValue("GroupMask", _groupMask);
1736 info.AddValue("EveryoneMask", _everyoneMask);
1737 info.AddValue("BaseMask", _baseMask);
1738
1739 info.AddValue("m_particleSystem", m_particleSystem);
1740
1741 info.AddValue("TimeStampFull", TimeStampFull);
1742 info.AddValue("TimeStampTerse", TimeStampTerse);
1743 info.AddValue("TimeStampLastActivity", TimeStampLastActivity);
1744
1745 info.AddValue("m_updateFlag", m_updateFlag);
1746 info.AddValue("CreatorID", _creatorID.Guid);
1747
1748 info.AddValue("m_inventorySerial", m_inventory.Serial);
1749 info.AddValue("m_uuid", m_uuid.Guid);
1750 info.AddValue("m_localID", m_localId);
1751 info.AddValue("m_name", m_name);
1752 info.AddValue("m_flags", _flags);
1753 info.AddValue("m_material", m_material);
1754 info.AddValue("m_regionHandle", m_regionHandle);
1755
1756 info.AddValue("m_groupPosition.X", m_groupPosition.X);
1757 info.AddValue("m_groupPosition.Y", m_groupPosition.Y);
1758 info.AddValue("m_groupPosition.Z", m_groupPosition.Z);
1759
1760 info.AddValue("m_offsetPosition.X", m_offsetPosition.X);
1761 info.AddValue("m_offsetPosition.Y", m_offsetPosition.Y);
1762 info.AddValue("m_offsetPosition.Z", m_offsetPosition.Z);
1763
1764 info.AddValue("m_rotationOffset.W", m_rotationOffset.W);
1765 info.AddValue("m_rotationOffset.X", m_rotationOffset.X);
1766 info.AddValue("m_rotationOffset.Y", m_rotationOffset.Y);
1767 info.AddValue("m_rotationOffset.Z", m_rotationOffset.Z);
1768
1769 info.AddValue("m_velocity.X", m_velocity.X);
1770 info.AddValue("m_velocity.Y", m_velocity.Y);
1771 info.AddValue("m_velocity.Z", m_velocity.Z);
1772
1773 info.AddValue("m_rotationalvelocity.X", RotationalVelocity.X);
1774 info.AddValue("m_rotationalvelocity.Y", RotationalVelocity.Y);
1775 info.AddValue("m_rotationalvelocity.Z", RotationalVelocity.Z);
1776
1777 info.AddValue("m_angularVelocity.X", m_angularVelocity.X);
1778 info.AddValue("m_angularVelocity.Y", m_angularVelocity.Y);
1779 info.AddValue("m_angularVelocity.Z", m_angularVelocity.Z);
1780
1781 info.AddValue("m_acceleration.X", m_acceleration.X);
1782 info.AddValue("m_acceleration.Y", m_acceleration.Y);
1783 info.AddValue("m_acceleration.Z", m_acceleration.Z);
1784
1785 info.AddValue("m_description", m_description);
1786 info.AddValue("m_color", m_color);
1787 info.AddValue("m_text", m_text);
1788 info.AddValue("m_sitName", m_sitName);
1789 info.AddValue("m_touchName", m_touchName);
1790 info.AddValue("m_clickAction", m_clickAction);
1791 info.AddValue("m_shape", m_shape);
1792 info.AddValue("m_parentGroup", m_parentGroup);
1793 info.AddValue("PayPrice", PayPrice);
1794 }
1795
1796 public void GetProperties(IClientAPI client)
1797 {
1798 client.SendObjectPropertiesReply(
1799 m_fromUserInventoryItemID, (ulong)_creationDate, _creatorID, UUID.Zero, UUID.Zero,
1800 _groupID, (short)InventorySerial, _lastOwnerID, UUID, _ownerID,
1801 ParentGroup.RootPart.TouchName, new byte[0], ParentGroup.RootPart.SitName, Name, Description,
1802 ParentGroup.RootPart._ownerMask, ParentGroup.RootPart._nextOwnerMask, ParentGroup.RootPart._groupMask, ParentGroup.RootPart._everyoneMask,
1803 ParentGroup.RootPart._baseMask,
1804 ParentGroup.RootPart.ObjectSaleType,
1805 ParentGroup.RootPart.SalePrice);
1806 }
1807
1808 public UUID GetRootPartUUID()
1809 {
1810 if (m_parentGroup != null)
1811 {
1812 return m_parentGroup.UUID;
1813 }
1814 return UUID.Zero;
1815 }
1816
1817 /// <summary>
1818 /// Method for a prim to get it's world position from the group.
1819 /// Remember, the Group Position simply gives the position of the group itself
1820 /// </summary>
1821 /// <returns>A Linked Child Prim objects position in world</returns>
1822 public Vector3 GetWorldPosition()
1823 {
1824 Quaternion parentRot = ParentGroup.RootPart.RotationOffset;
1825
1826 Vector3 axPos = OffsetPosition;
1827
1828 axPos *= parentRot;
1829 Vector3 translationOffsetPosition = axPos;
1830 return GroupPosition + translationOffsetPosition;
1831 }
1832
1833 /// <summary>
1834 /// Gets the rotation of this prim offset by the group rotation
1835 /// </summary>
1836 /// <returns></returns>
1837 public Quaternion GetWorldRotation()
1838 {
1839 Quaternion newRot;
1840
1841 if (this.LinkNum == 0)
1842 {
1843 newRot = RotationOffset;
1844 }
1845 else
1846 {
1847 Quaternion parentRot = ParentGroup.RootPart.RotationOffset;
1848 Quaternion oldRot = RotationOffset;
1849 newRot = parentRot * oldRot;
1850 }
1851
1852 return newRot;
1853 }
1854
1855 public void MoveToTarget(Vector3 target, float tau)
1856 {
1857 if (tau > 0)
1858 {
1859 m_parentGroup.moveToTarget(target, tau);
1860 }
1861 else
1862 {
1863 StopMoveToTarget();
1864 }
1865 }
1866
1867 public virtual void OnGrab(Vector3 offsetPos, IClientAPI remoteClient)
1868 {
1869 }
1870
1871 public void PhysicsCollision(EventArgs e)
1872 {
1873 // single threaded here
1874 if (e == null)
1875 {
1876 return;
1877 }
1878
1879 CollisionEventUpdate a = (CollisionEventUpdate)e;
1880 Dictionary<uint, float> collissionswith = a.m_objCollisionList;
1881 List<uint> thisHitColliders = new List<uint>();
1882 List<uint> endedColliders = new List<uint>();
1883 List<uint> startedColliders = new List<uint>();
1884
1885 // calculate things that started colliding this time
1886 // and build up list of colliders this time
1887 foreach (uint localid in collissionswith.Keys)
1888 {
1889 if (localid != 0)
1890 {
1891 thisHitColliders.Add(localid);
1892 if (!m_lastColliders.Contains(localid))
1893 {
1894 startedColliders.Add(localid);
1895 }
1896
1897 //m_log.Debug("[OBJECT]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString());
1898 }
1899 }
1900
1901 // calculate things that ended colliding
1902 foreach (uint localID in m_lastColliders)
1903 {
1904 if (!thisHitColliders.Contains(localID))
1905 {
1906 endedColliders.Add(localID);
1907 }
1908 }
1909
1910 //add the items that started colliding this time to the last colliders list.
1911 foreach (uint localID in startedColliders)
1912 {
1913 m_lastColliders.Add(localID);
1914 }
1915 // remove things that ended colliding from the last colliders list
1916 foreach (uint localID in endedColliders)
1917 {
1918 m_lastColliders.Remove(localID);
1919 }
1920 if (m_parentGroup == null)
1921 return;
1922 if (m_parentGroup.IsDeleted)
1923 return;
1924
1925 // play the sound.
1926 if (startedColliders.Count > 0 && CollisionSound != UUID.Zero && CollisionSoundVolume > 0.0f)
1927 {
1928 SendSound(CollisionSound.ToString(), CollisionSoundVolume, true, (byte)0);
1929 }
1930
1931 if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.collision_start) != 0)
1932 {
1933 // do event notification
1934 if (startedColliders.Count > 0)
1935 {
1936 ColliderArgs StartCollidingMessage = new ColliderArgs();
1937 List<DetectedObject> colliding = new List<DetectedObject>();
1938 foreach (uint localId in startedColliders)
1939 {
1940 // always running this check because if the user deletes the object it would return a null reference.
1941 if (m_parentGroup == null)
1942 return;
1943 if (m_parentGroup.Scene == null)
1944 return;
1945 SceneObjectPart obj = m_parentGroup.Scene.GetSceneObjectPart(localId);
1946 if (obj != null)
1947 {
1948 DetectedObject detobj = new DetectedObject();
1949 detobj.keyUUID = obj.UUID;
1950 detobj.nameStr = obj.Name;
1951 detobj.ownerUUID = obj._ownerID;
1952 detobj.posVector = obj.AbsolutePosition;
1953 detobj.rotQuat = obj.GetWorldRotation();
1954 detobj.velVector = obj.Velocity;
1955 detobj.colliderType = 0;
1956 detobj.groupUUID = obj._groupID;
1957 colliding.Add(detobj);
1958 }
1959 else
1960 {
1961 List<ScenePresence> avlist = m_parentGroup.Scene.GetScenePresences();
1962 if (avlist != null)
1963 {
1964 foreach (ScenePresence av in avlist)
1965 {
1966 if (av.LocalId == localId)
1967 {
1968 DetectedObject detobj = new DetectedObject();
1969 detobj.keyUUID = av.UUID;
1970 detobj.nameStr = av.ControllingClient.Name;
1971 detobj.ownerUUID = av.UUID;
1972 detobj.posVector = av.AbsolutePosition;
1973 detobj.rotQuat = av.Rotation;
1974 detobj.velVector = av.Velocity;
1975 detobj.colliderType = 0;
1976 detobj.groupUUID = av.ControllingClient.ActiveGroupId;
1977 colliding.Add(detobj);
1978 }
1979 }
1980 }
1981 }
1982 }
1983 if (colliding.Count > 0)
1984 {
1985 StartCollidingMessage.Colliders = colliding;
1986 // always running this check because if the user deletes the object it would return a null reference.
1987 if (m_parentGroup == null)
1988 return;
1989 if (m_parentGroup.Scene == null)
1990 return;
1991 m_parentGroup.Scene.EventManager.TriggerScriptCollidingStart(LocalId, StartCollidingMessage);
1992 }
1993 }
1994 }
1995 if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.collision) != 0)
1996 {
1997 if (m_lastColliders.Count > 0)
1998 {
1999 ColliderArgs CollidingMessage = new ColliderArgs();
2000 List<DetectedObject> colliding = new List<DetectedObject>();
2001 foreach (uint localId in m_lastColliders)
2002 {
2003 // always running this check because if the user deletes the object it would return a null reference.
2004 if (localId == 0)
2005 continue;
2006
2007 if (m_parentGroup == null)
2008 return;
2009 if (m_parentGroup.Scene == null)
2010 return;
2011 SceneObjectPart obj = m_parentGroup.Scene.GetSceneObjectPart(localId);
2012 if (obj != null)
2013 {
2014 DetectedObject detobj = new DetectedObject();
2015 detobj.keyUUID = obj.UUID;
2016 detobj.nameStr = obj.Name;
2017 detobj.ownerUUID = obj._ownerID;
2018 detobj.posVector = obj.AbsolutePosition;
2019 detobj.rotQuat = obj.GetWorldRotation();
2020 detobj.velVector = obj.Velocity;
2021 detobj.colliderType = 0;
2022 detobj.groupUUID = obj._groupID;
2023 colliding.Add(detobj);
2024 }
2025 else
2026 {
2027 List<ScenePresence> avlist = m_parentGroup.Scene.GetScenePresences();
2028 if (avlist != null)
2029 {
2030 foreach (ScenePresence av in avlist)
2031 {
2032 if (av.LocalId == localId)
2033 {
2034 DetectedObject detobj = new DetectedObject();
2035 detobj.keyUUID = av.UUID;
2036 detobj.nameStr = av.Name;
2037 detobj.ownerUUID = av.UUID;
2038 detobj.posVector = av.AbsolutePosition;
2039 detobj.rotQuat = av.Rotation;
2040 detobj.velVector = av.Velocity;
2041 detobj.colliderType = 0;
2042 detobj.groupUUID = av.ControllingClient.ActiveGroupId;
2043 colliding.Add(detobj);
2044 }
2045 }
2046
2047 }
2048 }
2049 }
2050 if (colliding.Count > 0)
2051 {
2052 CollidingMessage.Colliders = colliding;
2053 // always running this check because if the user deletes the object it would return a null reference.
2054 if (m_parentGroup == null)
2055 return;
2056 if (m_parentGroup.Scene == null)
2057 return;
2058 m_parentGroup.Scene.EventManager.TriggerScriptColliding(LocalId, CollidingMessage);
2059 }
2060
2061 }
2062 }
2063 if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.collision_end) != 0)
2064 {
2065 if (endedColliders.Count > 0)
2066 {
2067 ColliderArgs EndCollidingMessage = new ColliderArgs();
2068 List<DetectedObject> colliding = new List<DetectedObject>();
2069 foreach (uint localId in endedColliders)
2070 {
2071 if (localId == 0)
2072 continue;
2073
2074 // always running this check because if the user deletes the object it would return a null reference.
2075 if (m_parentGroup == null)
2076 return;
2077 if (m_parentGroup.Scene == null)
2078 return;
2079 SceneObjectPart obj = m_parentGroup.Scene.GetSceneObjectPart(localId);
2080 if (obj != null)
2081 {
2082 DetectedObject detobj = new DetectedObject();
2083 detobj.keyUUID = obj.UUID;
2084 detobj.nameStr = obj.Name;
2085 detobj.ownerUUID = obj._ownerID;
2086 detobj.posVector = obj.AbsolutePosition;
2087 detobj.rotQuat = obj.GetWorldRotation();
2088 detobj.velVector = obj.Velocity;
2089 detobj.colliderType = 0;
2090 detobj.groupUUID = obj._groupID;
2091 colliding.Add(detobj);
2092 }
2093 else
2094 {
2095 List<ScenePresence> avlist = m_parentGroup.Scene.GetScenePresences();
2096 if (avlist != null)
2097 {
2098 foreach (ScenePresence av in avlist)
2099 {
2100 if (av.LocalId == localId)
2101 {
2102 DetectedObject detobj = new DetectedObject();
2103 detobj.keyUUID = av.UUID;
2104 detobj.nameStr = av.Name;
2105 detobj.ownerUUID = av.UUID;
2106 detobj.posVector = av.AbsolutePosition;
2107 detobj.rotQuat = av.Rotation;
2108 detobj.velVector = av.Velocity;
2109 detobj.colliderType = 0;
2110 detobj.groupUUID = av.ControllingClient.ActiveGroupId;
2111 colliding.Add(detobj);
2112 }
2113 }
2114
2115 }
2116 }
2117 }
2118 if (colliding.Count > 0)
2119 {
2120 EndCollidingMessage.Colliders = colliding;
2121 // always running this check because if the user deletes the object it would return a null reference.
2122 if (m_parentGroup == null)
2123 return;
2124 if (m_parentGroup.Scene == null)
2125 return;
2126 m_parentGroup.Scene.EventManager.TriggerScriptCollidingEnd(LocalId, EndCollidingMessage);
2127 }
2128
2129 }
2130 }
2131 }
2132
2133 public void PhysicsOutOfBounds(PhysicsVector pos)
2134 {
2135 m_log.Info("[PHYSICS]: Physical Object went out of bounds.");
2136 RemFlag(PrimFlags.Physics);
2137 DoPhysicsPropertyUpdate(false, true);
2138 //m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
2139 }
2140
2141 public void PhysicsRequestingTerseUpdate()
2142 {
2143 if (PhysActor != null)
2144 {
2145 Vector3 newpos = new Vector3(PhysActor.Position.GetBytes(), 0);
2146 if (newpos.X > 257f || newpos.X < -1f || newpos.Y > 257f || newpos.Y < -1f)
2147 {
2148 m_parentGroup.AbsolutePosition = newpos;
2149 return;
2150 }
2151 }
2152 ScheduleTerseUpdate();
2153
2154 //SendTerseUpdateToAllClients();
2155 }
2156
2157 public void PreloadSound(string sound)
2158 {
2159 // UUID ownerID = OwnerID;
2160 UUID objectID = UUID;
2161 UUID soundID = UUID.Zero;
2162
2163 if (!UUID.TryParse(sound, out soundID))
2164 {
2165 //Trys to fetch sound id from prim's inventory.
2166 //Prim's inventory doesn't support non script items yet
2167 SceneObjectPart op = this;
2168 foreach (KeyValuePair<UUID, TaskInventoryItem> item in op.TaskInventory)
2169 {
2170 if (item.Value.Name == sound)
2171 {
2172 soundID = item.Value.ItemID;
2173 break;
2174 }
2175 }
2176 }
2177
2178 List<ScenePresence> avatarts = m_parentGroup.Scene.GetAvatars();
2179 foreach (ScenePresence p in avatarts)
2180 {
2181 // TODO: some filtering by distance of avatar
2182
2183 p.ControllingClient.SendPreLoadSound(objectID, objectID, soundID);
2184 }
2185 }
2186
2187 public void RemFlag(PrimFlags flag)
2188 {
2189 // PrimFlags prevflag = Flags;
2190 if ((ObjectFlags & (uint) flag) != 0)
2191 {
2192 //Console.WriteLine("Removing flag: " + ((PrimFlags)flag).ToString());
2193 _flags &= ~flag;
2194 }
2195 //System.Console.WriteLine("prev: " + prevflag.ToString() + " curr: " + Flags.ToString());
2196 //ScheduleFullUpdate();
2197 }
2198
2199 public void RemoveScriptEvents(UUID scriptid)
2200 {
2201 lock (m_scriptEvents)
2202 {
2203 if (m_scriptEvents.ContainsKey(scriptid))
2204 {
2205 scriptEvents oldparts = scriptEvents.None;
2206 oldparts = (scriptEvents) m_scriptEvents[scriptid];
2207
2208 // remove values from aggregated script events
2209 AggregateScriptEvents &= ~oldparts;
2210 m_scriptEvents.Remove(scriptid);
2211 aggregateScriptEvents();
2212 }
2213 }
2214 }
2215
2216 /// <summary>
2217 /// Reset UUIDs for this part. This involves generate this part's own UUID and
2218 /// generating new UUIDs for all the items in the inventory.
2219 /// </summary>
2220 /// <param name="linkNum">Link number for the part</param>
2221 public void ResetIDs(int linkNum)
2222 {
2223 UUID = UUID.Random();
2224 LinkNum = linkNum;
2225 LocalId = 0;
2226 Inventory.ResetInventoryIDs();
2227 }
2228
2229 /// <summary>
2230 /// Resize this part.
2231 /// </summary>
2232 /// <param name="scale"></param>
2233 public void Resize(Vector3 scale)
2234 {
2235 StoreUndoState();
2236 m_shape.Scale = scale;
2237
2238 ParentGroup.HasGroupChanged = true;
2239 ScheduleFullUpdate();
2240 }
2241
2242 /// <summary>
2243 /// Schedules this prim for a full update
2244 /// </summary>
2245 public void ScheduleFullUpdate()
2246 {
2247 if (m_parentGroup != null)
2248 {
2249 m_parentGroup.QueueForUpdateCheck();
2250 }
2251
2252 int timeNow = Util.UnixTimeSinceEpoch();
2253
2254 // If multiple updates are scheduled on the same second, we still need to perform all of them
2255 // So we'll force the issue by bumping up the timestamp so that later processing sees these need
2256 // to be performed.
2257 if (timeNow <= TimeStampFull)
2258 {
2259 TimeStampFull += 1;
2260 }
2261 else
2262 {
2263 TimeStampFull = (uint)timeNow;
2264 }
2265
2266 m_updateFlag = 2;
2267
2268 // m_log.DebugFormat(
2269 // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}",
2270 // UUID, Name, TimeStampFull);
2271 }
2272
2273 /// <summary>
2274 /// Schedule a terse update for this prim. Terse updates only send position,
2275 /// rotation, velocity, rotational velocity and shape information.
2276 /// </summary>
2277 public void ScheduleTerseUpdate()
2278 {
2279 if (m_updateFlag < 1)
2280 {
2281 if (m_parentGroup != null)
2282 {
2283 m_parentGroup.HasGroupChanged = true;
2284 m_parentGroup.QueueForUpdateCheck();
2285 }
2286 TimeStampTerse = (uint) Util.UnixTimeSinceEpoch();
2287 m_updateFlag = 1;
2288
2289 // m_log.DebugFormat(
2290 // "[SCENE OBJECT PART]: Scheduling terse update for {0}, {1} at {2}",
2291 // UUID, Name, TimeStampTerse);
2292 }
2293 }
2294
2295 public void ScriptSetPhantomStatus(bool Phantom)
2296 {
2297 if (m_parentGroup != null)
2298 {
2299 m_parentGroup.ScriptSetPhantomStatus(Phantom);
2300 }
2301 }
2302
2303 public void ScriptSetTemporaryStatus(bool Temporary)
2304 {
2305 if (m_parentGroup != null)
2306 {
2307 m_parentGroup.ScriptSetTemporaryStatus(Temporary);
2308 }
2309 }
2310
2311 public void ScriptSetPhysicsStatus(bool UsePhysics)
2312 {
2313 if (m_parentGroup == null)
2314 DoPhysicsPropertyUpdate(UsePhysics, false);
2315 else
2316 m_parentGroup.ScriptSetPhysicsStatus(UsePhysics);
2317 }
2318
2319 public void ScriptSetVolumeDetect(bool SetVD)
2320 {
2321
2322 if (m_parentGroup != null)
2323 {
2324 m_parentGroup.ScriptSetVolumeDetect(SetVD);
2325 }
2326 }
2327
2328
2329 public void SculptTextureCallback(UUID textureID, AssetBase texture)
2330 {
2331 if (m_shape.SculptEntry)
2332 {
2333 if (texture != null)
2334 {
2335 m_shape.SculptData = texture.Data;
2336 if (PhysActor != null)
2337 {
2338 // Tricks physics engine into thinking we've changed the part shape.
2339 PrimitiveBaseShape m_newshape = m_shape.Copy();
2340 PhysActor.Shape = m_newshape;
2341 m_shape = m_newshape;
2342
2343 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
2344 }
2345 }
2346 }
2347 }
2348
2349 /// <summary>
2350 ///
2351 /// </summary>
2352 /// <param name="remoteClient"></param>
2353 public void SendFullUpdate(IClientAPI remoteClient, uint clientFlags)
2354 {
2355 m_parentGroup.SendPartFullUpdate(remoteClient, this, clientFlags);
2356 }
2357
2358 /// <summary>
2359 ///
2360 /// </summary>
2361 public void SendFullUpdateToAllClients()
2362 {
2363 List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences();
2364 for (int i = 0; i < avatars.Count; i++)
2365 {
2366 // Ugly reference :(
2367 m_parentGroup.SendPartFullUpdate(avatars[i].ControllingClient, this,
2368 avatars[i].GenerateClientFlags(UUID));
2369 }
2370 }
2371
2372 public void SendFullUpdateToAllClientsExcept(UUID agentID)
2373 {
2374 List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences();
2375 for (int i = 0; i < avatars.Count; i++)
2376 {
2377 // Ugly reference :(
2378 if (avatars[i].UUID != agentID)
2379 {
2380 m_parentGroup.SendPartFullUpdate(avatars[i].ControllingClient, this,
2381 avatars[i].GenerateClientFlags(UUID));
2382 }
2383 }
2384 }
2385
2386 /// <summary>
2387 /// Sends a full update to the client
2388 /// </summary>
2389 /// <param name="remoteClient"></param>
2390 /// <param name="clientFlags"></param>
2391 public void SendFullUpdateToClient(IClientAPI remoteClient, uint clientflags)
2392 {
2393 Vector3 lPos;
2394 lPos = OffsetPosition;
2395 SendFullUpdateToClient(remoteClient, lPos, clientflags);
2396 }
2397
2398 /// <summary>
2399 /// Sends a full update to the client
2400 /// </summary>
2401 /// <param name="remoteClient"></param>
2402 /// <param name="lPos"></param>
2403 /// <param name="clientFlags"></param>
2404 public void SendFullUpdateToClient(IClientAPI remoteClient, Vector3 lPos, uint clientFlags)
2405 {
2406 // Suppress full updates during attachment editing
2407 //
2408 if (ParentGroup.IsSelected && IsAttachment)
2409 return;
2410
2411 if (ParentGroup.IsDeleted)
2412 return;
2413
2414 clientFlags &= ~(uint) PrimFlags.CreateSelected;
2415
2416 if (remoteClient.AgentId == _ownerID)
2417 {
2418 if ((uint) (_flags & PrimFlags.CreateSelected) != 0)
2419 {
2420 clientFlags |= (uint) PrimFlags.CreateSelected;
2421 _flags &= ~PrimFlags.CreateSelected;
2422 }
2423 }
2424 //bool isattachment = IsAttachment;
2425 //if (LocalId != ParentGroup.RootPart.LocalId)
2426 //isattachment = ParentGroup.RootPart.IsAttachment;
2427
2428 byte[] color = new byte[] {m_color.R, m_color.G, m_color.B, m_color.A};
2429 remoteClient.SendPrimitiveToClient(m_regionHandle, (ushort)(m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue), LocalId, m_shape,
2430 lPos, Velocity, Acceleration, RotationOffset, RotationalVelocity, clientFlags, m_uuid, _ownerID,
2431 m_text, color, _parentID, m_particleSystem, m_clickAction, (byte)m_material, m_TextureAnimation, IsAttachment,
2432 AttachmentPoint,FromAssetID, Sound, SoundGain, SoundFlags, SoundRadius);
2433 }
2434
2435 /// <summary>
2436 /// Tell all the prims which have had updates scheduled
2437 /// </summary>
2438 public void SendScheduledUpdates()
2439 {
2440 if (m_updateFlag == 1) //some change has been made so update the clients
2441 {
2442 AddTerseUpdateToAllAvatars();
2443 ClearUpdateSchedule();
2444
2445 // This causes the Scene to 'poll' physical objects every couple of frames
2446 // bad, so it's been replaced by an event driven method.
2447 //if ((ObjectFlags & (uint)PrimFlags.Physics) != 0)
2448 //{
2449 // Only send the constant terse updates on physical objects!
2450 //ScheduleTerseUpdate();
2451 //}
2452 }
2453 else
2454 {
2455 if (m_updateFlag == 2) // is a new prim, just created/reloaded or has major changes
2456 {
2457 AddFullUpdateToAllAvatars();
2458 ClearUpdateSchedule();
2459 }
2460 }
2461 }
2462
2463 /// <summary>
2464 /// Trigger or play an attached sound in this part's inventory.
2465 /// </summary>
2466 /// <param name="sound"></param>
2467 /// <param name="volume"></param>
2468 /// <param name="triggered"></param>
2469 /// <param name="flags"></param>
2470 public void SendSound(string sound, double volume, bool triggered, byte flags)
2471 {
2472 if (volume > 1)
2473 volume = 1;
2474 if (volume < 0)
2475 volume = 0;
2476
2477 UUID ownerID = _ownerID;
2478 UUID objectID = UUID;
2479 UUID parentID = GetRootPartUUID();
2480 UUID soundID = UUID.Zero;
2481 Vector3 position = AbsolutePosition; // region local
2482 ulong regionHandle = m_parentGroup.Scene.RegionInfo.RegionHandle;
2483
2484 if (!UUID.TryParse(sound, out soundID))
2485 {
2486 // search sound file from inventory
2487 SceneObjectPart op = this;
2488 foreach (KeyValuePair<UUID, TaskInventoryItem> item in op.TaskInventory)
2489 {
2490 if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound)
2491 {
2492 soundID = item.Value.ItemID;
2493 break;
2494 }
2495 }
2496 }
2497
2498 if (soundID == UUID.Zero)
2499 return;
2500
2501 ISoundModule soundModule = m_parentGroup.Scene.RequestModuleInterface<ISoundModule>();
2502 if (soundModule != null)
2503 {
2504 if (triggered)
2505 soundModule.TriggerSound(soundID, ownerID, objectID, parentID, volume, position, regionHandle);
2506 else
2507 soundModule.PlayAttachedSound(soundID, ownerID, objectID, volume, position, flags);
2508 }
2509 }
2510
2511 /// <summary>
2512 /// Send a terse update to all clients
2513 /// </summary>
2514 public void SendTerseUpdateToAllClients()
2515 {
2516 List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences();
2517 for (int i = 0; i < avatars.Count; i++)
2518 {
2519 SendTerseUpdateToClient(avatars[i].ControllingClient);
2520 }
2521 }
2522
2523 public void SetAttachmentPoint(uint AttachmentPoint)
2524 {
2525 this.AttachmentPoint = AttachmentPoint;
2526
2527 if (AttachmentPoint != 0)
2528 {
2529 IsAttachment = true;
2530 }
2531 else
2532 {
2533 IsAttachment = false;
2534 }
2535
2536 // save the attachment point.
2537 //if (AttachmentPoint != 0)
2538 //{
2539 m_shape.State = (byte)AttachmentPoint;
2540 //}
2541 }
2542
2543 public void SetAvatarOnSitTarget(UUID avatarID)
2544 {
2545 m_sitTargetAvatar = avatarID;
2546 if (ParentGroup != null)
2547 ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
2548 }
2549
2550 public void SetAxisRotation(int axis, int rotate)
2551 {
2552 if (m_parentGroup != null)
2553 {
2554 m_parentGroup.SetAxisRotation(axis, rotate);
2555 }
2556 }
2557
2558 public void SetBuoyancy(float fvalue)
2559 {
2560 if (PhysActor != null)
2561 {
2562 PhysActor.Buoyancy = fvalue;
2563 }
2564 }
2565
2566 public void SetDieAtEdge(bool p)
2567 {
2568 if (m_parentGroup == null)
2569 return;
2570 if (m_parentGroup.IsDeleted)
2571 return;
2572
2573 m_parentGroup.RootPart.DIE_AT_EDGE = p;
2574 }
2575
2576 public void SetFloatOnWater(int floatYN)
2577 {
2578 if (PhysActor != null)
2579 {
2580 if (floatYN == 1)
2581 {
2582 PhysActor.FloatOnWater = true;
2583 }
2584 else
2585 {
2586 PhysActor.FloatOnWater = false;
2587 }
2588 }
2589 }
2590
2591 public void SetForce(PhysicsVector force)
2592 {
2593 if (PhysActor != null)
2594 {
2595 PhysActor.Force = force;
2596 }
2597 }
2598
2599 public void SetVehicleType(int type)
2600 {
2601 if (PhysActor != null)
2602 {
2603 PhysActor.VehicleType = type;
2604 }
2605 }
2606
2607 public void SetVehicleFloatParam(int param, float value)
2608 {
2609 if (PhysActor != null)
2610 {
2611 PhysActor.VehicleFloatParam(param, value);
2612 }
2613 }
2614
2615 public void SetVehicleVectorParam(int param, PhysicsVector value)
2616 {
2617 if (PhysActor != null)
2618 {
2619 PhysActor.VehicleVectorParam(param, value);
2620 }
2621 }
2622
2623 public void SetVehicleRotationParam(int param, Quaternion rotation)
2624 {
2625 if (PhysActor != null)
2626 {
2627 PhysActor.VehicleRotationParam(param, rotation);
2628 }
2629 }
2630
2631 public void SetGroup(UUID groupID, IClientAPI client)
2632 {
2633 _groupID = groupID;
2634 if (client != null)
2635 GetProperties(client);
2636 m_updateFlag = 2;
2637 }
2638
2639 /// <summary>
2640 ///
2641 /// </summary>
2642 public void SetParent(SceneObjectGroup parent)
2643 {
2644 m_parentGroup = parent;
2645 }
2646
2647 // Use this for attachments! LocalID should be avatar's localid
2648 public void SetParentLocalId(uint localID)
2649 {
2650 _parentID = localID;
2651 }
2652
2653 public void SetPhysicsAxisRotation()
2654 {
2655 if (PhysActor != null)
2656 {
2657 PhysActor.LockAngularMotion(RotationAxis);
2658 m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
2659 }
2660 }
2661
2662 public void SetScriptEvents(UUID scriptid, int events)
2663 {
2664 // scriptEvents oldparts;
2665 lock (m_scriptEvents)
2666 {
2667 if (m_scriptEvents.ContainsKey(scriptid))
2668 {
2669 // oldparts = m_scriptEvents[scriptid];
2670
2671 // remove values from aggregated script events
2672 if (m_scriptEvents[scriptid] == (scriptEvents) events)
2673 return;
2674 m_scriptEvents[scriptid] = (scriptEvents) events;
2675 }
2676 else
2677 {
2678 m_scriptEvents.Add(scriptid, (scriptEvents) events);
2679 }
2680 }
2681 aggregateScriptEvents();
2682 }
2683
2684 /// <summary>
2685 /// Set the text displayed for this part.
2686 /// </summary>
2687 /// <param name="text"></param>
2688 public void SetText(string text)
2689 {
2690 Text = text;
2691
2692 ParentGroup.HasGroupChanged = true;
2693 ScheduleFullUpdate();
2694 }
2695
2696 /// <summary>
2697 /// Set the text displayed for this part.
2698 /// </summary>
2699 /// <param name="text"></param>
2700 /// <param name="color"></param>
2701 /// <param name="alpha"></param>
2702 public void SetText(string text, Vector3 color, double alpha)
2703 {
2704 Color = Color.FromArgb(0xff - (int) (alpha*0xff),
2705 (int) (color.X*0xff),
2706 (int) (color.Y*0xff),
2707 (int) (color.Z*0xff));
2708 SetText(text);
2709 }
2710
2711 public void StopMoveToTarget()
2712 {
2713 m_parentGroup.stopMoveToTarget();
2714
2715 m_parentGroup.ScheduleGroupForTerseUpdate();
2716 //m_parentGroup.ScheduleGroupForFullUpdate();
2717 }
2718
2719 public void StoreUndoState()
2720 {
2721 if (!Undoing)
2722 {
2723 if (m_parentGroup != null)
2724 {
2725 lock (m_undo)
2726 {
2727 if (m_undo.Count > 0)
2728 {
2729 UndoState last = m_undo.Peek();
2730 if (last != null)
2731 {
2732 if (last.Compare(this))
2733 return;
2734 }
2735 }
2736
2737 if (m_parentGroup.GetSceneMaxUndo() > 0)
2738 {
2739 UndoState nUndo = new UndoState(this);
2740
2741 m_undo.Push(nUndo);
2742 }
2743
2744 }
2745 }
2746 }
2747 }
2748
2749 public EntityIntersection TestIntersection(Ray iray, Quaternion parentrot)
2750 {
2751 // In this case we're using a sphere with a radius of the largest dimention of the prim
2752 // TODO: Change to take shape into account
2753
2754
2755 EntityIntersection returnresult = new EntityIntersection();
2756 Vector3 vAbsolutePosition = AbsolutePosition;
2757 Vector3 vScale = Scale;
2758 Vector3 rOrigin = iray.Origin;
2759 Vector3 rDirection = iray.Direction;
2760
2761 //rDirection = rDirection.Normalize();
2762 // Buidling the first part of the Quadratic equation
2763 Vector3 r2ndDirection = rDirection*rDirection;
2764 float itestPart1 = r2ndDirection.X + r2ndDirection.Y + r2ndDirection.Z;
2765
2766 // Buidling the second part of the Quadratic equation
2767 Vector3 tmVal2 = rOrigin - vAbsolutePosition;
2768 Vector3 r2Direction = rDirection*2.0f;
2769 Vector3 tmVal3 = r2Direction*tmVal2;
2770
2771 float itestPart2 = tmVal3.X + tmVal3.Y + tmVal3.Z;
2772
2773 // Buidling the third part of the Quadratic equation
2774 Vector3 tmVal4 = rOrigin*rOrigin;
2775 Vector3 tmVal5 = vAbsolutePosition*vAbsolutePosition;
2776
2777 Vector3 tmVal6 = vAbsolutePosition*rOrigin;
2778
2779
2780 // Set Radius to the largest dimention of the prim
2781 float radius = 0f;
2782 if (vScale.X > radius)
2783 radius = vScale.X;
2784 if (vScale.Y > radius)
2785 radius = vScale.Y;
2786 if (vScale.Z > radius)
2787 radius = vScale.Z;
2788
2789 // the second part of this is the default prim size
2790 // once we factor in the aabb of the prim we're adding we can
2791 // change this to;
2792 // radius = (radius / 2) - 0.01f;
2793 //
2794 radius = (radius / 2) + (0.5f / 2) - 0.1f;
2795
2796 //radius = radius;
2797
2798 float itestPart3 = tmVal4.X + tmVal4.Y + tmVal4.Z + tmVal5.X + tmVal5.Y + tmVal5.Z -
2799 (2.0f*(tmVal6.X + tmVal6.Y + tmVal6.Z + (radius*radius)));
2800
2801 // Yuk Quadradrics.. Solve first
2802 float rootsqr = (itestPart2*itestPart2) - (4.0f*itestPart1*itestPart3);
2803 if (rootsqr < 0.0f)
2804 {
2805 // No intersection
2806 return returnresult;
2807 }
2808 float root = ((-itestPart2) - (float) Math.Sqrt((double) rootsqr))/(itestPart1*2.0f);
2809
2810 if (root < 0.0f)
2811 {
2812 // perform second quadratic root solution
2813 root = ((-itestPart2) + (float) Math.Sqrt((double) rootsqr))/(itestPart1*2.0f);
2814
2815 // is there any intersection?
2816 if (root < 0.0f)
2817 {
2818 // nope, no intersection
2819 return returnresult;
2820 }
2821 }
2822
2823 // We got an intersection. putting together an EntityIntersection object with the
2824 // intersection information
2825 Vector3 ipoint =
2826 new Vector3(iray.Origin.X + (iray.Direction.X*root), iray.Origin.Y + (iray.Direction.Y*root),
2827 iray.Origin.Z + (iray.Direction.Z*root));
2828
2829 returnresult.HitTF = true;
2830 returnresult.ipoint = ipoint;
2831
2832 // Normal is calculated by the difference and then normalizing the result
2833 Vector3 normalpart = ipoint - vAbsolutePosition;
2834 returnresult.normal = normalpart / normalpart.Length();
2835
2836 // It's funny how the Vector3 object has a Distance function, but the Axiom.Math object doesn't.
2837 // I can write a function to do it.. but I like the fact that this one is Static.
2838
2839 Vector3 distanceConvert1 = new Vector3(iray.Origin.X, iray.Origin.Y, iray.Origin.Z);
2840 Vector3 distanceConvert2 = new Vector3(ipoint.X, ipoint.Y, ipoint.Z);
2841 float distance = (float) Util.GetDistanceTo(distanceConvert1, distanceConvert2);
2842
2843 returnresult.distance = distance;
2844
2845 return returnresult;
2846 }
2847
2848 public EntityIntersection TestIntersectionOBB(Ray iray, Quaternion parentrot, bool frontFacesOnly, bool faceCenters)
2849 {
2850 // In this case we're using a rectangular prism, which has 6 faces and therefore 6 planes
2851 // This breaks down into the ray---> plane equation.
2852 // TODO: Change to take shape into account
2853 Vector3[] vertexes = new Vector3[8];
2854
2855 // float[] distance = new float[6];
2856 Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
2857 Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
2858 Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
2859 Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
2860
2861 Vector3[] normals = new Vector3[6]; // Normal for Facei
2862 Vector3[] AAfacenormals = new Vector3[6]; // Axis Aligned face normals
2863
2864 AAfacenormals[0] = new Vector3(1, 0, 0);
2865 AAfacenormals[1] = new Vector3(0, 1, 0);
2866 AAfacenormals[2] = new Vector3(-1, 0, 0);
2867 AAfacenormals[3] = new Vector3(0, -1, 0);
2868 AAfacenormals[4] = new Vector3(0, 0, 1);
2869 AAfacenormals[5] = new Vector3(0, 0, -1);
2870
2871 Vector3 AmBa = new Vector3(0, 0, 0); // Vertex A - Vertex B
2872 Vector3 AmBb = new Vector3(0, 0, 0); // Vertex B - Vertex C
2873 Vector3 cross = new Vector3();
2874
2875 Vector3 pos = GetWorldPosition();
2876 Quaternion rot = GetWorldRotation();
2877
2878 // Variables prefixed with AX are Axiom.Math copies of the LL variety.
2879
2880 Quaternion AXrot = rot;
2881 AXrot.Normalize();
2882
2883 Vector3 AXpos = pos;
2884
2885 // tScale is the offset to derive the vertex based on the scale.
2886 // it's different for each vertex because we've got to rotate it
2887 // to get the world position of the vertex to produce the Oriented Bounding Box
2888
2889 Vector3 tScale = Vector3.Zero;
2890
2891 Vector3 AXscale = new Vector3(m_shape.Scale.X * 0.5f, m_shape.Scale.Y * 0.5f, m_shape.Scale.Z * 0.5f);
2892
2893 //Vector3 pScale = (AXscale) - (AXrot.Inverse() * (AXscale));
2894 //Vector3 nScale = (AXscale * -1) - (AXrot.Inverse() * (AXscale * -1));
2895
2896 // rScale is the rotated offset to find a vertex based on the scale and the world rotation.
2897 Vector3 rScale = new Vector3();
2898
2899 // Get Vertexes for Faces Stick them into ABCD for each Face
2900 // Form: Face<vertex>[face] that corresponds to the below diagram
2901 #region ABCD Face Vertex Map Comment Diagram
2902 // A _________ B
2903 // | |
2904 // | 4 top |
2905 // |_________|
2906 // C D
2907
2908 // A _________ B
2909 // | Back |
2910 // | 3 |
2911 // |_________|
2912 // C D
2913
2914 // A _________ B B _________ A
2915 // | Left | | Right |
2916 // | 0 | | 2 |
2917 // |_________| |_________|
2918 // C D D C
2919
2920 // A _________ B
2921 // | Front |
2922 // | 1 |
2923 // |_________|
2924 // C D
2925
2926 // C _________ D
2927 // | |
2928 // | 5 bot |
2929 // |_________|
2930 // A B
2931 #endregion
2932
2933 #region Plane Decomposition of Oriented Bounding Box
2934 tScale = new Vector3(AXscale.X, -AXscale.Y, AXscale.Z);
2935 rScale = tScale * AXrot;
2936 vertexes[0] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
2937 // vertexes[0].X = pos.X + vertexes[0].X;
2938 //vertexes[0].Y = pos.Y + vertexes[0].Y;
2939 //vertexes[0].Z = pos.Z + vertexes[0].Z;
2940
2941 FaceA[0] = vertexes[0];
2942 FaceB[3] = vertexes[0];
2943 FaceA[4] = vertexes[0];
2944
2945 tScale = AXscale;
2946 rScale = tScale * AXrot;
2947 vertexes[1] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
2948
2949 // vertexes[1].X = pos.X + vertexes[1].X;
2950 // vertexes[1].Y = pos.Y + vertexes[1].Y;
2951 //vertexes[1].Z = pos.Z + vertexes[1].Z;
2952
2953 FaceB[0] = vertexes[1];
2954 FaceA[1] = vertexes[1];
2955 FaceC[4] = vertexes[1];
2956
2957 tScale = new Vector3(AXscale.X, -AXscale.Y, -AXscale.Z);
2958 rScale = tScale * AXrot;
2959
2960 vertexes[2] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
2961
2962 //vertexes[2].X = pos.X + vertexes[2].X;
2963 //vertexes[2].Y = pos.Y + vertexes[2].Y;
2964 //vertexes[2].Z = pos.Z + vertexes[2].Z;
2965
2966 FaceC[0] = vertexes[2];
2967 FaceD[3] = vertexes[2];
2968 FaceC[5] = vertexes[2];
2969
2970 tScale = new Vector3(AXscale.X, AXscale.Y, -AXscale.Z);
2971 rScale = tScale * AXrot;
2972 vertexes[3] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
2973
2974 //vertexes[3].X = pos.X + vertexes[3].X;
2975 // vertexes[3].Y = pos.Y + vertexes[3].Y;
2976 // vertexes[3].Z = pos.Z + vertexes[3].Z;
2977
2978 FaceD[0] = vertexes[3];
2979 FaceC[1] = vertexes[3];
2980 FaceA[5] = vertexes[3];
2981
2982 tScale = new Vector3(-AXscale.X, AXscale.Y, AXscale.Z);
2983 rScale = tScale * AXrot;
2984 vertexes[4] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
2985
2986 // vertexes[4].X = pos.X + vertexes[4].X;
2987 // vertexes[4].Y = pos.Y + vertexes[4].Y;
2988 // vertexes[4].Z = pos.Z + vertexes[4].Z;
2989
2990 FaceB[1] = vertexes[4];
2991 FaceA[2] = vertexes[4];
2992 FaceD[4] = vertexes[4];
2993
2994 tScale = new Vector3(-AXscale.X, AXscale.Y, -AXscale.Z);
2995 rScale = tScale * AXrot;
2996 vertexes[5] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
2997
2998 // vertexes[5].X = pos.X + vertexes[5].X;
2999 // vertexes[5].Y = pos.Y + vertexes[5].Y;
3000 // vertexes[5].Z = pos.Z + vertexes[5].Z;
3001
3002 FaceD[1] = vertexes[5];
3003 FaceC[2] = vertexes[5];
3004 FaceB[5] = vertexes[5];
3005
3006 tScale = new Vector3(-AXscale.X, -AXscale.Y, AXscale.Z);
3007 rScale = tScale * AXrot;
3008 vertexes[6] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
3009
3010 // vertexes[6].X = pos.X + vertexes[6].X;
3011 // vertexes[6].Y = pos.Y + vertexes[6].Y;
3012 // vertexes[6].Z = pos.Z + vertexes[6].Z;
3013
3014 FaceB[2] = vertexes[6];
3015 FaceA[3] = vertexes[6];
3016 FaceB[4] = vertexes[6];
3017
3018 tScale = new Vector3(-AXscale.X, -AXscale.Y, -AXscale.Z);
3019 rScale = tScale * AXrot;
3020 vertexes[7] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
3021
3022 // vertexes[7].X = pos.X + vertexes[7].X;
3023 // vertexes[7].Y = pos.Y + vertexes[7].Y;
3024 // vertexes[7].Z = pos.Z + vertexes[7].Z;
3025
3026 FaceD[2] = vertexes[7];
3027 FaceC[3] = vertexes[7];
3028 FaceD[5] = vertexes[7];
3029 #endregion
3030
3031 // Get our plane normals
3032 for (int i = 0; i < 6; i++)
3033 {
3034 //m_log.Info("[FACECALCULATION]: FaceA[" + i + "]=" + FaceA[i] + " FaceB[" + i + "]=" + FaceB[i] + " FaceC[" + i + "]=" + FaceC[i] + " FaceD[" + i + "]=" + FaceD[i]);
3035
3036 // Our Plane direction
3037 AmBa = FaceA[i] - FaceB[i];
3038 AmBb = FaceB[i] - FaceC[i];
3039
3040 cross = Vector3.Cross(AmBb, AmBa);
3041
3042 // normalize the cross product to get the normal.
3043 normals[i] = cross / cross.Length();
3044
3045 //m_log.Info("[NORMALS]: normals[ " + i + "]" + normals[i].ToString());
3046 //distance[i] = (normals[i].X * AmBa.X + normals[i].Y * AmBa.Y + normals[i].Z * AmBa.Z) * -1;
3047 }
3048
3049 EntityIntersection returnresult = new EntityIntersection();
3050
3051 returnresult.distance = 1024;
3052 float c = 0;
3053 float a = 0;
3054 float d = 0;
3055 Vector3 q = new Vector3();
3056
3057 #region OBB Version 2 Experiment
3058 //float fmin = 999999;
3059 //float fmax = -999999;
3060 //float s = 0;
3061
3062 //for (int i=0;i<6;i++)
3063 //{
3064 //s = iray.Direction.Dot(normals[i]);
3065 //d = normals[i].Dot(FaceB[i]);
3066
3067 //if (s == 0)
3068 //{
3069 //if (iray.Origin.Dot(normals[i]) > d)
3070 //{
3071 //return returnresult;
3072 //}
3073 // else
3074 //{
3075 //continue;
3076 //}
3077 //}
3078 //a = (d - iray.Origin.Dot(normals[i])) / s;
3079 //if (iray.Direction.Dot(normals[i]) < 0)
3080 //{
3081 //if (a > fmax)
3082 //{
3083 //if (a > fmin)
3084 //{
3085 //return returnresult;
3086 //}
3087 //fmax = a;
3088 //}
3089
3090 //}
3091 //else
3092 //{
3093 //if (a < fmin)
3094 //{
3095 //if (a < 0 || a < fmax)
3096 //{
3097 //return returnresult;
3098 //}
3099 //fmin = a;
3100 //}
3101 //}
3102 //}
3103 //if (fmax > 0)
3104 // a= fmax;
3105 //else
3106 // a=fmin;
3107
3108 //q = iray.Origin + a * iray.Direction;
3109 #endregion
3110
3111 // Loop over faces (6 of them)
3112 for (int i = 0; i < 6; i++)
3113 {
3114 AmBa = FaceA[i] - FaceB[i];
3115 AmBb = FaceB[i] - FaceC[i];
3116 d = Vector3.Dot(normals[i], FaceB[i]);
3117
3118 //if (faceCenters)
3119 //{
3120 // c = normals[i].Dot(normals[i]);
3121 //}
3122 //else
3123 //{
3124 c = Vector3.Dot(iray.Direction, normals[i]);
3125 //}
3126 if (c == 0)
3127 continue;
3128
3129 a = (d - Vector3.Dot(iray.Origin, normals[i])) / c;
3130
3131 if (a < 0)
3132 continue;
3133
3134 // If the normal is pointing outside the object
3135 if (Vector3.Dot(iray.Direction, normals[i]) < 0 || !frontFacesOnly)
3136 {
3137 //if (faceCenters)
3138 //{ //(FaceA[i] + FaceB[i] + FaceC[1] + FaceD[i]) / 4f;
3139 // q = iray.Origin + a * normals[i];
3140 //}
3141 //else
3142 //{
3143 q = iray.Origin + iray.Direction * a;
3144 //}
3145
3146 float distance2 = (float)GetDistanceTo(q, AXpos);
3147 // Is this the closest hit to the object's origin?
3148 //if (faceCenters)
3149 //{
3150 // distance2 = (float)GetDistanceTo(q, iray.Origin);
3151 //}
3152
3153 if (distance2 < returnresult.distance)
3154 {
3155 returnresult.distance = distance2;
3156 returnresult.HitTF = true;
3157 returnresult.ipoint = q;
3158 //m_log.Info("[FACE]:" + i.ToString());
3159 //m_log.Info("[POINT]: " + q.ToString());
3160 //m_log.Info("[DIST]: " + distance2.ToString());
3161 if (faceCenters)
3162 {
3163 returnresult.normal = AAfacenormals[i] * AXrot;
3164
3165 Vector3 scaleComponent = AAfacenormals[i];
3166 float ScaleOffset = 0.5f;
3167 if (scaleComponent.X != 0) ScaleOffset = AXscale.X;
3168 if (scaleComponent.Y != 0) ScaleOffset = AXscale.Y;
3169 if (scaleComponent.Z != 0) ScaleOffset = AXscale.Z;
3170 ScaleOffset = Math.Abs(ScaleOffset);
3171 Vector3 offset = returnresult.normal * ScaleOffset;
3172 returnresult.ipoint = AXpos + offset;
3173
3174 ///pos = (intersectionpoint + offset);
3175 }
3176 else
3177 {
3178 returnresult.normal = normals[i];
3179 }
3180 returnresult.AAfaceNormal = AAfacenormals[i];
3181 }
3182 }
3183 }
3184 return returnresult;
3185 }
3186
3187 /// <summary>
3188 /// Serialize this part to xml.
3189 /// </summary>
3190 /// <param name="xmlWriter"></param>
3191 public void ToXml(XmlWriter xmlWriter)
3192 {
3193 serializer.Serialize(xmlWriter, this);
3194 }
3195
3196 public void TriggerScriptChangedEvent(Changed val)
3197 {
3198 if (m_parentGroup != null)
3199 {
3200 if (m_parentGroup.Scene != null)
3201 m_parentGroup.Scene.TriggerObjectChanged(LocalId, (uint)val);
3202 }
3203 }
3204
3205 public void TrimPermissions()
3206 {
3207 _baseMask &= (uint)PermissionMask.All;
3208 _ownerMask &= (uint)PermissionMask.All;
3209 _groupMask &= (uint)PermissionMask.All;
3210 _everyoneMask &= (uint)PermissionMask.All;
3211 _nextOwnerMask &= (uint)PermissionMask.All;
3212 }
3213
3214 public void Undo()
3215 {
3216 lock (m_undo)
3217 {
3218 if (m_undo.Count > 0)
3219 {
3220 UndoState goback = m_undo.Pop();
3221 if (goback != null)
3222 goback.PlaybackState(this);
3223 }
3224 }
3225 }
3226
3227 public void UpdateExtraParam(ushort type, bool inUse, byte[] data)
3228 {
3229 m_shape.ReadInUpdateExtraParam(type, inUse, data);
3230
3231 if (type == 0x30)
3232 {
3233 if (m_shape.SculptEntry && m_shape.SculptTexture != UUID.Zero)
3234 {
3235 //AssetBase tx = m_parentGroup.Scene.getase
3236 m_parentGroup.Scene.AssetCache.GetAsset(m_shape.SculptTexture, SculptTextureCallback, true);
3237 }
3238 }
3239
3240 ParentGroup.HasGroupChanged = true;
3241 ScheduleFullUpdate();
3242 }
3243
3244 public void UpdateGroupPosition(Vector3 pos)
3245 {
3246 if ((pos.X != GroupPosition.X) ||
3247 (pos.Y != GroupPosition.Y) ||
3248 (pos.Z != GroupPosition.Z))
3249 {
3250 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3251 GroupPosition = newPos;
3252 ScheduleTerseUpdate();
3253 }
3254 }
3255
3256 public virtual void UpdateMovement()
3257 {
3258 }
3259
3260 /// <summary>
3261 ///
3262 /// </summary>
3263 /// <param name="pos"></param>
3264 public void UpdateOffSet(Vector3 pos)
3265 {
3266 if ((pos.X != OffsetPosition.X) ||
3267 (pos.Y != OffsetPosition.Y) ||
3268 (pos.Z != OffsetPosition.Z))
3269 {
3270 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
3271 OffsetPosition = newPos;
3272 ScheduleTerseUpdate();
3273 }
3274 }
3275
3276 public void UpdatePermissions(UUID AgentID, byte field, uint localID, uint mask, byte addRemTF)
3277 {
3278 bool set = addRemTF == 1;
3279 bool god = m_parentGroup.Scene.Permissions.IsGod(AgentID);
3280
3281 uint baseMask = _baseMask;
3282 if (god)
3283 baseMask = 0x7ffffff0;
3284
3285 // Are we the owner?
3286 if ((AgentID == _ownerID) || god)
3287 {
3288 switch (field)
3289 {
3290 case 1:
3291 if (god)
3292 {
3293 _baseMask = ApplyMask(_baseMask, set, mask);
3294 Inventory.ApplyGodPermissions(_baseMask);
3295 }
3296
3297 break;
3298 case 2:
3299 _ownerMask = ApplyMask(_ownerMask, set, mask) &
3300 baseMask;
3301 break;
3302 case 4:
3303 _groupMask = ApplyMask(_groupMask, set, mask) &
3304 baseMask;
3305 break;
3306 case 8:
3307 _everyoneMask = ApplyMask(_everyoneMask, set, mask) &
3308 baseMask;
3309 break;
3310 case 16:
3311 _nextOwnerMask = ApplyMask(_nextOwnerMask, set, mask) &
3312 baseMask;
3313 break;
3314 }
3315 SendFullUpdateToAllClients();
3316
3317 SendObjectPropertiesToClient(AgentID);
3318
3319 }
3320 }
3321
3322 public bool IsHingeJoint()
3323 {
3324 // For now, we use the NINJA naming scheme for identifying joints.
3325 // In the future, we can support other joint specification schemes such as a
3326 // custom checkbox in the viewer GUI.
3327 if (m_parentGroup.Scene.PhysicsScene.SupportsNINJAJoints)
3328 {
3329 string hingeString = "hingejoint";
3330 return (Name.Length >= hingeString.Length && Name.Substring(0, hingeString.Length) == hingeString);
3331 }
3332 else
3333 {
3334 return false;
3335 }
3336 }
3337
3338 public bool IsBallJoint()
3339 {
3340 // For now, we use the NINJA naming scheme for identifying joints.
3341 // In the future, we can support other joint specification schemes such as a
3342 // custom checkbox in the viewer GUI.
3343 if (m_parentGroup.Scene.PhysicsScene.SupportsNINJAJoints)
3344 {
3345 string ballString = "balljoint";
3346 return (Name.Length >= ballString.Length && Name.Substring(0, ballString.Length) == ballString);
3347 }
3348 else
3349 {
3350 return false;
3351 }
3352 }
3353
3354 public bool IsJoint()
3355 {
3356 // For now, we use the NINJA naming scheme for identifying joints.
3357 // In the future, we can support other joint specification schemes such as a
3358 // custom checkbox in the viewer GUI.
3359 if (m_parentGroup.Scene.PhysicsScene.SupportsNINJAJoints)
3360 {
3361 return IsHingeJoint() || IsBallJoint();
3362 }
3363 else
3364 {
3365 return false;
3366 }
3367 }
3368
3369 public void UpdatePrimFlags(bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVD)
3370 {
3371 bool wasUsingPhysics = ((ObjectFlags & (uint) PrimFlags.Physics) != 0);
3372 bool wasTemporary = ((ObjectFlags & (uint)PrimFlags.TemporaryOnRez) != 0);
3373 bool wasPhantom = ((ObjectFlags & (uint)PrimFlags.Phantom) != 0);
3374 bool wasVD = VolumeDetectActive;
3375
3376 if ((UsePhysics == wasUsingPhysics) && (wasTemporary == IsTemporary) && (wasPhantom == IsPhantom) && (IsVD==wasVD) )
3377 {
3378 return;
3379 }
3380
3381 // Special cases for VD. VD can only be called from a script
3382 // and can't be combined with changes to other states. So we can rely
3383 // that...
3384 // ... if VD is changed, all others are not.
3385 // ... if one of the others is changed, VD is not.
3386 if (IsVD) // VD is active, special logic applies
3387 {
3388 // State machine logic for VolumeDetect
3389 // More logic below
3390 bool phanReset = (IsPhantom != wasPhantom) && !IsPhantom;
3391
3392 if (phanReset) // Phantom changes from on to off switch VD off too
3393 {
3394 IsVD = false; // Switch it of for the course of this routine
3395 VolumeDetectActive = false; // and also permanently
3396 if (PhysActor != null)
3397 PhysActor.SetVolumeDetect(0); // Let physics know about it too
3398 }
3399 else
3400 {
3401 IsPhantom = false;
3402 // If volumedetect is active we don't want phantom to be applied.
3403 // If this is a new call to VD out of the state "phantom"
3404 // this will also cause the prim to be visible to physics
3405 }
3406
3407 }
3408
3409 if (UsePhysics && IsJoint())
3410 {
3411 IsPhantom = true;
3412 }
3413
3414 if (UsePhysics)
3415 {
3416 AddFlag(PrimFlags.Physics);
3417 if (!wasUsingPhysics)
3418 {
3419 DoPhysicsPropertyUpdate(UsePhysics, false);
3420 if (m_parentGroup != null)
3421 {
3422 if (!m_parentGroup.IsDeleted)
3423 {
3424 if (LocalId == m_parentGroup.RootPart.LocalId)
3425 {
3426 m_parentGroup.CheckSculptAndLoad();
3427 }
3428 }
3429 }
3430 }
3431 }
3432 else
3433 {
3434 RemFlag(PrimFlags.Physics);
3435 if (wasUsingPhysics)
3436 {
3437 DoPhysicsPropertyUpdate(UsePhysics, false);
3438 }
3439 }
3440
3441
3442 if (IsPhantom || IsAttachment) // note: this may have been changed above in the case of joints
3443 {
3444 AddFlag(PrimFlags.Phantom);
3445 if (PhysActor != null)
3446 {
3447 m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor);
3448 /// that's not wholesome. Had to make Scene public
3449 PhysActor = null;
3450 }
3451 }
3452 else // Not phantom
3453 {
3454 RemFlag(PrimFlags.Phantom);
3455
3456 if (PhysActor == null)
3457 {
3458 // It's not phantom anymore. So make sure the physics engine get's knowledge of it
3459 PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape(
3460 Name,
3461 Shape,
3462 new PhysicsVector(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z),
3463 new PhysicsVector(Scale.X, Scale.Y, Scale.Z),
3464 RotationOffset,
3465 UsePhysics);
3466
3467 if (PhysActor != null)
3468 {
3469 PhysActor.LocalID = LocalId;
3470 DoPhysicsPropertyUpdate(UsePhysics, true);
3471 if (m_parentGroup != null)
3472 {
3473 if (!m_parentGroup.IsDeleted)
3474 {
3475 if (LocalId == m_parentGroup.RootPart.LocalId)
3476 {
3477 m_parentGroup.CheckSculptAndLoad();
3478 }
3479 }
3480 }
3481 if (
3482 ((AggregateScriptEvents & scriptEvents.collision) != 0) ||
3483 ((AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
3484 ((AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
3485 (CollisionSound != UUID.Zero)
3486 )
3487 {
3488 PhysActor.OnCollisionUpdate += PhysicsCollision;
3489 PhysActor.SubscribeEvents(1000);
3490 }
3491 }
3492 }
3493 else // it already has a physical representation
3494 {
3495 PhysActor.IsPhysical = UsePhysics;
3496
3497 DoPhysicsPropertyUpdate(UsePhysics, false); // Update physical status. If it's phantom this will remove the prim
3498 if (m_parentGroup != null)
3499 {
3500 if (!m_parentGroup.IsDeleted)
3501 {
3502 if (LocalId == m_parentGroup.RootPart.LocalId)
3503 {
3504 m_parentGroup.CheckSculptAndLoad();
3505 }
3506 }
3507 }
3508 }
3509 }
3510
3511 if (IsVD)
3512 {
3513 // If the above logic worked (this is urgent candidate to unit tests!)
3514 // we now have a physicsactor.
3515 // Defensive programming calls for a check here.
3516 // Better would be throwing an exception that could be catched by a unit test as the internal
3517 // logic should make sure, this Physactor is always here.
3518 if (this.PhysActor != null)
3519 {
3520 PhysActor.SetVolumeDetect(1);
3521 AddFlag(PrimFlags.Phantom); // We set this flag also if VD is active
3522 this.VolumeDetectActive = true;
3523 }
3524
3525 }
3526 else
3527 { // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like
3528 // (mumbles, well, at least if you have infinte CPU powers :-) )
3529 if (this.PhysActor != null)
3530 {
3531 PhysActor.SetVolumeDetect(0);
3532 }
3533 this.VolumeDetectActive = false;
3534 }
3535
3536
3537 if (IsTemporary)
3538 {
3539 AddFlag(PrimFlags.TemporaryOnRez);
3540 }
3541 else
3542 {
3543 RemFlag(PrimFlags.TemporaryOnRez);
3544 }
3545 // System.Console.WriteLine("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString());
3546
3547 ParentGroup.HasGroupChanged = true;
3548 ScheduleFullUpdate();
3549 }
3550
3551 public void UpdateRotation(Quaternion rot)
3552 {
3553 if ((rot.X != RotationOffset.X) ||
3554 (rot.Y != RotationOffset.Y) ||
3555 (rot.Z != RotationOffset.Z) ||
3556 (rot.W != RotationOffset.W))
3557 {
3558 //StoreUndoState();
3559 RotationOffset = rot;
3560 ParentGroup.HasGroupChanged = true;
3561 ScheduleTerseUpdate();
3562 }
3563 }
3564
3565 /// <summary>
3566 /// Update the shape of this part.
3567 /// </summary>
3568 /// <param name="shapeBlock"></param>
3569 public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock)
3570 {
3571 m_shape.PathBegin = shapeBlock.PathBegin;
3572 m_shape.PathEnd = shapeBlock.PathEnd;
3573 m_shape.PathScaleX = shapeBlock.PathScaleX;
3574 m_shape.PathScaleY = shapeBlock.PathScaleY;
3575 m_shape.PathShearX = shapeBlock.PathShearX;
3576 m_shape.PathShearY = shapeBlock.PathShearY;
3577 m_shape.PathSkew = shapeBlock.PathSkew;
3578 m_shape.ProfileBegin = shapeBlock.ProfileBegin;
3579 m_shape.ProfileEnd = shapeBlock.ProfileEnd;
3580 m_shape.PathCurve = shapeBlock.PathCurve;
3581 m_shape.ProfileCurve = shapeBlock.ProfileCurve;
3582 m_shape.ProfileHollow = shapeBlock.ProfileHollow;
3583 m_shape.PathRadiusOffset = shapeBlock.PathRadiusOffset;
3584 m_shape.PathRevolutions = shapeBlock.PathRevolutions;
3585 m_shape.PathTaperX = shapeBlock.PathTaperX;
3586 m_shape.PathTaperY = shapeBlock.PathTaperY;
3587 m_shape.PathTwist = shapeBlock.PathTwist;
3588 m_shape.PathTwistBegin = shapeBlock.PathTwistBegin;
3589 if (PhysActor != null)
3590 {
3591 PhysActor.Shape = m_shape;
3592 }
3593
3594 // This is what makes vehicle trailers work
3595 // A script in a child prim re-issues
3596 // llSetPrimitiveParams(PRIM_TYPE) every few seconds. That
3597 // prevents autoreturn. This is not well known. It also works
3598 // in SL.
3599 //
3600 if (ParentGroup.RootPart != this)
3601 ParentGroup.RootPart.Rezzed = DateTime.Now;
3602
3603 ParentGroup.HasGroupChanged = true;
3604 ScheduleFullUpdate();
3605 }
3606
3607 // Added to handle bug in libsecondlife's TextureEntry.ToBytes()
3608 // not handling RGBA properly. Cycles through, and "fixes" the color
3609 // info
3610 public void UpdateTexture(Primitive.TextureEntry tex)
3611 {
3612 //Color4 tmpcolor;
3613 //for (uint i = 0; i < 32; i++)
3614 //{
3615 // if (tex.FaceTextures[i] != null)
3616 // {
3617 // tmpcolor = tex.GetFace((uint) i).RGBA;
3618 // tmpcolor.A = tmpcolor.A*255;
3619 // tmpcolor.R = tmpcolor.R*255;
3620 // tmpcolor.G = tmpcolor.G*255;
3621 // tmpcolor.B = tmpcolor.B*255;
3622 // tex.FaceTextures[i].RGBA = tmpcolor;
3623 // }
3624 //}
3625 //tmpcolor = tex.DefaultTexture.RGBA;
3626 //tmpcolor.A = tmpcolor.A*255;
3627 //tmpcolor.R = tmpcolor.R*255;
3628 //tmpcolor.G = tmpcolor.G*255;
3629 //tmpcolor.B = tmpcolor.B*255;
3630 //tex.DefaultTexture.RGBA = tmpcolor;
3631 UpdateTextureEntry(tex.ToBytes());
3632 }
3633
3634 /// <summary>
3635 /// Update the texture entry for this part.
3636 /// </summary>
3637 /// <param name="textureEntry"></param>
3638 public void UpdateTextureEntry(byte[] textureEntry)
3639 {
3640 m_shape.TextureEntry = textureEntry;
3641 TriggerScriptChangedEvent(Changed.TEXTURE);
3642
3643 ParentGroup.HasGroupChanged = true;
3644 ParentGroup.ScheduleGroupForFullUpdate();
3645 }
3646
3647 public void aggregateScriptEvents()
3648 {
3649 AggregateScriptEvents = 0;
3650
3651 // Aggregate script events
3652 lock (m_scriptEvents)
3653 {
3654 foreach (scriptEvents s in m_scriptEvents.Values)
3655 {
3656 AggregateScriptEvents |= s;
3657 }
3658 }
3659
3660 uint objectflagupdate = 0;
3661
3662 if (
3663 ((AggregateScriptEvents & scriptEvents.touch) != 0) ||
3664 ((AggregateScriptEvents & scriptEvents.touch_end) != 0) ||
3665 ((AggregateScriptEvents & scriptEvents.touch_start) != 0)
3666 )
3667 {
3668 objectflagupdate |= (uint) PrimFlags.Touch;
3669 }
3670
3671 if ((AggregateScriptEvents & scriptEvents.money) != 0)
3672 {
3673 objectflagupdate |= (uint) PrimFlags.Money;
3674 }
3675
3676 if (AllowedDrop)
3677 {
3678 objectflagupdate |= (uint) PrimFlags.AllowInventoryDrop;
3679 }
3680
3681 if (
3682 ((AggregateScriptEvents & scriptEvents.collision) != 0) ||
3683 ((AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
3684 ((AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
3685 (CollisionSound != UUID.Zero)
3686 )
3687 {
3688 // subscribe to physics updates.
3689 if (PhysActor != null)
3690 {
3691 PhysActor.OnCollisionUpdate += PhysicsCollision;
3692 PhysActor.SubscribeEvents(1000);
3693
3694 }
3695 }
3696 else
3697 {
3698 if (PhysActor != null)
3699 {
3700 PhysActor.UnSubscribeEvents();
3701 PhysActor.OnCollisionUpdate -= PhysicsCollision;
3702 }
3703 }
3704
3705 if (m_parentGroup == null)
3706 {
3707 ScheduleFullUpdate();
3708 return;
3709 }
3710
3711 if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0)
3712 {
3713 m_parentGroup.Scene.EventManager.OnScriptTimerEvent += handleTimerAccounting;
3714 }
3715 else
3716 {
3717 m_parentGroup.Scene.EventManager.OnScriptTimerEvent -= handleTimerAccounting;
3718 }
3719
3720 LocalFlags=(PrimFlags)objectflagupdate;
3721
3722 if (m_parentGroup != null && m_parentGroup.RootPart == this)
3723 m_parentGroup.aggregateScriptEvents();
3724 else
3725 ScheduleFullUpdate();
3726 }
3727
3728 public int registerTargetWaypoint(Vector3 target, float tolerance)
3729 {
3730 if (m_parentGroup != null)
3731 {
3732 return m_parentGroup.registerTargetWaypoint(target, tolerance);
3733 }
3734 return 0;
3735 }
3736
3737 public void unregisterTargetWaypoint(int handle)
3738 {
3739 if (m_parentGroup != null)
3740 {
3741 m_parentGroup.unregisterTargetWaypoint(handle);
3742 }
3743 }
3744
3745 public void SetCameraAtOffset(Vector3 v)
3746 {
3747 m_cameraAtOffset = v;
3748 }
3749
3750 public void SetCameraEyeOffset(Vector3 v)
3751 {
3752 m_cameraEyeOffset = v;
3753 }
3754
3755 public void SetForceMouselook(bool force)
3756 {
3757 m_forceMouselook = force;
3758 }
3759
3760 public Vector3 GetCameraAtOffset()
3761 {
3762 return m_cameraAtOffset;
3763 }
3764
3765 public Vector3 GetCameraEyeOffset()
3766 {
3767 return m_cameraEyeOffset;
3768 }
3769
3770 public bool GetForceMouselook()
3771 {
3772 return m_forceMouselook;
3773 }
3774
3775 public override string ToString()
3776 {
3777 return String.Format("{0} {1} (parent {2}))", Name, UUID, ParentGroup);
3778 }
3779
3780 #endregion Public Methods
3781
3782 public void SendTerseUpdateToClient(IClientAPI remoteClient)
3783 {
3784 if (ParentGroup == null || ParentGroup.IsDeleted)
3785 return;
3786
3787 Vector3 lPos = OffsetPosition;
3788
3789 byte state = Shape.State;
3790 if (IsAttachment)
3791 {
3792 if (ParentGroup.RootPart != this)
3793 return;
3794
3795 lPos = ParentGroup.RootPart.AttachedPos;
3796 state = (byte)AttachmentPoint;
3797 }
3798 else
3799 {
3800 if (ParentGroup.RootPart == this)
3801 lPos = AbsolutePosition;
3802 }
3803
3804 remoteClient.SendPrimTerseUpdate(m_regionHandle,
3805 (ushort)(m_parentGroup.GetTimeDilation() *
3806 (float)ushort.MaxValue), LocalId, lPos,
3807 RotationOffset, Velocity,
3808 RotationalVelocity, state, FromAssetID,
3809 OwnerID, (int)AttachmentPoint);
3810 }
3811
3812 public void AddScriptLPS(int count)
3813 {
3814 m_parentGroup.AddScriptLPS(count);
3815 }
3816
3817 public void ApplyNextOwnerPermissions()
3818 {
3819 _baseMask &= _nextOwnerMask;
3820 _ownerMask &= _nextOwnerMask;
3821 _everyoneMask &= _nextOwnerMask;
3822
3823 Inventory.ApplyNextOwnerPermissions();
3824 }
3825 }
3826}
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
new file mode 100644
index 0000000..efd486d
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs
@@ -0,0 +1,891 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using OpenMetaverse;
32using log4net;
33using OpenSim.Framework;
34using OpenSim.Framework.Communications.Cache;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes.Scripting;
37
38namespace OpenSim.Region.Framework.Scenes
39{
40 public class SceneObjectPartInventory : IEntityInventory
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 private string m_inventoryFileName = String.Empty;
45 private int m_inventoryFileNameSerial = 0;
46
47 /// <value>
48 /// The part to which the inventory belongs.
49 /// </value>
50 private SceneObjectPart m_part;
51
52 /// <summary>
53 /// Serial count for inventory file , used to tell if inventory has changed
54 /// no need for this to be part of Database backup
55 /// </summary>
56 protected uint m_inventorySerial = 0;
57
58 /// <summary>
59 /// Holds in memory prim inventory
60 /// </summary>
61 protected TaskInventoryDictionary m_items = new TaskInventoryDictionary();
62
63 /// <summary>
64 /// Tracks whether inventory has changed since the last persistent backup
65 /// </summary>
66 internal bool HasInventoryChanged;
67
68 /// <value>
69 /// Inventory serial number
70 /// </value>
71 protected internal uint Serial
72 {
73 get { return m_inventorySerial; }
74 set { m_inventorySerial = value; }
75 }
76
77 /// <value>
78 /// Raw inventory data
79 /// </value>
80 protected internal TaskInventoryDictionary Items
81 {
82 get { return m_items; }
83 set
84 {
85 m_items = value;
86 m_inventorySerial++;
87 }
88 }
89
90 /// <summary>
91 /// Constructor
92 /// </summary>
93 /// <param name="part">
94 /// A <see cref="SceneObjectPart"/>
95 /// </param>
96 public SceneObjectPartInventory(SceneObjectPart part)
97 {
98 m_part = part;
99 }
100
101 /// <summary>
102 /// Force the task inventory of this prim to persist at the next update sweep
103 /// </summary>
104 public void ForceInventoryPersistence()
105 {
106 HasInventoryChanged = true;
107 }
108
109 /// <summary>
110 /// Reset UUIDs for all the items in the prim's inventory. This involves either generating
111 /// new ones or setting existing UUIDs to the correct parent UUIDs.
112 ///
113 /// If this method is called and there are inventory items, then we regard the inventory as having changed.
114 /// </summary>
115 /// <param name="linkNum">Link number for the part</param>
116 public void ResetInventoryIDs()
117 {
118 lock (Items)
119 {
120 if (0 == Items.Count)
121 return;
122
123 HasInventoryChanged = true;
124 m_part.ParentGroup.HasGroupChanged = true;
125 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
126 Items.Clear();
127
128 foreach (TaskInventoryItem item in items)
129 {
130 item.ResetIDs(m_part.UUID);
131 Items.Add(item.ItemID, item);
132 }
133 }
134 }
135
136 /// <summary>
137 /// Change every item in this inventory to a new owner.
138 /// </summary>
139 /// <param name="ownerId"></param>
140 public void ChangeInventoryOwner(UUID ownerId)
141 {
142 lock (Items)
143 {
144 if (0 == Items.Count)
145 {
146 return;
147 }
148
149 HasInventoryChanged = true;
150 m_part.ParentGroup.HasGroupChanged = true;
151 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
152 foreach (TaskInventoryItem item in items)
153 {
154 if (ownerId != item.OwnerID)
155 {
156 item.LastOwnerID = item.OwnerID;
157 item.OwnerID = ownerId;
158 }
159 }
160 }
161 }
162
163 /// <summary>
164 /// Change every item in this inventory to a new group.
165 /// </summary>
166 /// <param name="groupID"></param>
167 public void ChangeInventoryGroup(UUID groupID)
168 {
169 lock (Items)
170 {
171 if (0 == Items.Count)
172 {
173 return;
174 }
175
176 HasInventoryChanged = true;
177 m_part.ParentGroup.HasGroupChanged = true;
178 IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
179 foreach (TaskInventoryItem item in items)
180 {
181 if (groupID != item.GroupID)
182 {
183 item.GroupID = groupID;
184 }
185 }
186 }
187 }
188
189 /// <summary>
190 /// Start all the scripts contained in this prim's inventory
191 /// </summary>
192 public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource)
193 {
194 lock (m_items)
195 {
196 foreach (TaskInventoryItem item in Items.Values)
197 {
198 if ((int)InventoryType.LSL == item.InvType)
199 {
200 CreateScriptInstance(item, startParam, postOnRez, engine, stateSource);
201 }
202 }
203 }
204 }
205
206 /// <summary>
207 /// Stop all the scripts in this prim.
208 /// </summary>
209 public void RemoveScriptInstances()
210 {
211 lock (Items)
212 {
213 foreach (TaskInventoryItem item in Items.Values)
214 {
215 if ((int)InventoryType.LSL == item.InvType)
216 {
217 RemoveScriptInstance(item.ItemID);
218 m_part.RemoveScriptEvents(item.ItemID);
219 }
220 }
221 }
222 }
223
224 /// <summary>
225 /// Start a script which is in this prim's inventory.
226 /// </summary>
227 /// <param name="item"></param>
228 /// <returns></returns>
229 public void CreateScriptInstance(TaskInventoryItem item, int startParam, bool postOnRez, string engine, int stateSource)
230 {
231 // m_log.InfoFormat(
232 // "[PRIM INVENTORY]: " +
233 // "Starting script {0}, {1} in prim {2}, {3}",
234 // item.Name, item.ItemID, Name, UUID);
235
236 if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID))
237 return;
238
239 m_part.AddFlag(PrimFlags.Scripted);
240
241 if (!m_part.ParentGroup.Scene.RegionInfo.RegionSettings.DisableScripts)
242 {
243 if (stateSource == 1 && // Prim crossing
244 m_part.ParentGroup.Scene.m_trustBinaries)
245 {
246 m_items[item.ItemID].PermsMask = 0;
247 m_items[item.ItemID].PermsGranter = UUID.Zero;
248 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
249 m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource);
250 m_part.ParentGroup.AddActiveScriptCount(1);
251 m_part.ScheduleFullUpdate();
252 return;
253 }
254 AssetCache cache = m_part.ParentGroup.Scene.AssetCache;
255
256 cache.GetAsset(item.AssetID, delegate(UUID assetID, AssetBase asset)
257 {
258 if (null == asset)
259 {
260 m_log.ErrorFormat(
261 "[PRIM INVENTORY]: " +
262 "Couldn't start script {0}, {1} since asset ID {2} could not be found",
263 item.Name, item.ItemID, item.AssetID);
264 }
265 else
266 {
267 m_items[item.ItemID].PermsMask = 0;
268 m_items[item.ItemID].PermsGranter = UUID.Zero;
269 string script = Utils.BytesToString(asset.Data);
270 m_part.ParentGroup.Scene.EventManager.TriggerRezScript(
271 m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource);
272 m_part.ParentGroup.AddActiveScriptCount(1);
273 m_part.ScheduleFullUpdate();
274 }
275 }, false);
276 }
277 }
278
279 /// <summary>
280 /// Start a script which is in this prim's inventory.
281 /// </summary>
282 /// <param name="itemId">
283 /// A <see cref="UUID"/>
284 /// </param>
285 public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource)
286 {
287 lock (m_items)
288 {
289 if (m_items.ContainsKey(itemId))
290 {
291 CreateScriptInstance(m_items[itemId], startParam, postOnRez, engine, stateSource);
292 }
293 else
294 {
295 m_log.ErrorFormat(
296 "[PRIM INVENTORY]: " +
297 "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2}",
298 itemId, m_part.Name, m_part.UUID);
299 }
300 }
301 }
302
303 /// <summary>
304 /// Stop a script which is in this prim's inventory.
305 /// </summary>
306 /// <param name="itemId"></param>
307 public void RemoveScriptInstance(UUID itemId)
308 {
309 if (m_items.ContainsKey(itemId))
310 {
311 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemId);
312 m_part.ParentGroup.AddActiveScriptCount(-1);
313 }
314 else
315 {
316 m_log.ErrorFormat(
317 "[PRIM INVENTORY]: " +
318 "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2}",
319 itemId, m_part.Name, m_part.UUID);
320 }
321 }
322
323 /// <summary>
324 /// Check if the inventory holds an item with a given name.
325 /// This method assumes that the task inventory is already locked.
326 /// </summary>
327 /// <param name="name"></param>
328 /// <returns></returns>
329 private bool InventoryContainsName(string name)
330 {
331 foreach (TaskInventoryItem item in Items.Values)
332 {
333 if (item.Name == name)
334 return true;
335 }
336 return false;
337 }
338
339 /// <summary>
340 /// For a given item name, return that name if it is available. Otherwise, return the next available
341 /// similar name (which is currently the original name with the next available numeric suffix).
342 /// </summary>
343 /// <param name="name"></param>
344 /// <returns></returns>
345 private string FindAvailableInventoryName(string name)
346 {
347 if (!InventoryContainsName(name))
348 return name;
349
350 int suffix=1;
351 while (suffix < 256)
352 {
353 string tryName=String.Format("{0} {1}", name, suffix);
354 if (!InventoryContainsName(tryName))
355 return tryName;
356 suffix++;
357 }
358 return String.Empty;
359 }
360
361 /// <summary>
362 /// Add an item to this prim's inventory. If an item with the same name already exists, then an alternative
363 /// name is chosen.
364 /// </summary>
365 /// <param name="item"></param>
366 public void AddInventoryItem(TaskInventoryItem item, bool allowedDrop)
367 {
368 AddInventoryItem(item.Name, item, allowedDrop);
369 }
370
371 /// <summary>
372 /// Add an item to this prim's inventory. If an item with the same name already exists, it is replaced.
373 /// </summary>
374 /// <param name="item"></param>
375 public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop)
376 {
377 List<TaskInventoryItem> il = new List<TaskInventoryItem>(m_items.Values);
378 foreach (TaskInventoryItem i in il)
379 {
380 if (i.Name == item.Name)
381 {
382 if (i.InvType == (int)InventoryType.LSL)
383 RemoveScriptInstance(i.ItemID);
384
385 RemoveInventoryItem(i.ItemID);
386 break;
387 }
388 }
389
390 AddInventoryItem(item.Name, item, allowedDrop);
391 }
392
393 /// <summary>
394 /// Add an item to this prim's inventory.
395 /// </summary>
396 /// <param name="name">The name that the new item should have.</param>
397 /// <param name="item">
398 /// The item itself. The name within this structure is ignored in favour of the name
399 /// given in this method's arguments
400 /// </param>
401 /// <param name="allowedDrop">
402 /// Item was only added to inventory because AllowedDrop is set
403 /// </param>
404 protected void AddInventoryItem(string name, TaskInventoryItem item, bool allowedDrop)
405 {
406 name = FindAvailableInventoryName(name);
407 if (name == String.Empty)
408 return;
409
410 item.ParentID = m_part.UUID;
411 item.ParentPartID = m_part.UUID;
412 item.Name = name;
413
414 lock (m_items)
415 {
416 m_items.Add(item.ItemID, item);
417
418 if (allowedDrop)
419 m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP);
420 else
421 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
422 }
423
424 m_inventorySerial++;
425 //m_inventorySerial += 2;
426 HasInventoryChanged = true;
427 m_part.ParentGroup.HasGroupChanged = true;
428 }
429
430 /// <summary>
431 /// Restore a whole collection of items to the prim's inventory at once.
432 /// We assume that the items already have all their fields correctly filled out.
433 /// The items are not flagged for persistence to the database, since they are being restored
434 /// from persistence rather than being newly added.
435 /// </summary>
436 /// <param name="items"></param>
437 public void RestoreInventoryItems(ICollection<TaskInventoryItem> items)
438 {
439 lock (m_items)
440 {
441 foreach (TaskInventoryItem item in items)
442 {
443 m_items.Add(item.ItemID, item);
444 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
445 }
446 }
447
448 m_inventorySerial++;
449 }
450
451 /// <summary>
452 /// Returns an existing inventory item. Returns the original, so any changes will be live.
453 /// </summary>
454 /// <param name="itemID"></param>
455 /// <returns>null if the item does not exist</returns>
456 public TaskInventoryItem GetInventoryItem(UUID itemId)
457 {
458 TaskInventoryItem item;
459 m_items.TryGetValue(itemId, out item);
460
461 return item;
462 }
463
464 /// <summary>
465 /// Update an existing inventory item.
466 /// </summary>
467 /// <param name="item">The updated item. An item with the same id must already exist
468 /// in this prim's inventory.</param>
469 /// <returns>false if the item did not exist, true if the update occurred successfully</returns>
470 public bool UpdateInventoryItem(TaskInventoryItem item)
471 {
472 lock (m_items)
473 {
474 if (m_items.ContainsKey(item.ItemID))
475 {
476 item.ParentID = m_part.UUID;
477 item.ParentPartID = m_part.UUID;
478 item.Flags = m_items[item.ItemID].Flags;
479 if (item.AssetID == UUID.Zero)
480 {
481 item.AssetID = m_items[item.ItemID].AssetID;
482 }
483 else if ((InventoryType)item.Type == InventoryType.Notecard)
484 {
485 ScenePresence presence = m_part.ParentGroup.Scene.GetScenePresence(item.OwnerID);
486
487 if (presence != null)
488 {
489 presence.ControllingClient.SendAgentAlertMessage(
490 "Notecard saved", false);
491 }
492 }
493
494 m_items[item.ItemID] = item;
495 m_inventorySerial++;
496 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
497
498 HasInventoryChanged = true;
499 m_part.ParentGroup.HasGroupChanged = true;
500
501 return true;
502 }
503 else
504 {
505 m_log.ErrorFormat(
506 "[PRIM INVENTORY]: " +
507 "Tried to retrieve item ID {0} from prim {1}, {2} but the item does not exist in this inventory",
508 item.ItemID, m_part.Name, m_part.UUID);
509 }
510 }
511
512 return false;
513 }
514
515 /// <summary>
516 /// Remove an item from this prim's inventory
517 /// </summary>
518 /// <param name="itemID"></param>
519 /// <returns>Numeric asset type of the item removed. Returns -1 if the item did not exist
520 /// in this prim's inventory.</returns>
521 public int RemoveInventoryItem(UUID itemID)
522 {
523 lock (m_items)
524 {
525 if (m_items.ContainsKey(itemID))
526 {
527 int type = m_items[itemID].InvType;
528 if (type == 10) // Script
529 {
530 m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
531 }
532 m_items.Remove(itemID);
533 m_inventorySerial++;
534 m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
535
536 HasInventoryChanged = true;
537 m_part.ParentGroup.HasGroupChanged = true;
538
539 int scriptcount = 0;
540 lock (m_items)
541 {
542 foreach (TaskInventoryItem item in m_items.Values)
543 {
544 if (item.Type == 10)
545 {
546 scriptcount++;
547 }
548 }
549 }
550
551 if (scriptcount <= 0)
552 {
553 m_part.RemFlag(PrimFlags.Scripted);
554 }
555
556 m_part.ScheduleFullUpdate();
557
558 return type;
559 }
560 else
561 {
562 m_log.ErrorFormat(
563 "[PRIM INVENTORY]: " +
564 "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory",
565 itemID, m_part.Name, m_part.UUID);
566 }
567 }
568
569 return -1;
570 }
571
572 public string GetInventoryFileName()
573 {
574 if (m_inventoryFileName == String.Empty)
575 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp";
576 if (m_inventoryFileNameSerial < m_inventorySerial)
577 {
578 m_inventoryFileName = "inventory_" + UUID.Random().ToString() + ".tmp";
579 }
580 return m_inventoryFileName;
581 }
582
583 /// <summary>
584 /// Return the name with which a client can request a xfer of this prim's inventory metadata
585 /// </summary>
586 /// <param name="client"></param>
587 /// <param name="localID"></param>
588 public bool GetInventoryFileName(IClientAPI client, uint localID)
589 {
590// m_log.DebugFormat(
591// "[PRIM INVENTORY]: Received request from client {0} for inventory file name of {1}, {2}",
592// client.AgentId, Name, UUID);
593
594 if (m_inventorySerial > 0)
595 {
596 client.SendTaskInventory(m_part.UUID, (short)m_inventorySerial,
597 Utils.StringToBytes(GetInventoryFileName()));
598 return true;
599 }
600 else
601 {
602 client.SendTaskInventory(m_part.UUID, 0, new byte[0]);
603 return false;
604 }
605 }
606
607 /// <summary>
608 /// Serialize all the metadata for the items in this prim's inventory ready for sending to the client
609 /// </summary>
610 /// <param name="xferManager"></param>
611 public void RequestInventoryFile(IClientAPI client, IXfer xferManager)
612 {
613 byte[] fileData = new byte[0];
614
615 // Confusingly, the folder item has to be the object id, while the 'parent id' has to be zero. This matches
616 // what appears to happen in the Second Life protocol. If this isn't the case. then various functionality
617 // isn't available (such as drag from prim inventory to agent inventory)
618 InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero);
619
620 lock (m_items)
621 {
622 foreach (TaskInventoryItem item in m_items.Values)
623 {
624 UUID ownerID = item.OwnerID;
625 uint everyoneMask = 0;
626 uint baseMask = item.BasePermissions;
627 uint ownerMask = item.CurrentPermissions;
628
629 invString.AddItemStart();
630 invString.AddNameValueLine("item_id", item.ItemID.ToString());
631 invString.AddNameValueLine("parent_id", m_part.UUID.ToString());
632
633 invString.AddPermissionsStart();
634
635 invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask));
636 invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask));
637 invString.AddNameValueLine("group_mask", Utils.UIntToHexString(0));
638 invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask));
639 invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions));
640
641 invString.AddNameValueLine("creator_id", item.CreatorID.ToString());
642 invString.AddNameValueLine("owner_id", ownerID.ToString());
643
644 invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString());
645
646 invString.AddNameValueLine("group_id", item.GroupID.ToString());
647 invString.AddSectionEnd();
648
649 invString.AddNameValueLine("asset_id", item.AssetID.ToString());
650 invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]);
651 invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]);
652 invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags));
653
654 invString.AddSaleStart();
655 invString.AddNameValueLine("sale_type", "not");
656 invString.AddNameValueLine("sale_price", "0");
657 invString.AddSectionEnd();
658
659 invString.AddNameValueLine("name", item.Name + "|");
660 invString.AddNameValueLine("desc", item.Description + "|");
661
662 invString.AddNameValueLine("creation_date", item.CreationDate.ToString());
663 invString.AddSectionEnd();
664 }
665 }
666
667 fileData = Utils.StringToBytes(invString.BuildString);
668
669 //Console.WriteLine(Utils.BytesToString(fileData));
670 //m_log.Debug("[PRIM INVENTORY]: RequestInventoryFile fileData: " + Utils.BytesToString(fileData));
671
672 if (fileData.Length > 2)
673 {
674 xferManager.AddNewFile(m_inventoryFileName, fileData);
675 }
676 }
677
678 /// <summary>
679 /// Process inventory backup
680 /// </summary>
681 /// <param name="datastore"></param>
682 public void ProcessInventoryBackup(IRegionDataStore datastore)
683 {
684 if (HasInventoryChanged)
685 {
686 lock (Items)
687 {
688 datastore.StorePrimInventory(m_part.UUID, Items.Values);
689 }
690
691 HasInventoryChanged = false;
692 }
693 }
694
695 public class InventoryStringBuilder
696 {
697 public string BuildString = String.Empty;
698
699 public InventoryStringBuilder(UUID folderID, UUID parentID)
700 {
701 BuildString += "\tinv_object\t0\n\t{\n";
702 AddNameValueLine("obj_id", folderID.ToString());
703 AddNameValueLine("parent_id", parentID.ToString());
704 AddNameValueLine("type", "category");
705 AddNameValueLine("name", "Contents|");
706 AddSectionEnd();
707 }
708
709 public void AddItemStart()
710 {
711 BuildString += "\tinv_item\t0\n";
712 AddSectionStart();
713 }
714
715 public void AddPermissionsStart()
716 {
717 BuildString += "\tpermissions 0\n";
718 AddSectionStart();
719 }
720
721 public void AddSaleStart()
722 {
723 BuildString += "\tsale_info\t0\n";
724 AddSectionStart();
725 }
726
727 protected void AddSectionStart()
728 {
729 BuildString += "\t{\n";
730 }
731
732 public void AddSectionEnd()
733 {
734 BuildString += "\t}\n";
735 }
736
737 public void AddLine(string addLine)
738 {
739 BuildString += addLine;
740 }
741
742 public void AddNameValueLine(string name, string value)
743 {
744 BuildString += "\t\t";
745 BuildString += name + "\t";
746 BuildString += value + "\n";
747 }
748
749 public void Close()
750 {
751 }
752 }
753
754 public uint MaskEffectivePermissions()
755 {
756 uint mask=0x7fffffff;
757
758 foreach (TaskInventoryItem item in m_items.Values)
759 {
760 if (item.InvType != 6)
761 {
762 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Copy) == 0)
763 mask &= ~((uint)PermissionMask.Copy >> 13);
764 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Transfer) == 0)
765 mask &= ~((uint)PermissionMask.Transfer >> 13);
766 if ((item.CurrentPermissions & item.NextPermissions & (uint)PermissionMask.Modify) == 0)
767 mask &= ~((uint)PermissionMask.Modify >> 13);
768 }
769 else
770 {
771 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
772 mask &= ~((uint)PermissionMask.Copy >> 13);
773 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
774 mask &= ~((uint)PermissionMask.Transfer >> 13);
775 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
776 mask &= ~((uint)PermissionMask.Modify >> 13);
777 }
778
779 if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
780 mask &= ~(uint)PermissionMask.Copy;
781 if ((item.CurrentPermissions & (uint)PermissionMask.Transfer) == 0)
782 mask &= ~(uint)PermissionMask.Transfer;
783 if ((item.CurrentPermissions & (uint)PermissionMask.Modify) == 0)
784 mask &= ~(uint)PermissionMask.Modify;
785 }
786 return mask;
787 }
788
789 public void ApplyNextOwnerPermissions()
790 {
791 foreach (TaskInventoryItem item in m_items.Values)
792 {
793 if (item.InvType == 6 && (item.CurrentPermissions & 7) != 0)
794 {
795 if ((item.CurrentPermissions & ((uint)PermissionMask.Copy >> 13)) == 0)
796 item.CurrentPermissions &= ~(uint)PermissionMask.Copy;
797 if ((item.CurrentPermissions & ((uint)PermissionMask.Transfer >> 13)) == 0)
798 item.CurrentPermissions &= ~(uint)PermissionMask.Transfer;
799 if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0)
800 item.CurrentPermissions &= ~(uint)PermissionMask.Modify;
801 item.CurrentPermissions |= 8;
802 }
803 item.CurrentPermissions &= item.NextPermissions;
804 item.BasePermissions &= item.NextPermissions;
805 item.EveryonePermissions &= item.NextPermissions;
806 }
807
808 m_part.TriggerScriptChangedEvent(Changed.OWNER);
809 }
810
811 public void ApplyGodPermissions(uint perms)
812 {
813 foreach (TaskInventoryItem item in m_items.Values)
814 {
815 item.CurrentPermissions = perms;
816 item.BasePermissions = perms;
817 }
818 }
819
820 public bool ContainsScripts()
821 {
822 foreach (TaskInventoryItem item in m_items.Values)
823 {
824 if (item.InvType == 10)
825 {
826 return true;
827 }
828 }
829 return false;
830 }
831
832 public List<UUID> GetInventoryList()
833 {
834 List<UUID> ret = new List<UUID>();
835
836 foreach (TaskInventoryItem item in m_items.Values)
837 ret.Add(item.ItemID);
838
839 return ret;
840 }
841
842 public string[] GetScriptAssemblies()
843 {
844 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
845
846 List<string> ret = new List<string>();
847
848 foreach (TaskInventoryItem item in m_items.Values)
849 {
850 if (item.InvType == 10)
851 {
852 foreach (IScriptModule e in engines)
853 {
854 string n = e.GetAssemblyName(item.ItemID);
855 if (n != "")
856 {
857 if (!ret.Contains(n))
858 ret.Add(n);
859 break;
860 }
861 }
862 }
863 }
864 return ret.ToArray();
865 }
866
867 public Dictionary<UUID, string> GetScriptStates()
868 {
869 IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces<IScriptModule>();
870 Dictionary<UUID, string> ret = new Dictionary<UUID, string>();
871
872 foreach (TaskInventoryItem item in m_items.Values)
873 {
874 if (item.InvType == 10)
875 {
876 foreach (IScriptModule e in engines)
877 {
878 string n = e.GetXMLState(item.ItemID);
879 if (n != "")
880 {
881 if (!ret.ContainsKey(item.ItemID))
882 ret[item.ItemID] = n;
883 break;
884 }
885 }
886 }
887 }
888 return ret;
889 }
890 }
891}
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
new file mode 100644
index 0000000..36cd862
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -0,0 +1,3649 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Runtime.Serialization;
32using System.Security.Permissions;
33using OpenMetaverse;
34using OpenMetaverse.Packets;
35using log4net;
36using OpenSim.Framework;
37using OpenSim.Framework.Client;
38using OpenSim.Framework.Communications.Cache;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes.Types;
41using OpenSim.Region.Physics.Manager;
42using OSD = OpenMetaverse.StructuredData.OSD;
43
44namespace OpenSim.Region.Framework.Scenes
45{
46 enum ScriptControlled : uint
47 {
48 CONTROL_ZERO = 0,
49 CONTROL_FWD = 1,
50 CONTROL_BACK = 2,
51 CONTROL_LEFT = 4,
52 CONTROL_RIGHT = 8,
53 CONTROL_UP = 16,
54 CONTROL_DOWN = 32,
55 CONTROL_ROT_LEFT = 256,
56 CONTROL_ROT_RIGHT = 512,
57 CONTROL_LBUTTON = 268435456,
58 CONTROL_ML_LBUTTON = 1073741824
59 }
60
61 struct ScriptControllers
62 {
63 public UUID itemID;
64 public uint objID;
65 public ScriptControlled ignoreControls;
66 public ScriptControlled eventControls;
67 }
68
69 [Serializable]
70 public class ScenePresence : EntityBase, ISerializable
71 {
72// ~ScenePresence()
73// {
74// System.Console.WriteLine("[ScenePresence] Destructor called");
75// }
76
77 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
78
79 public static byte[] DefaultTexture;
80
81 public UUID currentParcelUUID = UUID.Zero;
82 private AnimationSet m_animations = new AnimationSet();
83 private Dictionary<UUID, ScriptControllers> scriptedcontrols = new Dictionary<UUID, ScriptControllers>();
84 private ScriptControlled IgnoredControls = ScriptControlled.CONTROL_ZERO;
85 private ScriptControlled LastCommands = ScriptControlled.CONTROL_ZERO;
86 private bool MouseDown = false;
87 private SceneObjectGroup proxyObjectGroup = null;
88 //private SceneObjectPart proxyObjectPart = null;
89
90 public Vector3 lastKnownAllowedPosition = new Vector3();
91 public bool sentMessageAboutRestrictedParcelFlyingDown = false;
92
93 private bool m_updateflag = false;
94 private byte m_movementflag = 0;
95 private readonly List<NewForce> m_forcesList = new List<NewForce>();
96 private short m_updateCount = 0;
97 private uint m_requestedSitTargetID = 0;
98 private UUID m_requestedSitTargetUUID = UUID.Zero;
99
100 private bool m_startAnimationSet = false;
101
102 private Vector3 m_requestedSitOffset = new Vector3();
103
104 private Vector3 m_LastFinitePos = new Vector3();
105
106 private float m_sitAvatarHeight = 2.0f;
107
108 // experimentally determined "fudge factor" to make sit-target positions
109 // the same as in SecondLife. Fudge factor was tested for 36 different
110 // test cases including prims of type box, sphere, cylinder, and torus,
111 // with varying parameters for sit target location, prim size, prim
112 // rotation, prim cut, prim twist, prim taper, and prim shear. See mantis
113 // issue #1716
114 private static readonly Vector3 m_sitTargetCorrectionOffset = new Vector3(0.1f, 0.0f, 0.3f);
115 private float m_godlevel = 0;
116
117 private bool m_invulnerable = true;
118
119 private Vector3 m_LastChildAgentUpdatePosition = new Vector3();
120
121 private int m_perfMonMS = 0;
122
123 private bool m_setAlwaysRun = false;
124
125 private Quaternion m_bodyRot= Quaternion.Identity;
126
127 public bool IsRestrictedToRegion = false;
128
129 public string JID = string.Empty;
130
131 // Agent moves with a PID controller causing a force to be exerted.
132 private bool m_newForce = false;
133 private bool m_newCoarseLocations = true;
134 private float m_health = 100f;
135
136 private Vector3 m_lastVelocity = Vector3.Zero;
137
138 // Default AV Height
139 private float m_avHeight = 127.0f;
140
141 protected RegionInfo m_regionInfo;
142 protected ulong crossingFromRegion = 0;
143
144 private readonly Vector3[] Dir_Vectors = new Vector3[6];
145
146 /// <value>
147 /// The avatar position last sent to clients
148 /// </value>
149 private Vector3 lastPhysPos = Vector3.Zero;
150
151 /// <value>
152 /// The avatar body rotation last sent to clients
153 /// </value>
154 private Quaternion lastPhysRot = Quaternion.Identity;
155
156 // Position of agent's camera in world (region cordinates)
157 protected Vector3 m_CameraCenter = Vector3.Zero;
158
159 // Use these three vectors to figure out what the agent is looking at
160 // Convert it to a Matrix and/or Quaternion
161 protected Vector3 m_CameraAtAxis = Vector3.Zero;
162 protected Vector3 m_CameraLeftAxis = Vector3.Zero;
163 protected Vector3 m_CameraUpAxis = Vector3.Zero;
164 private uint m_AgentControlFlags = 0;
165 private Quaternion m_headrotation = Quaternion.Identity;
166 private byte m_state = 0;
167
168 //Reuse the Vector3 instead of creating a new one on the UpdateMovement method
169 private Vector3 movementvector = Vector3.Zero;
170
171 private bool m_autopilotMoving = false;
172 private Vector3 m_autoPilotTarget = Vector3.Zero;
173 private bool m_sitAtAutoTarget = false;
174
175 private string m_nextSitAnimation = String.Empty;
176
177 //PauPaw:Proper PID Controler for autopilot************
178 private bool m_moveToPositionInProgress = false;
179 private Vector3 m_moveToPositionTarget = Vector3.Zero;
180 //private int m_moveToPositionStateStatus = 0;
181 //*****************************************************
182
183 // Agent's Draw distance.
184 protected float m_DrawDistance = 0f;
185
186 protected AvatarAppearance m_appearance;
187
188 protected List<SceneObjectGroup> m_attachments = new List<SceneObjectGroup>();
189
190 // neighbouring regions we have enabled a child agent in
191 // holds the seed cap for the child agent in that region
192 private Dictionary<ulong, string> m_knownChildRegions = new Dictionary<ulong, string>();
193
194 /// <summary>
195 /// Implemented Control Flags
196 /// </summary>
197 private enum Dir_ControlFlags
198 {
199 DIR_CONTROL_FLAG_FORWARD = AgentManager.ControlFlags.AGENT_CONTROL_AT_POS,
200 DIR_CONTROL_FLAG_BACK = AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG,
201 DIR_CONTROL_FLAG_LEFT = AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS,
202 DIR_CONTROL_FLAG_RIGHT = AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG,
203 DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS,
204 DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG,
205 DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG
206 }
207
208 /// <summary>
209 /// Position at which a significant movement was made
210 /// </summary>
211 private Vector3 posLastSignificantMove = new Vector3();
212
213 private UpdateQueue m_partsUpdateQueue = new UpdateQueue();
214 private Queue<SceneObjectGroup> m_pendingObjects = null;
215
216 private Dictionary<UUID, ScenePartUpdate> m_updateTimes = new Dictionary<UUID, ScenePartUpdate>();
217
218 // For teleports and crossings callbacks
219 string m_callbackURI;
220 ulong m_rootRegionHandle;
221
222 #region Properties
223
224 /// <summary>
225 /// Physical scene representation of this Avatar.
226 /// </summary>
227 public PhysicsActor PhysicsActor
228 {
229 set { m_physicsActor = value; }
230 get { return m_physicsActor; }
231 }
232
233 public byte MovementFlag
234 {
235 set { m_movementflag = value; }
236 get { return m_movementflag; }
237 }
238
239 public bool Updated
240 {
241 set { m_updateflag = value; }
242 get { return m_updateflag; }
243 }
244
245 public bool Invulnerable
246 {
247 set { m_invulnerable = value; }
248 get { return m_invulnerable; }
249 }
250
251 public float GodLevel
252 {
253 get { return m_godlevel; }
254 }
255
256 private readonly ulong m_regionHandle;
257
258 public ulong RegionHandle
259 {
260 get { return m_regionHandle; }
261 }
262
263 public Vector3 CameraPosition
264 {
265 get { return m_CameraCenter; }
266 }
267
268 public Quaternion CameraRotation
269 {
270 get { return Util.Axes2Rot(m_CameraAtAxis, m_CameraLeftAxis, m_CameraUpAxis); }
271 }
272
273 public Vector3 Lookat
274 {
275 get
276 {
277 Vector3 a = new Vector3(m_CameraAtAxis.X, m_CameraAtAxis.Y, 0);
278
279 if (a == Vector3.Zero)
280 return a;
281
282 return Util.GetNormalizedVector(a);
283 }
284 }
285
286 private readonly string m_firstname;
287
288 public string Firstname
289 {
290 get { return m_firstname; }
291 }
292
293 private readonly string m_lastname;
294
295 public string Lastname
296 {
297 get { return m_lastname; }
298 }
299
300 private string m_grouptitle;
301
302 public string Grouptitle
303 {
304 get { return m_grouptitle; }
305 set { m_grouptitle = value; }
306 }
307
308 public float DrawDistance
309 {
310 get { return m_DrawDistance; }
311 }
312
313 protected bool m_allowMovement = true;
314
315 public bool AllowMovement
316 {
317 get { return m_allowMovement; }
318 set { m_allowMovement = value; }
319 }
320
321 public bool SetAlwaysRun
322 {
323 get
324 {
325 if (PhysicsActor != null)
326 {
327 return PhysicsActor.SetAlwaysRun;
328 }
329 else
330 {
331 return m_setAlwaysRun;
332 }
333 }
334 set
335 {
336 m_setAlwaysRun = value;
337 if (PhysicsActor != null)
338 {
339 PhysicsActor.SetAlwaysRun = value;
340 }
341 }
342 }
343
344 public byte State
345 {
346 get { return m_state; }
347 set { m_state = value; }
348 }
349
350 public uint AgentControlFlags
351 {
352 get { return m_AgentControlFlags; }
353 set { m_AgentControlFlags = value; }
354 }
355
356 /// <summary>
357 /// This works out to be the ClientView object associated with this avatar, or it's client connection manager
358 /// </summary>
359 private IClientAPI m_controllingClient;
360
361 protected PhysicsActor m_physicsActor;
362
363 /// <value>
364 /// The client controlling this presence
365 /// </value>
366 public IClientAPI ControllingClient
367 {
368 get { return m_controllingClient; }
369 }
370
371 public IClientCore ClientView
372 {
373 get { return (IClientCore) m_controllingClient; }
374 }
375
376 protected Vector3 m_parentPosition = new Vector3();
377 public Vector3 ParentPosition
378 {
379 get { return m_parentPosition; }
380 set { m_parentPosition = value; }
381 }
382
383 /// <summary>
384 /// Absolute position of this avatar in 'region cordinates'
385 /// </summary>
386 public override Vector3 AbsolutePosition
387 {
388 get
389 {
390 if (m_physicsActor != null)
391 {
392 m_pos.X = m_physicsActor.Position.X;
393 m_pos.Y = m_physicsActor.Position.Y;
394 m_pos.Z = m_physicsActor.Position.Z;
395 }
396
397 return m_parentPosition + m_pos;
398 }
399 set
400 {
401 if (m_physicsActor != null)
402 {
403 try
404 {
405 lock (m_scene.SyncRoot)
406 {
407 m_physicsActor.Position = new PhysicsVector(value.X, value.Y, value.Z);
408 }
409 }
410 catch (Exception e)
411 {
412 Console.WriteLine("[SCENEPRESENCE]: ABSOLUTE POSITION " + e.Message);
413 }
414 }
415
416 m_pos = value;
417 m_parentPosition = new Vector3(0, 0, 0);
418 }
419 }
420
421 /// <summary>
422 /// Current velocity of the avatar.
423 /// </summary>
424 public override Vector3 Velocity
425 {
426 get
427 {
428 if (m_physicsActor != null)
429 {
430 m_velocity.X = m_physicsActor.Velocity.X;
431 m_velocity.Y = m_physicsActor.Velocity.Y;
432 m_velocity.Z = m_physicsActor.Velocity.Z;
433 }
434
435 return m_velocity;
436 }
437 set
438 {
439 //m_log.DebugFormat("In {0} setting velocity of {1} to {2}", m_scene.RegionInfo.RegionName, Name, value);
440
441 if (m_physicsActor != null)
442 {
443 try
444 {
445 lock (m_scene.SyncRoot)
446 {
447 m_physicsActor.Velocity = new PhysicsVector(value.X, value.Y, value.Z);
448 }
449 }
450 catch (Exception e)
451 {
452 Console.WriteLine("[SCENEPRESENCE]: VELOCITY " + e.Message);
453 }
454 }
455
456 m_velocity = value;
457 }
458 }
459
460 /// <summary>
461 /// If this is true, agent doesn't have a representation in this scene.
462 /// this is an agent 'looking into' this scene from a nearby scene(region)
463 ///
464 /// if False, this agent has a representation in this scene
465 /// </summary>
466 private bool m_isChildAgent = true;
467
468 public bool IsChildAgent
469 {
470 get { return m_isChildAgent; }
471 set { m_isChildAgent = value; }
472 }
473
474 private uint m_parentID = 0;
475
476 public uint ParentID
477 {
478 get { return m_parentID; }
479 set { m_parentID = value; }
480 }
481 public float Health
482 {
483 get { return m_health; }
484 set { m_health = value; }
485 }
486
487 /// <summary>
488 /// These are the region handles known by the avatar.
489 /// </summary>
490 public List<ulong> KnownChildRegionHandles
491 {
492 get
493 {
494 if (m_knownChildRegions.Count == 0)
495 return new List<ulong>();
496 else
497 return new List<ulong>(m_knownChildRegions.Keys);
498 }
499 }
500
501 public Dictionary<ulong, string> KnownRegions
502 {
503 get { return m_knownChildRegions; }
504 set
505 {
506 m_knownChildRegions = value;
507 }
508 }
509
510 public void AdjustKnownSeeds()
511 {
512 Dictionary<ulong, string> seeds = Scene.CapsModule.GetChildrenSeeds(UUID);
513 List<ulong> old = new List<ulong>();
514 foreach (ulong handle in seeds.Keys)
515 {
516 uint x, y;
517 Utils.LongToUInts(handle, out x, out y);
518 x = x / Constants.RegionSize;
519 y = y / Constants.RegionSize;
520 if (Util.IsOutsideView(x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY))
521 {
522 old.Add(handle);
523 }
524 }
525 DropOldNeighbours(old);
526 Scene.CapsModule.SetChildrenSeed(UUID, seeds);
527 KnownRegions = seeds;
528 //Console.WriteLine(" ++++++++++AFTER+++++++++++++ ");
529 //DumpKnownRegions();
530 }
531
532 public void DumpKnownRegions()
533 {
534 Console.WriteLine("================ KnownRegions {0} ================", Scene.RegionInfo.RegionName);
535 foreach (KeyValuePair<ulong, string> kvp in KnownRegions)
536 {
537 uint x, y;
538 Utils.LongToUInts(kvp.Key, out x, out y);
539 x = x / Constants.RegionSize;
540 y = y / Constants.RegionSize;
541 Console.WriteLine(" >> {0}, {1}: {2}", x, y, kvp.Value);
542 }
543 }
544
545 public AnimationSet Animations
546 {
547 get { return m_animations; }
548 }
549
550 #endregion
551
552 #region Constructor(s)
553
554 private ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo)
555 {
556 m_regionHandle = reginfo.RegionHandle;
557 m_controllingClient = client;
558 m_firstname = m_controllingClient.FirstName;
559 m_lastname = m_controllingClient.LastName;
560 m_name = String.Format("{0} {1}", m_firstname, m_lastname);
561
562 m_scene = world;
563 m_uuid = client.AgentId;
564 m_regionInfo = reginfo;
565 m_localId = m_scene.AllocateLocalId();
566
567 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
568 if (gm != null)
569 m_grouptitle = gm.GetGroupTitle(m_uuid);
570
571 AbsolutePosition = m_controllingClient.StartPos;
572 AdjustKnownSeeds();
573
574 TrySetMovementAnimation("STAND"); // TODO: I think, this won't send anything, as we are still a child here...
575
576 // we created a new ScenePresence (a new child agent) in a fresh region.
577 // Request info about all the (root) agents in this region
578 // Note: This won't send data *to* other clients in that region (children don't send)
579 SendInitialFullUpdateToAllClients();
580
581 RegisterToEvents();
582 SetDirectionVectors();
583
584 CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(m_uuid);
585 if (userInfo != null)
586 userInfo.OnItemReceived += ItemReceived;
587 }
588
589 public ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo, byte[] visualParams,
590 AvatarWearable[] wearables)
591 : this(client, world, reginfo)
592 {
593 m_appearance = new AvatarAppearance(m_uuid, wearables, visualParams);
594 }
595
596 public ScenePresence(IClientAPI client, Scene world, RegionInfo reginfo, AvatarAppearance appearance)
597 : this(client, world, reginfo)
598 {
599 m_appearance = appearance;
600 }
601
602 public void RegisterToEvents()
603 {
604 m_controllingClient.OnRequestWearables += SendWearables;
605 m_controllingClient.OnSetAppearance += SetAppearance;
606 m_controllingClient.OnCompleteMovementToRegion += CompleteMovement;
607 m_controllingClient.OnCompleteMovementToRegion += SendInitialData;
608 m_controllingClient.OnAgentUpdate += HandleAgentUpdate;
609 m_controllingClient.OnAgentRequestSit += HandleAgentRequestSit;
610 m_controllingClient.OnAgentSit += HandleAgentSit;
611 m_controllingClient.OnSetAlwaysRun += HandleSetAlwaysRun;
612 m_controllingClient.OnStartAnim += HandleStartAnim;
613 m_controllingClient.OnStopAnim += HandleStopAnim;
614 m_controllingClient.OnForceReleaseControls += HandleForceReleaseControls;
615 m_controllingClient.OnAutoPilotGo += DoAutoPilot;
616 m_controllingClient.AddGenericPacketHandler("autopilot", DoMoveToPosition);
617
618 // ControllingClient.OnChildAgentStatus += new StatusChange(this.ChildStatusChange);
619 // ControllingClient.OnStopMovement += new GenericCall2(this.StopMovement);
620 }
621
622 private void SetDirectionVectors()
623 {
624 Dir_Vectors[0] = new Vector3(1, 0, 0); //FORWARD
625 Dir_Vectors[1] = new Vector3(-1, 0, 0); //BACK
626 Dir_Vectors[2] = new Vector3(0, 1, 0); //LEFT
627 Dir_Vectors[3] = new Vector3(0, -1, 0); //RIGHT
628 Dir_Vectors[4] = new Vector3(0, 0, 1); //UP
629 Dir_Vectors[5] = new Vector3(0, 0, -1); //DOWN
630 Dir_Vectors[5] = new Vector3(0, 0, -0.5f); //DOWN_Nudge
631 }
632
633 #endregion
634
635 /// <summary>
636 /// Add the part to the queue of parts for which we need to send an update to the client
637 /// </summary>
638 /// <param name="part"></param>
639 public void QueuePartForUpdate(SceneObjectPart part)
640 {
641 //if (InterestList.Contains(part.ParentGroup))
642 //{
643 lock (m_partsUpdateQueue)
644 {
645 m_partsUpdateQueue.Enqueue(part);
646 }
647 // }
648 }
649
650 public uint GenerateClientFlags(UUID ObjectID)
651 {
652 return m_scene.Permissions.GenerateClientFlags(m_uuid, ObjectID);
653 }
654
655 /// <summary>
656 /// Send updates to the client about prims which have been placed on the update queue. We don't
657 /// necessarily send updates for all the parts on the queue, e.g. if an updates with a more recent
658 /// timestamp has already been sent.
659 /// </summary>
660 public void SendPrimUpdates()
661 {
662 // if (m_scene.QuadTree.GetNodeID(this.AbsolutePosition.X, this.AbsolutePosition.Y) != m_currentQuadNode)
663 //{
664 // this.UpdateQuadTreeNode();
665 //this.RefreshQuadObject();
666 //}
667 m_perfMonMS = System.Environment.TickCount;
668
669 if (m_pendingObjects == null)
670 {
671 if (!m_isChildAgent || m_scene.m_seeIntoRegionFromNeighbor)
672 {
673 m_pendingObjects = new Queue<SceneObjectGroup>();
674
675 List<EntityBase> ents = new List<EntityBase>(m_scene.Entities);
676 if (!m_isChildAgent) // Proximity sort makes no sense for
677 { // Child agents
678 ents.Sort(delegate(EntityBase a, EntityBase b)
679 {
680 return Vector3.Distance(AbsolutePosition, a.AbsolutePosition).CompareTo(Vector3.Distance(AbsolutePosition, b.AbsolutePosition));
681 });
682 }
683
684 foreach (EntityBase e in ents)
685 {
686 if (e is SceneObjectGroup)
687 m_pendingObjects.Enqueue((SceneObjectGroup)e);
688 }
689 }
690 }
691
692 while (m_pendingObjects.Count > 0 && m_partsUpdateQueue.Count < 60)
693 {
694 SceneObjectGroup g = m_pendingObjects.Dequeue();
695
696 // This is where we should check for draw distance
697 // do culling and stuff. Problem with that is that until
698 // we recheck in movement, that won't work right.
699 // So it's not implemented now.
700 //
701
702 // Don't even queue if we have sent this one
703 //
704 if (!m_updateTimes.ContainsKey(g.UUID))
705 g.ScheduleFullUpdateToAvatar(this);
706 }
707
708 int updateCount = 0;
709
710 while (m_partsUpdateQueue.Count > 0)
711 {
712 SceneObjectPart part = m_partsUpdateQueue.Dequeue();
713
714 if (part.ParentGroup == null || part.ParentGroup.IsDeleted)
715 continue;
716
717 if (m_updateTimes.ContainsKey(part.UUID))
718 {
719 ScenePartUpdate update = m_updateTimes[part.UUID];
720
721 // We deal with the possibility that two updates occur at
722 // the same unix time at the update point itself.
723
724 if ((update.LastFullUpdateTime < part.TimeStampFull) ||
725 part.IsAttachment)
726 {
727// m_log.DebugFormat(
728// "[SCENE PRESENCE]: Fully updating prim {0}, {1} - part timestamp {2}",
729// part.Name, part.UUID, part.TimeStampFull);
730
731 part.SendFullUpdate(ControllingClient,
732 GenerateClientFlags(part.UUID));
733
734 // We'll update to the part's timestamp rather than
735 // the current time to avoid the race condition
736 // whereby the next tick occurs while we are doing
737 // this update. If this happened, then subsequent
738 // updates which occurred on the same tick or the
739 // next tick of the last update would be ignored.
740
741 update.LastFullUpdateTime = part.TimeStampFull;
742
743 updateCount++;
744 }
745 else if (update.LastTerseUpdateTime <= part.TimeStampTerse)
746 {
747// m_log.DebugFormat(
748// "[SCENE PRESENCE]: Tersely updating prim {0}, {1} - part timestamp {2}",
749// part.Name, part.UUID, part.TimeStampTerse);
750
751 part.SendTerseUpdateToClient(ControllingClient);
752
753 update.LastTerseUpdateTime = part.TimeStampTerse;
754 updateCount++;
755 }
756 }
757 else
758 {
759 //never been sent to client before so do full update
760 ScenePartUpdate update = new ScenePartUpdate();
761 update.FullID = part.UUID;
762 update.LastFullUpdateTime = part.TimeStampFull;
763 m_updateTimes.Add(part.UUID, update);
764
765 // Attachment handling
766 //
767 if (part.ParentGroup.RootPart.Shape.PCode == 9 && part.ParentGroup.RootPart.Shape.State != 0)
768 {
769 if (part != part.ParentGroup.RootPart)
770 continue;
771
772 part.ParentGroup.SendFullUpdateToClient(ControllingClient);
773 continue;
774 }
775
776 part.SendFullUpdate(ControllingClient,
777 GenerateClientFlags(part.UUID));
778 updateCount++;
779 }
780
781 if (updateCount > 60)
782 break;
783 }
784
785 m_scene.AddAgentTime(System.Environment.TickCount - m_perfMonMS);
786 }
787
788 #region Status Methods
789
790 /// <summary>
791 /// This turns a child agent, into a root agent
792 /// This is called when an agent teleports into a region, or if an
793 /// agent crosses into this region from a neighbor over the border
794 /// </summary>
795 public void MakeRootAgent(Vector3 pos, bool isFlying)
796 {
797 m_log.DebugFormat(
798 "[SCENE]: Upgrading child to root agent for {0} in {1}",
799 Name, m_scene.RegionInfo.RegionName);
800
801 //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
802
803 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
804 if (gm != null)
805 m_grouptitle = gm.GetGroupTitle(m_uuid);
806
807 m_scene.SetRootAgentScene(m_uuid);
808
809 // Moved this from SendInitialData to ensure that m_appearance is initialized
810 // before the inventory is processed in MakeRootAgent. This fixes a race condition
811 // related to the handling of attachments
812 m_scene.GetAvatarAppearance(m_controllingClient, out m_appearance);
813
814 if (pos.X < 0 || pos.X > Constants.RegionSize || pos.Y < 0 || pos.Y > Constants.RegionSize || pos.Z < 0)
815 {
816 Vector3 emergencyPos = new Vector3(128, 128, 128);
817
818 m_log.WarnFormat(
819 "[SCENE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}",
820 pos, Name, UUID, emergencyPos);
821
822 pos = emergencyPos;
823 }
824
825 m_isChildAgent = false;
826
827 float localAVHeight = 1.56f;
828 if (m_avHeight != 127.0f)
829 {
830 localAVHeight = m_avHeight;
831 }
832
833 float posZLimit = (float)m_scene.GetLandHeight((int)pos.X, (int)pos.Y);
834 float newPosZ = posZLimit + localAVHeight / 2;
835 if (posZLimit >= (pos.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
836 {
837 pos.Z = newPosZ;
838 }
839 AbsolutePosition = pos;
840
841 AddToPhysicalScene();
842 m_physicsActor.Flying = isFlying;
843
844 // Don't send an animation pack here, since on a region crossing this will sometimes cause a flying
845 // avatar to return to the standing position in mid-air. On login it looks like this is being sent
846 // elsewhere anyway
847 //SendAnimPack();
848
849 m_scene.SwapRootAgentCount(false);
850 m_scene.CommsManager.UserProfileCacheService.RequestInventoryForUser(m_uuid);
851 m_scene.CapsModule.AddCapsHandler(m_uuid);
852
853 // On the next prim update, all objects will be sent
854 //
855 m_pendingObjects = null;
856
857 m_scene.EventManager.TriggerOnMakeRootAgent(this);
858 }
859
860 /// <summary>
861 /// This turns a root agent into a child agent
862 /// when an agent departs this region for a neighbor, this gets called.
863 ///
864 /// It doesn't get called for a teleport. Reason being, an agent that
865 /// teleports out may not end up anywhere near this region
866 /// </summary>
867 public void MakeChildAgent()
868 {
869 m_animations.Clear();
870
871// m_log.DebugFormat(
872// "[SCENEPRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}",
873// Name, UUID, m_scene.RegionInfo.RegionName);
874
875 // Don't zero out the velocity since this can cause problems when an avatar is making a region crossing,
876 // depending on the exact timing. This shouldn't matter anyway since child agent positions are not updated.
877 //Velocity = new Vector3(0, 0, 0);
878
879 m_isChildAgent = true;
880 m_scene.SwapRootAgentCount(true);
881 RemoveFromPhysicalScene();
882 m_scene.EventManager.TriggerOnMakeChildAgent(this);
883 }
884
885 /// <summary>
886 /// Removes physics plugin scene representation of this agent if it exists.
887 /// </summary>
888 private void RemoveFromPhysicalScene()
889 {
890 if (PhysicsActor != null)
891 {
892 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor);
893 m_physicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients;
894 m_physicsActor.UnSubscribeEvents();
895 m_physicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate;
896 PhysicsActor = null;
897 }
898 }
899
900 /// <summary>
901 ///
902 /// </summary>
903 /// <param name="pos"></param>
904 public void Teleport(Vector3 pos)
905 {
906 RemoveFromPhysicalScene();
907 Velocity = new Vector3(0, 0, 0);
908 AbsolutePosition = pos;
909 AddToPhysicalScene();
910 SendTerseUpdateToAllClients();
911 }
912
913 /// <summary>
914 ///
915 /// </summary>
916 public void StopMovement()
917 {
918 }
919
920 public void StopFlying()
921 {
922 // It turns out to get the agent to stop flying, you have to feed it stop flying velocities
923 // and send a full object update.
924 // There's no message to send the client to tell it to stop flying
925
926 // Add 1/6 the avatar's height to it's position so it doesn't shoot into the air
927 // when the avatar stands up
928
929 if (m_avHeight != 127.0f)
930 {
931 AbsolutePosition = AbsolutePosition + new Vector3(0, 0, (m_avHeight / 6f));
932 }
933 else
934 {
935 AbsolutePosition = AbsolutePosition + new Vector3(0, 0, (1.56f / 6f));
936 }
937 TrySetMovementAnimation("LAND");
938 SendFullUpdateToAllClients();
939 }
940
941 public void AddNeighbourRegion(ulong regionHandle, string cap)
942 {
943 lock (m_knownChildRegions)
944 {
945 if (!m_knownChildRegions.ContainsKey(regionHandle))
946 {
947 uint x, y;
948 Utils.LongToUInts(regionHandle, out x, out y);
949 m_knownChildRegions.Add(regionHandle, cap);
950 }
951 }
952 }
953
954 public void RemoveNeighbourRegion(ulong regionHandle)
955 {
956 lock (m_knownChildRegions)
957 {
958 if (m_knownChildRegions.ContainsKey(regionHandle))
959 {
960 m_knownChildRegions.Remove(regionHandle);
961 //Console.WriteLine(" !!! removing known region {0} in {1}. Count = {2}", regionHandle, Scene.RegionInfo.RegionName, m_knownChildRegions.Count);
962 }
963 }
964 }
965
966 public void DropOldNeighbours(List<ulong> oldRegions)
967 {
968 foreach (ulong handle in oldRegions)
969 {
970 RemoveNeighbourRegion(handle);
971 Scene.CapsModule.DropChildSeed(UUID, handle);
972 }
973 }
974
975 public List<ulong> GetKnownRegionList()
976 {
977 return new List<ulong>(m_knownChildRegions.Keys);
978 }
979
980 #endregion
981
982 #region Event Handlers
983
984 /// <summary>
985 /// Sets avatar height in the phyiscs plugin
986 /// </summary>
987 internal void SetHeight(float height)
988 {
989 m_avHeight = height;
990 if (PhysicsActor != null)
991 {
992 PhysicsVector SetSize = new PhysicsVector(0.45f, 0.6f, m_avHeight);
993 PhysicsActor.Size = SetSize;
994 }
995 }
996
997 /// <summary>
998 /// Complete Avatar's movement into the region
999 /// </summary>
1000 public void CompleteMovement()
1001 {
1002 Vector3 look = Velocity;
1003 if ((look.X == 0) && (look.Y == 0) && (look.Z == 0))
1004 {
1005 look = new Vector3(0.99f, 0.042f, 0);
1006 }
1007
1008 m_controllingClient.MoveAgentIntoRegion(m_regionInfo, AbsolutePosition, look);
1009
1010 if (m_isChildAgent)
1011 {
1012 m_isChildAgent = false;
1013
1014 MakeRootAgent(AbsolutePosition, false);
1015
1016 if ((m_callbackURI != null) && !m_callbackURI.Equals(""))
1017 {
1018 m_log.DebugFormat("[SCENE PRESENCE]: Releasing agent in URI {0}", m_callbackURI);
1019 Scene.SendReleaseAgent(m_rootRegionHandle, UUID, m_callbackURI);
1020 m_callbackURI = null;
1021 }
1022
1023 //m_log.DebugFormat("Completed movement");
1024 }
1025 }
1026
1027 /// <summary>
1028 /// This is the event handler for client movement. If a client is moving, this event is triggering.
1029 /// </summary>
1030 public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
1031 {
1032 //if (m_isChildAgent)
1033 //{
1034 // // Console.WriteLine("DEBUG: HandleAgentUpdate: child agent");
1035 // return;
1036 //}
1037
1038 // Must check for standing up even when PhysicsActor is null,
1039 // since sitting currently removes avatar from physical scene
1040 //m_log.Debug("agentPos:" + AbsolutePosition.ToString());
1041
1042 // This is irritating. Really.
1043 if (!AbsolutePosition.IsFinite())
1044 {
1045 RemoveFromPhysicalScene();
1046 m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error# 9999902");
1047
1048 m_pos = m_LastFinitePos;
1049 if (!m_pos.IsFinite())
1050 {
1051 m_pos.X = 127f;
1052 m_pos.Y = 127f;
1053 m_pos.Z = 127f;
1054 m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error# 9999903");
1055 }
1056
1057 AddToPhysicalScene();
1058 }
1059 else
1060 {
1061 m_LastFinitePos = m_pos;
1062 }
1063 //m_physicsActor.AddForce(new PhysicsVector(999999999, 99999999, 999999999999999), true);
1064
1065
1066 //ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y);
1067 //if (land != null)
1068 //{
1069 //if (land.landData.landingType == (byte)1 && land.landData.userLocation != Vector3.Zero)
1070 //{
1071 // agent.startpos = land.landData.userLocation;
1072 //}
1073 //}
1074
1075 m_perfMonMS = System.Environment.TickCount;
1076
1077 uint flags = agentData.ControlFlags;
1078 Quaternion bodyRotation = agentData.BodyRotation;
1079
1080 // Camera location in world. We'll need to raytrace
1081 // from this location from time to time.
1082 m_CameraCenter = agentData.CameraCenter;
1083
1084 // Use these three vectors to figure out what the agent is looking at
1085 // Convert it to a Matrix and/or Quaternion
1086 m_CameraAtAxis = agentData.CameraAtAxis;
1087 m_CameraLeftAxis = agentData.CameraLeftAxis;
1088 m_CameraUpAxis = agentData.CameraUpAxis;
1089
1090 // The Agent's Draw distance setting
1091 m_DrawDistance = agentData.Far;
1092
1093 if ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0)
1094 {
1095 StandUp();
1096 }
1097 lock (scriptedcontrols)
1098 {
1099 if (scriptedcontrols.Count > 0)
1100 {
1101 SendControlToScripts(flags);
1102 flags = this.RemoveIgnoredControls(flags, IgnoredControls);
1103
1104 }
1105 }
1106
1107 if (PhysicsActor == null)
1108 {
1109 return;
1110 }
1111
1112 if (m_autopilotMoving)
1113 CheckAtSitTarget();
1114
1115 if ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0)
1116 {
1117 // TODO: This doesn't prevent the user from walking yet.
1118 // Setting parent ID would fix this, if we knew what value
1119 // to use. Or we could add a m_isSitting variable.
1120
1121 TrySetMovementAnimation("SIT_GROUND_CONSTRAINED");
1122 }
1123 // In the future, these values might need to go global.
1124 // Here's where you get them.
1125
1126 m_AgentControlFlags = flags;
1127 m_headrotation = agentData.HeadRotation;
1128 m_state = agentData.State;
1129
1130 if (m_allowMovement)
1131 {
1132 int i = 0;
1133 bool update_movementflag = false;
1134 bool update_rotation = false;
1135 bool DCFlagKeyPressed = false;
1136 Vector3 agent_control_v3 = new Vector3(0, 0, 0);
1137 Quaternion q = bodyRotation;
1138 if (PhysicsActor != null)
1139 {
1140 bool oldflying = PhysicsActor.Flying;
1141
1142 PhysicsActor.Flying = ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
1143
1144 if (PhysicsActor.Flying != oldflying)
1145 {
1146 update_movementflag = true;
1147 }
1148 }
1149
1150 if (q != m_bodyRot)
1151 {
1152 m_bodyRot = q;
1153 update_rotation = true;
1154 }
1155
1156 if (m_parentID == 0)
1157 {
1158 bool bAllowUpdateMoveToPosition = false;
1159 bool bResetMoveToPosition = false;
1160 foreach (Dir_ControlFlags DCF in Enum.GetValues(typeof (Dir_ControlFlags)))
1161 {
1162 if ((flags & (uint) DCF) != 0)
1163 {
1164 bResetMoveToPosition = true;
1165 DCFlagKeyPressed = true;
1166 try
1167 {
1168 agent_control_v3 += Dir_Vectors[i];
1169 }
1170 catch (IndexOutOfRangeException)
1171 {
1172 // Why did I get this?
1173 }
1174
1175 if ((m_movementflag & (uint) DCF) == 0)
1176 {
1177 m_movementflag += (byte) (uint) DCF;
1178 update_movementflag = true;
1179 }
1180 }
1181 else
1182 {
1183 if ((m_movementflag & (uint) DCF) != 0)
1184 {
1185 m_movementflag -= (byte) (uint) DCF;
1186 update_movementflag = true;
1187 }
1188 else
1189 {
1190 bAllowUpdateMoveToPosition = true;
1191 }
1192 }
1193 i++;
1194 }
1195
1196 //Paupaw:Do Proper PID for Autopilot here
1197 if (bResetMoveToPosition)
1198 {
1199 m_moveToPositionTarget = Vector3.Zero;
1200 m_moveToPositionInProgress = false;
1201 update_movementflag = true;
1202 bAllowUpdateMoveToPosition = false;
1203 }
1204
1205 if (bAllowUpdateMoveToPosition && (m_moveToPositionInProgress && !m_autopilotMoving))
1206 {
1207 //Check the error term of the current position in relation to the target position
1208 if (Util.GetDistanceTo(AbsolutePosition, m_moveToPositionTarget) <= 1.5)
1209 {
1210 // we are close enough to the target
1211 m_moveToPositionTarget = Vector3.Zero;
1212 m_moveToPositionInProgress = false;
1213 update_movementflag = true;
1214 }
1215 else
1216 {
1217 try
1218 {
1219 // move avatar in 2D at one meter/second towards target, in avatar coordinate frame.
1220 // This movement vector gets added to the velocity through AddNewMovement().
1221 // Theoretically we might need a more complex PID approach here if other
1222 // unknown forces are acting on the avatar and we need to adaptively respond
1223 // to such forces, but the following simple approach seems to works fine.
1224 Vector3 LocalVectorToTarget3D =
1225 (m_moveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords
1226 * Matrix4.CreateFromQuaternion(Quaternion.Inverse(bodyRotation)); // change to avatar coords
1227 // Ignore z component of vector
1228 Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f);
1229 LocalVectorToTarget2D.Normalize();
1230 agent_control_v3 += LocalVectorToTarget2D;
1231
1232 // update avatar movement flags. the avatar coordinate system is as follows:
1233 //
1234 // +X (forward)
1235 //
1236 // ^
1237 // |
1238 // |
1239 // |
1240 // |
1241 // (left) +Y <--------o--------> -Y
1242 // avatar
1243 // |
1244 // |
1245 // |
1246 // |
1247 // v
1248 // -X
1249 //
1250
1251 // based on the above avatar coordinate system, classify the movement into
1252 // one of left/right/back/forward.
1253 if (LocalVectorToTarget2D.Y > 0)//MoveLeft
1254 {
1255 m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT;
1256 update_movementflag = true;
1257 }
1258 else if (LocalVectorToTarget2D.Y < 0) //MoveRight
1259 {
1260 m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT;
1261 update_movementflag = true;
1262 }
1263 if (LocalVectorToTarget2D.X < 0) //MoveBack
1264 {
1265 m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK;
1266 update_movementflag = true;
1267 }
1268 else if (LocalVectorToTarget2D.X > 0) //Move Forward
1269 {
1270 m_movementflag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD;
1271 update_movementflag = true;
1272 }
1273 }
1274 catch (Exception)
1275 {
1276
1277 //Avoid system crash, can be slower but...
1278 }
1279
1280 }
1281 }
1282 }
1283
1284 // Cause the avatar to stop flying if it's colliding
1285 // with something with the down arrow pressed.
1286
1287 // Only do this if we're flying
1288 if (m_physicsActor != null && m_physicsActor.Flying)
1289 {
1290 // Are the landing controls requirements filled?
1291 bool controlland = (((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) ||
1292 ((flags & (uint) AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
1293
1294 // Are the collision requirements fulfilled?
1295 bool colliding = (m_physicsActor.IsColliding == true);
1296
1297 if (m_physicsActor.Flying && colliding && controlland)
1298 {
1299 StopFlying();
1300 }
1301 }
1302
1303 if (update_movementflag || (update_rotation && DCFlagKeyPressed))
1304 {
1305// m_log.DebugFormat("{0} {1}", update_movementflag, (update_rotation && DCFlagKeyPressed));
1306// m_log.DebugFormat(
1307// "In {0} adding velocity to {1} of {2}", m_scene.RegionInfo.RegionName, Name, agent_control_v3);
1308
1309 AddNewMovement(agent_control_v3, q);
1310
1311 if (update_movementflag)
1312 UpdateMovementAnimations();
1313 }
1314 }
1315
1316 m_scene.EventManager.TriggerOnClientMovement(this);
1317
1318 m_scene.AddAgentTime(System.Environment.TickCount - m_perfMonMS);
1319 }
1320
1321 public void DoAutoPilot(uint not_used, Vector3 Pos, IClientAPI remote_client)
1322 {
1323 m_autopilotMoving = true;
1324 m_autoPilotTarget = Pos;
1325 m_sitAtAutoTarget = false;
1326 PrimitiveBaseShape proxy = PrimitiveBaseShape.Default;
1327 //proxy.PCode = (byte)PCode.ParticleSystem;
1328
1329 proxyObjectGroup = new SceneObjectGroup(UUID, Pos, Rotation, proxy);
1330 proxyObjectGroup.AttachToScene(m_scene);
1331
1332 // Commented out this code since it could never have executed, but might still be informative.
1333// if (proxyObjectGroup != null)
1334// {
1335 proxyObjectGroup.SendGroupFullUpdate();
1336 remote_client.SendSitResponse(proxyObjectGroup.UUID, Vector3.Zero, Quaternion.Identity, true, Vector3.Zero, Vector3.Zero, false);
1337 m_scene.DeleteSceneObject(proxyObjectGroup, false);
1338// }
1339// else
1340// {
1341// m_autopilotMoving = false;
1342// m_autoPilotTarget = Vector3.Zero;
1343// ControllingClient.SendAlertMessage("Autopilot cancelled");
1344// }
1345 }
1346
1347 public void DoMoveToPosition(Object sender, string method, List<String> args)
1348 {
1349 try
1350 {
1351 float locx = 0f;
1352 float locy = 0f;
1353 float locz = 0f;
1354 uint regionX = 0;
1355 uint regionY = 0;
1356 try
1357 {
1358 Utils.LongToUInts(Scene.RegionInfo.RegionHandle, out regionX, out regionY);
1359 locx = Convert.ToSingle(args[0]) - (float)regionX;
1360 locy = Convert.ToSingle(args[1]) - (float)regionY;
1361 locz = Convert.ToSingle(args[2]);
1362 }
1363 catch (InvalidCastException)
1364 {
1365 m_log.Error("[CLIENT]: Invalid autopilot request");
1366 return;
1367 }
1368 m_moveToPositionInProgress = true;
1369 m_moveToPositionTarget = new Vector3(locx, locy, locz);
1370 }
1371 catch (Exception ex)
1372 {
1373 //Why did I get this error?
1374 Console.WriteLine("[SCENEPRESENCE]: DoMoveToPosition" + ex.ToString());
1375 }
1376 }
1377
1378 private void CheckAtSitTarget()
1379 {
1380 //m_log.Debug("[AUTOPILOT]: " + Util.GetDistanceTo(AbsolutePosition, m_autoPilotTarget).ToString());
1381 if (Util.GetDistanceTo(AbsolutePosition, m_autoPilotTarget) <= 1.5)
1382 {
1383 if (m_sitAtAutoTarget)
1384 {
1385 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetUUID);
1386 if (part != null)
1387 {
1388 AbsolutePosition = part.AbsolutePosition;
1389 Velocity = new Vector3(0, 0, 0);
1390 SendFullUpdateToAllClients();
1391
1392 //HandleAgentSit(ControllingClient, m_requestedSitTargetUUID);
1393 }
1394 //ControllingClient.SendSitResponse(m_requestedSitTargetID, m_requestedSitOffset, Quaternion.Identity, false, Vector3.Zero, Vector3.Zero, false);
1395 m_requestedSitTargetUUID = UUID.Zero;
1396 }
1397 else
1398 {
1399 //ControllingClient.SendAlertMessage("Autopilot cancelled");
1400 //SendTerseUpdateToAllClients();
1401 //PrimitiveBaseShape proxy = PrimitiveBaseShape.Default;
1402 //proxy.PCode = (byte)PCode.ParticleSystem;
1403 ////uint nextUUID = m_scene.NextLocalId;
1404
1405 //proxyObjectGroup = new SceneObjectGroup(m_scene, m_scene.RegionInfo.RegionHandle, UUID, nextUUID, m_autoPilotTarget, Quaternion.Identity, proxy);
1406 //if (proxyObjectGroup != null)
1407 //{
1408 //proxyObjectGroup.SendGroupFullUpdate();
1409 //ControllingClient.SendSitResponse(UUID.Zero, m_autoPilotTarget, Quaternion.Identity, true, Vector3.Zero, Vector3.Zero, false);
1410 //m_scene.DeleteSceneObject(proxyObjectGroup);
1411 //}
1412 }
1413
1414 m_autoPilotTarget = Vector3.Zero;
1415 m_autopilotMoving = false;
1416 }
1417 }
1418 /// <summary>
1419 /// Perform the logic necessary to stand the client up. This method also executes
1420 /// the stand animation.
1421 /// </summary>
1422 public void StandUp()
1423 {
1424 if (m_parentID != 0)
1425 {
1426 SceneObjectPart part = m_scene.GetSceneObjectPart(m_parentID);
1427 if (part != null)
1428 {
1429 TaskInventoryDictionary taskIDict = part.TaskInventory;
1430 if (taskIDict != null)
1431 {
1432 lock (taskIDict)
1433 {
1434 foreach (UUID taskID in taskIDict.Keys)
1435 {
1436 UnRegisterControlEventsToScript(LocalId, taskID);
1437 taskIDict[taskID].PermsMask &= ~(
1438 2048 | //PERMISSION_CONTROL_CAMERA
1439 4); // PERMISSION_TAKE_CONTROLS
1440 }
1441 }
1442
1443 }
1444 // Reset sit target.
1445 if (part.GetAvatarOnSitTarget() == UUID)
1446 part.SetAvatarOnSitTarget(UUID.Zero);
1447
1448 m_parentPosition = part.GetWorldPosition();
1449 }
1450
1451 if (m_physicsActor == null)
1452 {
1453 AddToPhysicalScene();
1454 }
1455
1456 m_pos += m_parentPosition + new Vector3(0.0f, 0.0f, 2.0f*m_sitAvatarHeight);
1457 m_parentPosition = new Vector3();
1458
1459 m_parentID = 0;
1460 SendFullUpdateToAllClients();
1461 m_requestedSitTargetID = 0;
1462 if (m_physicsActor != null)
1463 {
1464 SetHeight(m_avHeight);
1465 }
1466 }
1467
1468 TrySetMovementAnimation("STAND");
1469 }
1470
1471 private SceneObjectPart FindNextAvailableSitTarget(UUID targetID)
1472 {
1473 SceneObjectPart targetPart = m_scene.GetSceneObjectPart(targetID);
1474 if (targetPart == null)
1475 return null;
1476
1477 // If the primitive the player clicked on has a sit target and that sit target is not full, that sit target is used.
1478 // If the primitive the player clicked on has no sit target, and one or more other linked objects have sit targets that are not full, the sit target of the object with the lowest link number will be used.
1479
1480 // Get our own copy of the part array, and sort into the order we want to test
1481 SceneObjectPart[] partArray = targetPart.ParentGroup.GetParts();
1482 Array.Sort(partArray, delegate(SceneObjectPart p1, SceneObjectPart p2)
1483 {
1484 // we want the originally selected part first, then the rest in link order -- so make the selected part link num (-1)
1485 int linkNum1 = p1==targetPart ? -1 : p1.LinkNum;
1486 int linkNum2 = p2==targetPart ? -1 : p2.LinkNum;
1487 return linkNum1 - linkNum2;
1488 }
1489 );
1490
1491 //look for prims with explicit sit targets that are available
1492 foreach (SceneObjectPart part in partArray)
1493 {
1494 // Is a sit target available?
1495 Vector3 avSitOffSet = part.SitTargetPosition;
1496 Quaternion avSitOrientation = part.SitTargetOrientation;
1497 UUID avOnTargetAlready = part.GetAvatarOnSitTarget();
1498
1499 bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero));
1500 bool SitTargetisSet =
1501 (!(avSitOffSet.X == 0f && avSitOffSet.Y == 0f && avSitOffSet.Z == 0f && avSitOrientation.W == 1f &&
1502 avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f));
1503
1504 if (SitTargetisSet && SitTargetUnOccupied)
1505 {
1506 //switch the target to this prim
1507 return part;
1508 }
1509 }
1510
1511 // no explicit sit target found - use original target
1512 return targetPart;
1513 }
1514
1515 private void SendSitResponse(IClientAPI remoteClient, UUID targetID, Vector3 offset)
1516 {
1517 bool autopilot = true;
1518 Vector3 pos = new Vector3();
1519 Quaternion sitOrientation = Quaternion.Identity;
1520 Vector3 cameraEyeOffset = Vector3.Zero;
1521 Vector3 cameraAtOffset = Vector3.Zero;
1522 bool forceMouselook = false;
1523
1524 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID);
1525 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
1526 if (part != null)
1527 {
1528 // TODO: determine position to sit at based on scene geometry; don't trust offset from client
1529 // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it
1530
1531 // Is a sit target available?
1532 Vector3 avSitOffSet = part.SitTargetPosition;
1533 Quaternion avSitOrientation = part.SitTargetOrientation;
1534 UUID avOnTargetAlready = part.GetAvatarOnSitTarget();
1535
1536 bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero));
1537 bool SitTargetisSet =
1538 (!(avSitOffSet.X == 0f && avSitOffSet.Y == 0f && avSitOffSet.Z == 0f && avSitOrientation.W == 0f &&
1539 avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 1f));
1540
1541 if (SitTargetisSet && SitTargetUnOccupied)
1542 {
1543 part.SetAvatarOnSitTarget(UUID);
1544 offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z);
1545 sitOrientation = avSitOrientation;
1546 autopilot = false;
1547 }
1548
1549 pos = part.AbsolutePosition + offset;
1550 //if (Math.Abs(part.AbsolutePosition.Z - AbsolutePosition.Z) > 1)
1551 //{
1552 // offset = pos;
1553 //autopilot = false;
1554 //}
1555 if (m_physicsActor != null)
1556 {
1557 // If we're not using the client autopilot, we're immediately warping the avatar to the location
1558 // We can remove the physicsActor until they stand up.
1559 m_sitAvatarHeight = m_physicsActor.Size.Z;
1560
1561 if (autopilot)
1562 {
1563 if (Util.GetDistanceTo(AbsolutePosition, pos) < 4.5)
1564 {
1565 autopilot = false;
1566
1567 RemoveFromPhysicalScene();
1568 AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight);
1569 }
1570 }
1571 else
1572 {
1573 RemoveFromPhysicalScene();
1574 }
1575 }
1576
1577 cameraAtOffset = part.GetCameraAtOffset();
1578 cameraEyeOffset = part.GetCameraEyeOffset();
1579 forceMouselook = part.GetForceMouselook();
1580 }
1581
1582 ControllingClient.SendSitResponse(targetID, offset, sitOrientation, autopilot, cameraAtOffset, cameraEyeOffset, forceMouselook);
1583 m_requestedSitTargetUUID = targetID;
1584 // This calls HandleAgentSit twice, once from here, and the client calls
1585 // HandleAgentSit itself after it gets to the location
1586 // It doesn't get to the location until we've moved them there though
1587 // which happens in HandleAgentSit :P
1588 m_autopilotMoving = autopilot;
1589 m_autoPilotTarget = pos;
1590 m_sitAtAutoTarget = autopilot;
1591 if (!autopilot)
1592 HandleAgentSit(remoteClient, UUID);
1593 }
1594
1595 public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset)
1596 {
1597 if (m_parentID != 0)
1598 {
1599 StandUp();
1600 }
1601 m_nextSitAnimation = "SIT";
1602
1603 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID);
1604 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
1605
1606 if (part != null)
1607 {
1608 if (!String.IsNullOrEmpty(part.SitAnimation))
1609 {
1610 m_nextSitAnimation = part.SitAnimation;
1611 }
1612 m_requestedSitTargetID = part.LocalId;
1613 m_requestedSitOffset = offset;
1614 }
1615 else
1616 {
1617
1618 m_log.Warn("Sit requested on unknown object: " + targetID.ToString());
1619 }
1620 SendSitResponse(remoteClient, targetID, offset);
1621 }
1622
1623 public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset, string sitAnimation)
1624 {
1625 if (m_parentID != 0)
1626 {
1627 StandUp();
1628 }
1629 if (!String.IsNullOrEmpty(sitAnimation))
1630 {
1631 m_nextSitAnimation = sitAnimation;
1632 }
1633 else
1634 {
1635 m_nextSitAnimation = "SIT";
1636 }
1637
1638 //SceneObjectPart part = m_scene.GetSceneObjectPart(targetID);
1639 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
1640 if (part != null)
1641 {
1642 m_requestedSitTargetID = part.LocalId;
1643 m_requestedSitOffset = offset;
1644 }
1645 else
1646 {
1647 m_log.Warn("Sit requested on unknown object: " + targetID.ToString());
1648 }
1649 SendSitResponse(remoteClient, targetID, offset);
1650 }
1651
1652 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID)
1653 {
1654 if (!String.IsNullOrEmpty(m_nextSitAnimation))
1655 {
1656 HandleAgentSit(remoteClient, agentID, m_nextSitAnimation);
1657 }
1658 else
1659 {
1660 HandleAgentSit(remoteClient, agentID, "SIT");
1661 }
1662 }
1663
1664 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID, string sitAnimation)
1665 {
1666 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
1667
1668 if (m_sitAtAutoTarget || !m_autopilotMoving)
1669 {
1670 if (part != null)
1671 {
1672 if (part.GetAvatarOnSitTarget() == UUID)
1673 {
1674 Vector3 sitTargetPos = part.SitTargetPosition;
1675 Quaternion sitTargetOrient = part.SitTargetOrientation;
1676
1677 //Quaternion vq = new Quaternion(sitTargetPos.X, sitTargetPos.Y+0.2f, sitTargetPos.Z+0.2f, 0);
1678 //Quaternion nq = new Quaternion(-sitTargetOrient.X, -sitTargetOrient.Y, -sitTargetOrient.Z, sitTargetOrient.w);
1679
1680 //Quaternion result = (sitTargetOrient * vq) * nq;
1681
1682 m_pos = new Vector3(sitTargetPos.X, sitTargetPos.Y, sitTargetPos.Z);
1683 m_pos += m_sitTargetCorrectionOffset;
1684 m_bodyRot = sitTargetOrient;
1685 //Rotation = sitTargetOrient;
1686 m_parentPosition = part.AbsolutePosition;
1687
1688 //SendTerseUpdateToAllClients();
1689 }
1690 else
1691 {
1692 m_pos -= part.AbsolutePosition;
1693 m_parentPosition = part.AbsolutePosition;
1694 }
1695 }
1696 else
1697 {
1698 return;
1699 }
1700 }
1701 m_parentID = m_requestedSitTargetID;
1702
1703 Velocity = new Vector3(0, 0, 0);
1704 RemoveFromPhysicalScene();
1705
1706 TrySetMovementAnimation(sitAnimation);
1707 SendFullUpdateToAllClients();
1708 // This may seem stupid, but Our Full updates don't send avatar rotation :P
1709 // So we're also sending a terse update (which has avatar rotation)
1710 // [Update] We do now.
1711 //SendTerseUpdateToAllClients();
1712 }
1713
1714 /// <summary>
1715 /// Event handler for the 'Always run' setting on the client
1716 /// Tells the physics plugin to increase speed of movement.
1717 /// </summary>
1718 public void HandleSetAlwaysRun(IClientAPI remoteClient, bool SetAlwaysRun)
1719 {
1720 m_setAlwaysRun = SetAlwaysRun;
1721 if (PhysicsActor != null)
1722 {
1723 PhysicsActor.SetAlwaysRun = SetAlwaysRun;
1724 }
1725 }
1726
1727 public void AddAnimation(UUID animID)
1728 {
1729 if (m_isChildAgent)
1730 return;
1731
1732 if (m_animations.Add(animID, m_controllingClient.NextAnimationSequenceNumber))
1733 {
1734 SendAnimPack();
1735 }
1736 }
1737
1738 public void AddAnimation(string name)
1739 {
1740 if (m_isChildAgent)
1741 return;
1742
1743 UUID animID = m_controllingClient.GetDefaultAnimation(name);
1744 if (animID == UUID.Zero)
1745 return;
1746
1747 AddAnimation(animID);
1748 }
1749
1750 public void RemoveAnimation(UUID animID)
1751 {
1752 if (m_isChildAgent)
1753 return;
1754
1755 if (m_animations.Remove(animID))
1756 {
1757 SendAnimPack();
1758 }
1759 }
1760
1761 public void RemoveAnimation(string name)
1762 {
1763 if (m_isChildAgent)
1764 return;
1765
1766 UUID animID = m_controllingClient.GetDefaultAnimation(name);
1767 if (animID == UUID.Zero)
1768 return;
1769
1770 RemoveAnimation(animID);
1771 }
1772
1773 public UUID[] GetAnimationArray()
1774 {
1775 UUID[] animIDs;
1776 int[] sequenceNums;
1777 m_animations.GetArrays( out animIDs, out sequenceNums );
1778 return animIDs;
1779 }
1780
1781 public void HandleStartAnim(IClientAPI remoteClient, UUID animID)
1782 {
1783 AddAnimation(animID);
1784 }
1785
1786 public void HandleStopAnim(IClientAPI remoteClient, UUID animID)
1787 {
1788 RemoveAnimation(animID);
1789 }
1790
1791 /// <summary>
1792 /// The movement animation is reserved for "main" animations
1793 /// that are mutually exclusive, e.g. flying and sitting.
1794 /// </summary>
1795 protected void TrySetMovementAnimation(string anim)
1796 {
1797 //m_log.DebugFormat("Updating movement animation to {0}", anim);
1798
1799 if (m_animations.TrySetDefaultAnimation(anim, m_controllingClient.NextAnimationSequenceNumber))
1800 {
1801 SendAnimPack();
1802 }
1803 }
1804
1805 /// <summary>
1806 /// This method determines the proper movement related animation
1807 /// </summary>
1808 public string GetMovementAnimation()
1809 {
1810 if (m_movementflag != 0)
1811 {
1812 // We are moving
1813 if (PhysicsActor != null && PhysicsActor.Flying)
1814 {
1815 return "FLY";
1816 }
1817 else if (PhysicsActor != null && (m_movementflag & (uint) AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0 &&
1818 PhysicsActor.IsColliding)
1819 {
1820 if ((m_movementflag & (uint) AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) != 0 ||
1821 (m_movementflag & (uint) AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) != 0)
1822 {
1823 return "CROUCHWALK";
1824 }
1825 else
1826 {
1827 return "CROUCH";
1828 }
1829 }
1830 else if (PhysicsActor != null && !PhysicsActor.IsColliding && PhysicsActor.Velocity.Z < -2)
1831 {
1832 return "FALLDOWN";
1833 }
1834 else if (PhysicsActor != null && !PhysicsActor.IsColliding && Velocity.Z > 1e-6 &&
1835 (m_movementflag & (uint) AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0)
1836 {
1837 return "JUMP";
1838 }
1839 else if (m_setAlwaysRun)
1840 {
1841 return "RUN";
1842 }
1843 else
1844 {
1845 return "WALK";
1846 }
1847 }
1848 else
1849 {
1850 // We are not moving
1851 if (PhysicsActor != null && !PhysicsActor.IsColliding && PhysicsActor.Velocity.Z < -2 && !PhysicsActor.Flying)
1852 {
1853 return "FALLDOWN";
1854 }
1855 else if (PhysicsActor != null && !PhysicsActor.IsColliding && Velocity.Z > 6 && !PhysicsActor.Flying)
1856 {
1857 // HACK: We check if Velocity.Z > 6 for this animation in order to avoid false positives during normal movement.
1858 // TODO: set this animation only when on the ground and UP_POS is received?
1859
1860 // This is the standing jump
1861 return "JUMP";
1862 }
1863 else if (PhysicsActor != null && PhysicsActor.Flying)
1864 {
1865 return "HOVER";
1866 }
1867 else
1868 {
1869 return "STAND";
1870 }
1871 }
1872 }
1873
1874 /// <summary>
1875 /// Update the movement animation of this avatar according to its current state
1876 /// </summary>
1877 protected void UpdateMovementAnimations()
1878 {
1879 string animation = GetMovementAnimation();
1880 TrySetMovementAnimation(animation);
1881 }
1882
1883 /// <summary>
1884 /// Rotate the avatar to the given rotation and apply a movement in the given relative vector
1885 /// </summary>
1886 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
1887 /// <param name="rotation">The direction in which this avatar should now face.
1888 public void AddNewMovement(Vector3 vec, Quaternion rotation)
1889 {
1890 if (m_isChildAgent)
1891 {
1892 Console.WriteLine("DEBUG: AddNewMovement: child agent");
1893 return;
1894 }
1895
1896 m_perfMonMS = System.Environment.TickCount;
1897
1898 m_rotation = rotation;
1899 NewForce newVelocity = new NewForce();
1900 Vector3 direc = vec * rotation;
1901 direc.Normalize();
1902
1903 direc *= 0.03f * 128f;
1904 if (m_physicsActor.Flying)
1905 {
1906 direc *= 4;
1907 //bool controlland = (((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
1908 //bool colliding = (m_physicsActor.IsColliding==true);
1909 //if (controlland)
1910 // m_log.Info("[AGENT]: landCommand");
1911 //if (colliding)
1912 // m_log.Info("[AGENT]: colliding");
1913 //if (m_physicsActor.Flying && colliding && controlland)
1914 //{
1915 // StopFlying();
1916 // m_log.Info("[AGENT]: Stop FLying");
1917 //}
1918 }
1919 else
1920 {
1921 if (!m_physicsActor.Flying && m_physicsActor.IsColliding)
1922 {
1923 if (direc.Z > 2.0f)
1924 {
1925 direc.Z *= 3;
1926
1927 // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored.
1928 TrySetMovementAnimation("PREJUMP");
1929 TrySetMovementAnimation("JUMP");
1930 }
1931 }
1932 }
1933
1934 newVelocity.X = direc.X;
1935 newVelocity.Y = direc.Y;
1936 newVelocity.Z = direc.Z;
1937 m_forcesList.Add(newVelocity);
1938
1939 m_scene.AddAgentTime(System.Environment.TickCount - m_perfMonMS);
1940 }
1941
1942 #endregion
1943
1944 #region Overridden Methods
1945
1946 public override void Update()
1947 {
1948 SendPrimUpdates();
1949
1950 if (m_newCoarseLocations)
1951 {
1952 SendCoarseLocations();
1953 m_newCoarseLocations = false;
1954 }
1955
1956 if (m_isChildAgent == false)
1957 {
1958 if (m_newForce) // user movement 'forces' (ie commands to move)
1959 {
1960 SendTerseUpdateToAllClients();
1961 m_updateCount = 0;
1962 }
1963 else if (m_movementflag != 0) // scripted movement (?)
1964 {
1965 m_updateCount++;
1966 if (m_updateCount > 3)
1967 {
1968 SendTerseUpdateToAllClients();
1969 m_updateCount = 0;
1970 }
1971 }
1972 else if ((Util.GetDistanceTo(lastPhysPos, AbsolutePosition) > 0.02)
1973 || (Util.GetDistanceTo(m_lastVelocity, m_velocity) > 0.02)
1974 || lastPhysRot != m_bodyRot)
1975 {
1976 // Send Terse Update to all clients updates lastPhysPos and m_lastVelocity
1977 // doing the above assures us that we know what we sent the clients last
1978 SendTerseUpdateToAllClients();
1979 m_updateCount = 0;
1980 }
1981
1982 // followed suggestion from mic bowman. reversed the two lines below.
1983 CheckForBorderCrossing();
1984 CheckForSignificantMovement(); // sends update to the modules.
1985 }
1986 }
1987
1988 #endregion
1989
1990 #region Update Client(s)
1991
1992 /// <summary>
1993 /// Sends a location update to the client connected to this scenePresence
1994 /// </summary>
1995 /// <param name="remoteClient"></param>
1996 public void SendTerseUpdateToClient(IClientAPI remoteClient)
1997 {
1998 m_perfMonMS = System.Environment.TickCount;
1999
2000 Vector3 pos = m_pos;
2001 Vector3 vel = Velocity;
2002 Quaternion rot = m_bodyRot;
2003 pos.Z -= m_appearance.HipOffset;
2004 remoteClient.SendAvatarTerseUpdate(m_regionHandle, (ushort)(m_scene.TimeDilation * (float)ushort.MaxValue), LocalId, new Vector3(pos.X, pos.Y, pos.Z),
2005 new Vector3(vel.X, vel.Y, vel.Z), rot);
2006
2007 m_scene.AddAgentTime(System.Environment.TickCount - m_perfMonMS);
2008 m_scene.AddAgentUpdates(1);
2009 }
2010
2011 /// <summary>
2012 /// Send a location/velocity/accelleration update to all agents in scene
2013 /// </summary>
2014 public void SendTerseUpdateToAllClients()
2015 {
2016 m_perfMonMS = System.Environment.TickCount;
2017
2018 m_scene.Broadcast(SendTerseUpdateToClient);
2019
2020 m_lastVelocity = m_velocity;
2021 lastPhysPos = AbsolutePosition;
2022 lastPhysRot = m_bodyRot;
2023
2024 m_scene.AddAgentTime(System.Environment.TickCount - m_perfMonMS);
2025
2026 }
2027
2028 public void SendCoarseLocations()
2029 {
2030 m_perfMonMS = System.Environment.TickCount;
2031
2032 List<Vector3> CoarseLocations = new List<Vector3>();
2033 List<ScenePresence> avatars = m_scene.GetAvatars();
2034 for (int i = 0; i < avatars.Count; i++)
2035 {
2036 if (avatars[i] != this)
2037 {
2038 if (avatars[i].ParentID != 0)
2039 {
2040 // sitting avatar
2041 SceneObjectPart sop = m_scene.GetSceneObjectPart(avatars[i].ParentID);
2042 if (sop != null)
2043 {
2044 CoarseLocations.Add(sop.AbsolutePosition + avatars[i].m_pos);
2045 }
2046 else
2047 {
2048 // we can't find the parent.. ! arg!
2049 CoarseLocations.Add(avatars[i].m_pos);
2050 }
2051 }
2052 else
2053 {
2054 CoarseLocations.Add(avatars[i].m_pos);
2055 }
2056 }
2057 }
2058
2059 m_controllingClient.SendCoarseLocationUpdate(CoarseLocations);
2060
2061 m_scene.AddAgentTime(System.Environment.TickCount - m_perfMonMS);
2062 }
2063
2064 public void CoarseLocationChange()
2065 {
2066 m_newCoarseLocations = true;
2067 }
2068
2069 /// <summary>
2070 /// Tell other client about this avatar (The client previously didn't know or had outdated details about this avatar)
2071 /// </summary>
2072 /// <param name="remoteAvatar"></param>
2073 public void SendFullUpdateToOtherClient(ScenePresence remoteAvatar)
2074 {
2075 // 2 stage check is needed.
2076 if (remoteAvatar == null)
2077 return;
2078 IClientAPI cl=remoteAvatar.ControllingClient;
2079 if (cl == null)
2080 return;
2081 if (m_appearance.Texture == null)
2082 return;
2083
2084 // Note: because Quaternion is a struct, it can't be null
2085 Quaternion rot = m_bodyRot;
2086
2087 Vector3 pos = m_pos;
2088 pos.Z -= m_appearance.HipOffset;
2089
2090 remoteAvatar.m_controllingClient.SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid,
2091 LocalId, m_pos, m_appearance.Texture.ToBytes(),
2092 m_parentID, rot);
2093 m_scene.AddAgentUpdates(1);
2094 }
2095
2096 /// <summary>
2097 /// Tell *ALL* agents about this agent
2098 /// </summary>
2099 public void SendInitialFullUpdateToAllClients()
2100 {
2101 m_perfMonMS = System.Environment.TickCount;
2102
2103 List<ScenePresence> avatars = m_scene.GetScenePresences();
2104 foreach (ScenePresence avatar in avatars)
2105 {
2106 // only send if this is the root (children are only "listening posts" in a foreign region)
2107 if (!IsChildAgent)
2108 {
2109 SendFullUpdateToOtherClient(avatar);
2110 }
2111
2112 if (avatar.LocalId != LocalId)
2113 {
2114 if (!avatar.IsChildAgent)
2115 {
2116 avatar.SendFullUpdateToOtherClient(this);
2117 avatar.SendAppearanceToOtherAgent(this);
2118 avatar.SendAnimPackToClient(this.ControllingClient);
2119 }
2120 }
2121 }
2122 m_scene.AddAgentUpdates(avatars.Count);
2123 m_scene.AddAgentTime(System.Environment.TickCount - m_perfMonMS);
2124 }
2125
2126 public void SendFullUpdateToAllClients()
2127 {
2128 m_perfMonMS = System.Environment.TickCount;
2129
2130 // only send update from root agents to other clients; children are only "listening posts"
2131 List<ScenePresence> avatars = m_scene.GetAvatars();
2132 foreach (ScenePresence avatar in avatars)
2133 {
2134 SendFullUpdateToOtherClient(avatar);
2135
2136 }
2137 m_scene.AddAgentUpdates(avatars.Count);
2138 m_scene.AddAgentTime(System.Environment.TickCount - m_perfMonMS);
2139
2140 SendAnimPack();
2141 }
2142
2143 /// <summary>
2144 /// Do everything required once a client completes its movement into a region
2145 /// </summary>
2146 public void SendInitialData()
2147 {
2148 // Moved this into CompleteMovement to ensure that m_appearance is initialized before
2149 // the inventory arrives
2150 // m_scene.GetAvatarAppearance(m_controllingClient, out m_appearance);
2151
2152 // Note: because Quaternion is a struct, it can't be null
2153 Quaternion rot = m_bodyRot;
2154
2155 Vector3 pos = m_pos;
2156 pos.Z -= m_appearance.HipOffset;
2157
2158 m_controllingClient.SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, LocalId,
2159 m_pos, m_appearance.Texture.ToBytes(), m_parentID, rot);
2160
2161 if (!m_isChildAgent)
2162 {
2163 m_scene.InformClientOfNeighbours(this);
2164 }
2165
2166 SendInitialFullUpdateToAllClients();
2167 SendAppearanceToAllOtherAgents();
2168 }
2169
2170 /// <summary>
2171 /// Tell the client for this scene presence what items it should be wearing now
2172 /// </summary>
2173 /// <param name="client"></param>
2174 public void SendWearables()
2175 {
2176 ControllingClient.SendWearables(m_appearance.Wearables, m_appearance.Serial++);
2177 }
2178
2179 /// <summary>
2180 ///
2181 /// </summary>
2182 public void SendAppearanceToAllOtherAgents()
2183 {
2184 m_perfMonMS = System.Environment.TickCount;
2185
2186 m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence)
2187 {
2188 if (scenePresence.UUID != UUID)
2189 {
2190 SendAppearanceToOtherAgent(scenePresence);
2191 }
2192 });
2193
2194 m_scene.AddAgentTime(System.Environment.TickCount - m_perfMonMS);
2195 }
2196
2197 /// <summary>
2198 /// Send appearance data to an agent that isn't this one.
2199 /// </summary>
2200 /// <param name="avatar"></param>
2201 public void SendAppearanceToOtherAgent(ScenePresence avatar)
2202 {
2203 avatar.ControllingClient.SendAppearance(
2204 m_appearance.Owner, m_appearance.VisualParams, m_appearance.Texture.ToBytes());
2205 }
2206
2207 /// <summary>
2208 /// Set appearance data (textureentry and slider settings) received from the client
2209 /// </summary>
2210 /// <param name="texture"></param>
2211 /// <param name="visualParam"></param>
2212 public void SetAppearance(byte[] texture, List<byte> visualParam)
2213 {
2214 if (m_physicsActor != null)
2215 {
2216 // This may seem like it's redundant, remove the avatar from the physics scene
2217 // just to add it back again, but it saves us from having to update
2218 // 3 variables 10 times a second.
2219 m_scene.PhysicsScene.RemoveAvatar(m_physicsActor);
2220 AddToPhysicalScene();
2221 }
2222 m_appearance.SetAppearance(texture, visualParam);
2223 SetHeight(m_appearance.AvatarHeight);
2224 m_scene.CommsManager.AvatarService.UpdateUserAppearance(m_controllingClient.AgentId, m_appearance);
2225
2226 SendAppearanceToAllOtherAgents();
2227 //SendWearables();
2228 if (!m_startAnimationSet)
2229 {
2230 UpdateMovementAnimations();
2231 m_startAnimationSet = true;
2232 }
2233 }
2234
2235 public void SetWearable(int wearableId, AvatarWearable wearable)
2236 {
2237 m_appearance.SetWearable(wearableId, wearable);
2238 m_scene.CommsManager.AvatarService.UpdateUserAppearance(m_controllingClient.AgentId, m_appearance);
2239 m_controllingClient.SendWearables(m_appearance.Wearables, m_appearance.Serial++);
2240 }
2241
2242 // Because appearance setting is in a module, we actually need
2243 // to give it access to our appearance directly, otherwise we
2244 // get a synchronization issue.
2245 public AvatarAppearance Appearance
2246 {
2247 get { return m_appearance; }
2248 set { m_appearance = value; }
2249 }
2250
2251 /// <summary>
2252 ///
2253 /// </summary>
2254 /// <param name="animations"></param>
2255 /// <param name="seqs"></param>
2256 public void SendAnimPack(UUID[] animations, int[] seqs)
2257 {
2258 if (m_isChildAgent)
2259 return;
2260
2261 m_scene.Broadcast(
2262 delegate(IClientAPI client) { client.SendAnimations(animations, seqs, m_controllingClient.AgentId); });
2263 }
2264
2265 public void SendAnimPackToClient(IClientAPI client)
2266 {
2267 if (m_isChildAgent)
2268 return;
2269 UUID[] animIDs;
2270 int[] sequenceNums;
2271
2272 m_animations.GetArrays(out animIDs, out sequenceNums);
2273
2274 client.SendAnimations(animIDs, sequenceNums, m_controllingClient.AgentId);
2275 }
2276
2277 /// <summary>
2278 /// Send animation information about this avatar to all clients.
2279 /// </summary>
2280 public void SendAnimPack()
2281 {
2282 //m_log.Debug("Sending animation pack");
2283
2284 if (m_isChildAgent)
2285 return;
2286
2287 UUID[] animIDs;
2288 int[] sequenceNums;
2289
2290 m_animations.GetArrays(out animIDs, out sequenceNums);
2291
2292 SendAnimPack(animIDs, sequenceNums);
2293 }
2294
2295 #endregion
2296
2297 #region Significant Movement Method
2298
2299 /// <summary>
2300 /// This checks for a significant movement and sends a courselocationchange update
2301 /// </summary>
2302 protected void CheckForSignificantMovement()
2303 {
2304 if (Util.GetDistanceTo(AbsolutePosition, posLastSignificantMove) > 0.5)
2305 {
2306 posLastSignificantMove = AbsolutePosition;
2307 m_scene.EventManager.TriggerSignificantClientMovement(m_controllingClient);
2308 m_scene.NotifyMyCoarseLocationChange();
2309 }
2310
2311 // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m
2312 if (Util.GetDistanceTo(AbsolutePosition,m_LastChildAgentUpdatePosition) > 32)
2313 {
2314 ChildAgentDataUpdate cadu = new ChildAgentDataUpdate();
2315 cadu.ActiveGroupID = UUID.Zero.Guid;
2316 cadu.AgentID = UUID.Guid;
2317 cadu.alwaysrun = m_setAlwaysRun;
2318 cadu.AVHeight = m_avHeight;
2319 sLLVector3 tempCameraCenter = new sLLVector3(new Vector3(m_CameraCenter.X, m_CameraCenter.Y, m_CameraCenter.Z));
2320 cadu.cameraPosition = tempCameraCenter;
2321 cadu.drawdistance = m_DrawDistance;
2322 if (m_scene.Permissions.IsGod(new UUID(cadu.AgentID)))
2323 cadu.godlevel = m_godlevel;
2324 cadu.GroupAccess = 0;
2325 cadu.Position = new sLLVector3(AbsolutePosition);
2326 cadu.regionHandle = m_scene.RegionInfo.RegionHandle;
2327 float multiplier = 1;
2328 int innacurateNeighbors = m_scene.GetInaccurateNeighborCount();
2329 if (innacurateNeighbors != 0)
2330 {
2331 multiplier = 1f / (float)innacurateNeighbors;
2332 }
2333 if (multiplier <= 0f)
2334 {
2335 multiplier = 0.25f;
2336 }
2337
2338 //m_log.Info("[NeighborThrottle]: " + m_scene.GetInaccurateNeighborCount().ToString() + " - m: " + multiplier.ToString());
2339 cadu.throttles = ControllingClient.GetThrottlesPacked(multiplier);
2340 cadu.Velocity = new sLLVector3(Velocity);
2341
2342 AgentPosition agentpos = new AgentPosition();
2343 agentpos.CopyFrom(cadu);
2344
2345 m_scene.SendOutChildAgentUpdates(agentpos, this);
2346
2347 m_LastChildAgentUpdatePosition.X = AbsolutePosition.X;
2348 m_LastChildAgentUpdatePosition.Y = AbsolutePosition.Y;
2349 m_LastChildAgentUpdatePosition.Z = AbsolutePosition.Z;
2350 }
2351 }
2352
2353 #endregion
2354
2355 #region Border Crossing Methods
2356
2357 /// <summary>
2358 /// Checks to see if the avatar is in range of a border and calls CrossToNewRegion
2359 /// </summary>
2360 protected void CheckForBorderCrossing()
2361 {
2362 if (IsChildAgent)
2363 return;
2364
2365 Vector3 pos2 = AbsolutePosition;
2366 Vector3 vel = Velocity;
2367
2368 float timeStep = 0.1f;
2369 pos2.X = pos2.X + (vel.X*timeStep);
2370 pos2.Y = pos2.Y + (vel.Y*timeStep);
2371 pos2.Z = pos2.Z + (vel.Z*timeStep);
2372
2373 if ((pos2.X < 0) || (pos2.X > Constants.RegionSize))
2374 {
2375 CrossToNewRegion();
2376 }
2377
2378 if ((pos2.Y < 0) || (pos2.Y > Constants.RegionSize))
2379 {
2380 CrossToNewRegion();
2381 }
2382 }
2383
2384 /// <summary>
2385 /// Moves the agent outside the region bounds
2386 /// Tells neighbor region that we're crossing to it
2387 /// If the neighbor accepts, remove the agent's viewable avatar from this scene
2388 /// set them to a child agent.
2389 /// </summary>
2390 protected void CrossToNewRegion()
2391 {
2392 Vector3 pos = AbsolutePosition;
2393 Vector3 newpos = new Vector3(pos.X, pos.Y, pos.Z);
2394 uint neighbourx = m_regionInfo.RegionLocX;
2395 uint neighboury = m_regionInfo.RegionLocY;
2396
2397 // distance to edge that will trigger crossing
2398 const float boundaryDistance = 1.7f;
2399
2400 // distance into new region to place avatar
2401 const float enterDistance = 0.1f;
2402
2403 if (pos.X < boundaryDistance)
2404 {
2405 neighbourx--;
2406 newpos.X = Constants.RegionSize - enterDistance;
2407 }
2408 else if (pos.X > Constants.RegionSize - boundaryDistance)
2409 {
2410 neighbourx++;
2411 newpos.X = enterDistance;
2412 }
2413
2414 if (pos.Y < boundaryDistance)
2415 {
2416 neighboury--;
2417 newpos.Y = Constants.RegionSize - enterDistance;
2418 }
2419 else if (pos.Y > Constants.RegionSize - boundaryDistance)
2420 {
2421 neighboury++;
2422 newpos.Y = enterDistance;
2423 }
2424
2425 Vector3 vel = m_velocity;
2426 ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize));
2427 SimpleRegionInfo neighbourRegion = m_scene.RequestNeighbouringRegionInfo(neighbourHandle);
2428 if (neighbourRegion != null && ValidateAttachments())
2429 {
2430 // When the neighbour is informed of the border crossing, it will set up CAPS handlers for the avatar
2431 // This means we need to remove the current caps handler here and possibly compensate later,
2432 // in case both scenes are being hosted on the same region server. Messy
2433 //m_scene.RemoveCapsHandler(UUID);
2434 newpos = newpos + (vel);
2435
2436 CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(UUID);
2437 if (userInfo != null)
2438 {
2439 userInfo.DropInventory();
2440 }
2441 else
2442 {
2443 m_log.WarnFormat("[SCENE PRESENCE]: No cached user info found for {0} {1} on leaving region", Name, UUID);
2444 }
2445
2446 bool crossingSuccessful =
2447 m_scene.InformNeighbourOfCrossing(neighbourHandle, m_controllingClient.AgentId, newpos,
2448 m_physicsActor.Flying);
2449 if (crossingSuccessful)
2450 {
2451 // Next, let's close the child agent connections that are too far away.
2452 CloseChildAgents(neighbourx, neighboury);
2453
2454 //AgentCircuitData circuitdata = m_controllingClient.RequestClientInfo();
2455 m_controllingClient.RequestClientInfo();
2456
2457 //Console.WriteLine("BEFORE CROSS");
2458 //Scene.DumpChildrenSeeds(UUID);
2459 //DumpKnownRegions();
2460 string agentcaps;
2461 if (!m_knownChildRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
2462 {
2463 m_log.ErrorFormat("[SCENE PRESENCE]: No CAPS information for region handle {0}, exiting CrossToNewRegion.",
2464 neighbourRegion.RegionHandle);
2465 return;
2466 }
2467 // TODO Should construct this behind a method
2468 string capsPath =
2469 "http://" + neighbourRegion.ExternalHostName + ":" + neighbourRegion.HttpPort
2470 + "/CAPS/" + agentcaps /*circuitdata.CapsPath*/ + "0000/";
2471
2472 m_log.DebugFormat("[CAPS]: Sending new CAPS seed url {0} to client {1}", capsPath, m_uuid);
2473
2474 IEventQueue eq = m_scene.RequestModuleInterface<IEventQueue>();
2475 if (eq != null)
2476 {
2477 eq.CrossRegion(neighbourHandle, newpos, vel, neighbourRegion.ExternalEndPoint,
2478 capsPath, UUID, ControllingClient.SessionId);
2479 }
2480 else
2481 {
2482 m_controllingClient.CrossRegion(neighbourHandle, newpos, vel, neighbourRegion.ExternalEndPoint,
2483 capsPath);
2484 }
2485
2486 MakeChildAgent();
2487 // now we have a child agent in this region. Request all interesting data about other (root) agents
2488 SendInitialFullUpdateToAllClients();
2489
2490 CrossAttachmentsIntoNewRegion(neighbourHandle, true);
2491
2492 // m_scene.SendKillObject(m_localId);
2493
2494 m_scene.NotifyMyCoarseLocationChange();
2495 // the user may change their profile information in other region,
2496 // so the userinfo in UserProfileCache is not reliable any more, delete it
2497 if (m_scene.NeedSceneCacheClear(UUID))
2498 {
2499 m_scene.CommsManager.UserProfileCacheService.RemoveUser(UUID);
2500 m_log.DebugFormat(
2501 "[SCENE PRESENCE]: User {0} is going to another region, profile cache removed", UUID);
2502 }
2503 }
2504 else
2505 {
2506 // Restore the user structures that we needed to delete before asking the receiving region to complete the crossing
2507 m_scene.CommsManager.UserProfileCacheService.RequestInventoryForUser(UUID);
2508 m_scene.CapsModule.AddCapsHandler(UUID);
2509 }
2510 }
2511
2512 //Console.WriteLine("AFTER CROSS");
2513 //Scene.DumpChildrenSeeds(UUID);
2514 //DumpKnownRegions();
2515 }
2516
2517 /// <summary>
2518 /// Computes which child agents to close when the scene presence moves to another region.
2519 /// Removes those regions from m_knownRegions.
2520 /// </summary>
2521 /// <param name="newRegionX">The new region's x on the map</param>
2522 /// <param name="newRegionY">The new region's y on the map</param>
2523 /// <returns></returns>
2524 public void CloseChildAgents(uint newRegionX, uint newRegionY)
2525 {
2526 List<ulong> byebyeRegions = new List<ulong>();
2527 m_log.DebugFormat(
2528 "[SCENE PRESENCE]: Closing child agents. Checking {0} regions in {1}",
2529 m_knownChildRegions.Keys.Count, Scene.RegionInfo.RegionName);
2530 //DumpKnownRegions();
2531
2532 lock (m_knownChildRegions)
2533 {
2534 foreach (ulong handle in m_knownChildRegions.Keys)
2535 {
2536 // Don't close the agent on this region yet
2537 if (handle != Scene.RegionInfo.RegionHandle)
2538 {
2539 uint x, y;
2540 Utils.LongToUInts(handle, out x, out y);
2541 x = x / Constants.RegionSize;
2542 y = y / Constants.RegionSize;
2543
2544 //Console.WriteLine("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX)));
2545 //Console.WriteLine("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY)));
2546 if (Util.IsOutsideView(x, newRegionX, y, newRegionY))
2547 {
2548 byebyeRegions.Add(handle);
2549 }
2550 }
2551 }
2552 }
2553
2554 if (byebyeRegions.Count > 0)
2555 {
2556 m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents");
2557 m_scene.SceneGridService.SendCloseChildAgentConnections(m_controllingClient.AgentId, byebyeRegions);
2558 }
2559
2560 foreach (ulong handle in byebyeRegions)
2561 {
2562 RemoveNeighbourRegion(handle);
2563 }
2564
2565 }
2566
2567 #endregion
2568
2569 /// <summary>
2570 /// This allows the Sim owner the abiility to kick users from their sim currently.
2571 /// It tells the client that the agent has permission to do so.
2572 /// </summary>
2573 public void GrantGodlikePowers(UUID agentID, UUID sessionID, UUID token, bool godStatus)
2574 {
2575 if (godStatus)
2576 {
2577 // For now, assign god level 200 to anyone
2578 // who is granted god powers, but has no god level set.
2579 //
2580 CachedUserInfo profile = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(agentID);
2581 if (profile.UserProfile.GodLevel > 0)
2582 m_godlevel = profile.UserProfile.GodLevel;
2583 else
2584 m_godlevel = 200;
2585 }
2586 else
2587 {
2588 m_godlevel = 0;
2589 }
2590
2591 ControllingClient.SendAdminResponse(token, (uint)m_godlevel);
2592 }
2593
2594 #region Child Agent Updates
2595
2596 public void ChildAgentDataUpdate(AgentData cAgentData)
2597 {
2598 //Console.WriteLine(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName);
2599 if (!IsChildAgent)
2600 return;
2601
2602 CopyFrom(cAgentData);
2603 }
2604
2605 /// <summary>
2606 /// This updates important decision making data about a child agent
2607 /// The main purpose is to figure out what objects to send to a child agent that's in a neighboring region
2608 /// </summary>
2609 public void ChildAgentDataUpdate(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY)
2610 {
2611 if (!IsChildAgent)
2612 return;
2613
2614 //Console.WriteLine(" >>> ChildAgentPositionUpdate <<< " + rRegionX + "-" + rRegionY);
2615 int shiftx = ((int)rRegionX - (int)tRegionX) * (int)Constants.RegionSize;
2616 int shifty = ((int)rRegionY - (int)tRegionY) * (int)Constants.RegionSize;
2617
2618 m_DrawDistance = cAgentData.Far;
2619 if (cAgentData.Position != new Vector3(-1, -1, -1)) // UGH!!
2620 m_pos = new Vector3(cAgentData.Position.X + shiftx, cAgentData.Position.Y + shifty, cAgentData.Position.Z);
2621
2622 // It's hard to say here.. We can't really tell where the camera position is unless it's in world cordinates from the sending region
2623 m_CameraCenter = cAgentData.Center;
2624
2625 m_avHeight = cAgentData.Size.Z;
2626 //SetHeight(cAgentData.AVHeight);
2627
2628 if ((cAgentData.Throttles != null) && cAgentData.Throttles.Length > 0)
2629 ControllingClient.SetChildAgentThrottle(cAgentData.Throttles);
2630
2631 // Sends out the objects in the user's draw distance if m_sendTasksToChild is true.
2632 if (m_scene.m_seeIntoRegionFromNeighbor)
2633 m_pendingObjects = null;
2634
2635 //cAgentData.AVHeight;
2636 //cAgentData.regionHandle;
2637 //m_velocity = cAgentData.Velocity;
2638 }
2639
2640 public void CopyTo(AgentData cAgent)
2641 {
2642 cAgent.AgentID = UUID;
2643 cAgent.RegionHandle = m_scene.RegionInfo.RegionHandle;
2644
2645 cAgent.Position = m_pos;
2646 cAgent.Velocity = m_velocity;
2647 cAgent.Center = m_CameraCenter;
2648 cAgent.Size = new Vector3(0, 0, m_avHeight);
2649 cAgent.AtAxis = m_CameraAtAxis;
2650 cAgent.LeftAxis = m_CameraLeftAxis;
2651 cAgent.UpAxis = m_CameraUpAxis;
2652
2653 cAgent.Far = m_DrawDistance;
2654
2655 // Throttles
2656 float multiplier = 1;
2657 int innacurateNeighbors = m_scene.GetInaccurateNeighborCount();
2658 if (innacurateNeighbors != 0)
2659 {
2660 multiplier = 1f / (float)innacurateNeighbors;
2661 }
2662 if (multiplier <= 0f)
2663 {
2664 multiplier = 0.25f;
2665 }
2666 //m_log.Info("[NeighborThrottle]: " + m_scene.GetInaccurateNeighborCount().ToString() + " - m: " + multiplier.ToString());
2667 cAgent.Throttles = ControllingClient.GetThrottlesPacked(multiplier);
2668
2669 cAgent.HeadRotation = m_headrotation;
2670 cAgent.BodyRotation = m_bodyRot;
2671 cAgent.ControlFlags = m_AgentControlFlags;
2672 if ((m_physicsActor != null) && (m_physicsActor.Flying))
2673 {
2674 cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY;
2675 }
2676
2677 if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID)))
2678 cAgent.GodLevel = (byte)m_godlevel;
2679 else
2680 cAgent.GodLevel = (byte) 0;
2681
2682 cAgent.AlwaysRun = m_setAlwaysRun;
2683
2684 //cAgent.AgentTextures = ???
2685 //cAgent.GroupID = ??
2686 // Groups???
2687
2688 // Animations???
2689
2690 cAgent.VisualParams = m_appearance.VisualParams;
2691 }
2692
2693 public void CopyFrom(AgentData cAgent)
2694 {
2695 m_rootRegionHandle= cAgent.RegionHandle;
2696 m_callbackURI = cAgent.CallbackURI;
2697
2698 m_pos = cAgent.Position;
2699 m_velocity = cAgent.Velocity;
2700 m_CameraCenter = cAgent.Center;
2701 m_avHeight = cAgent.Size.Z;
2702 m_CameraAtAxis = cAgent.AtAxis;
2703 m_CameraLeftAxis = cAgent.LeftAxis;
2704 m_CameraUpAxis = cAgent.UpAxis;
2705
2706 m_DrawDistance = cAgent.Far;
2707
2708 if ((cAgent.Throttles != null) && cAgent.Throttles.Length > 0)
2709 ControllingClient.SetChildAgentThrottle(cAgent.Throttles);
2710
2711 m_headrotation = cAgent.HeadRotation;
2712 m_bodyRot = cAgent.BodyRotation;
2713 m_AgentControlFlags = cAgent.ControlFlags; // We need more flags!
2714 if (m_physicsActor != null)
2715 {
2716 m_physicsActor.Flying = ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
2717 }
2718 if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID)))
2719 m_godlevel = cAgent.GodLevel;
2720 m_setAlwaysRun = cAgent.AlwaysRun;
2721
2722 //cAgent.AgentTextures = ???
2723
2724 //cAgent.GroupID = ??
2725 //Groups???
2726
2727 // Animations???
2728
2729 m_appearance.VisualParams = cAgent.VisualParams;
2730 }
2731
2732 #endregion Child Agent Updates
2733
2734 /// <summary>
2735 /// Handles part of the PID controller function for moving an avatar.
2736 /// </summary>
2737 public override void UpdateMovement()
2738 {
2739 m_newForce = false;
2740 lock (m_forcesList)
2741 {
2742 if (m_forcesList.Count > 0)
2743 {
2744 for (int i = 0; i < m_forcesList.Count; i++)
2745 {
2746 NewForce force = m_forcesList[i];
2747
2748 m_updateflag = true;
2749 try
2750 {
2751 movementvector.X = force.X;
2752 movementvector.Y = force.Y;
2753 movementvector.Z = force.Z;
2754 Velocity = movementvector;
2755 }
2756 catch (NullReferenceException)
2757 {
2758 // Under extreme load, this returns a NullReference Exception that we can ignore.
2759 // Ignoring this causes no movement to be sent to the physics engine...
2760 // which when the scene is moving at 1 frame every 10 seconds, it doesn't really matter!
2761 }
2762 m_newForce = true;
2763 }
2764 for (int i = 0; i < m_forcesList.Count; i++)
2765 {
2766 m_forcesList.RemoveAt(0);
2767 }
2768 }
2769 }
2770 }
2771
2772 static ScenePresence()
2773 {
2774 Primitive.TextureEntry textu = AvatarAppearance.GetDefaultTexture();
2775 DefaultTexture = textu.ToBytes();
2776 }
2777
2778 [Serializable]
2779 public class NewForce
2780 {
2781 public float X;
2782 public float Y;
2783 public float Z;
2784
2785 public NewForce()
2786 {
2787 }
2788 }
2789
2790 [Serializable]
2791 public class ScenePartUpdate : ISerializable
2792 {
2793 public UUID FullID;
2794 public uint LastFullUpdateTime;
2795 public uint LastTerseUpdateTime;
2796
2797 public ScenePartUpdate()
2798 {
2799 FullID = UUID.Zero;
2800 LastFullUpdateTime = 0;
2801 LastTerseUpdateTime = 0;
2802 }
2803
2804 protected ScenePartUpdate(SerializationInfo info, StreamingContext context)
2805 {
2806 //System.Console.WriteLine("ScenePartUpdate Deserialize BGN");
2807
2808 if (info == null)
2809 {
2810 throw new ArgumentNullException("info");
2811 }
2812
2813 FullID = new UUID((Guid)info.GetValue("FullID", typeof(Guid)));
2814 LastFullUpdateTime = (uint)info.GetValue("LastFullUpdateTime", typeof(uint));
2815 LastTerseUpdateTime = (uint)info.GetValue("LastTerseUpdateTime", typeof(uint));
2816
2817 //System.Console.WriteLine("ScenePartUpdate Deserialize END");
2818 }
2819
2820 [SecurityPermission(SecurityAction.LinkDemand,
2821 Flags = SecurityPermissionFlag.SerializationFormatter)]
2822 public virtual void GetObjectData(
2823 SerializationInfo info, StreamingContext context)
2824 {
2825 if (info == null)
2826 {
2827 throw new ArgumentNullException("info");
2828 }
2829
2830 info.AddValue("FullID", FullID.Guid);
2831 info.AddValue("LastFullUpdateTime", LastFullUpdateTime);
2832 info.AddValue("LastTerseUpdateTime", LastTerseUpdateTime);
2833 }
2834 }
2835
2836 public override void SetText(string text, Vector3 color, double alpha)
2837 {
2838 throw new Exception("Can't set Text on avatar.");
2839 }
2840
2841 /// <summary>
2842 /// Adds a physical representation of the avatar to the Physics plugin
2843 /// </summary>
2844 public void AddToPhysicalScene()
2845 {
2846 PhysicsScene scene = m_scene.PhysicsScene;
2847
2848 PhysicsVector pVec =
2849 new PhysicsVector(AbsolutePosition.X, AbsolutePosition.Y,
2850 AbsolutePosition.Z);
2851
2852 if (m_avHeight == 127.0f)
2853 {
2854 m_physicsActor = scene.AddAvatar(Firstname + "." + Lastname, pVec, new PhysicsVector(0, 0, 1.56f));
2855 }
2856 else
2857 {
2858 m_physicsActor = scene.AddAvatar(Firstname + "." + Lastname, pVec, new PhysicsVector(0, 0, m_avHeight));
2859 }
2860
2861 //m_physicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients;
2862 m_physicsActor.OnCollisionUpdate += PhysicsCollisionUpdate;
2863 m_physicsActor.SubscribeEvents(1000);
2864 m_physicsActor.LocalID = LocalId;
2865 }
2866
2867 // Event called by the physics plugin to tell the avatar about a collision.
2868 private void PhysicsCollisionUpdate(EventArgs e)
2869 {
2870 if (e == null)
2871 return;
2872 CollisionEventUpdate collisionData = (CollisionEventUpdate)e;
2873 Dictionary<uint, float> coldata = collisionData.m_objCollisionList;
2874 float starthealth = Health;
2875 uint killerObj = 0;
2876 foreach (uint localid in coldata.Keys)
2877 {
2878 if (coldata[localid] <= 0.10f || m_invulnerable)
2879 continue;
2880 //if (localid == 0)
2881 //continue;
2882
2883 Health -= coldata[localid] * 5;
2884
2885 if (Health <= 0)
2886 {
2887 if (localid != 0)
2888 killerObj = localid;
2889 }
2890 //m_log.Debug("[AVATAR]: Collision with localid: " + localid.ToString() + " at depth: " + coldata[localid].ToString());
2891 }
2892 //Health = 100;
2893 if (!m_invulnerable)
2894 {
2895 if (starthealth != Health)
2896 {
2897 ControllingClient.SendHealth(Health);
2898 }
2899 if (m_health <= 0)
2900 m_scene.EventManager.TriggerAvatarKill(killerObj, this);
2901 }
2902
2903 if (Velocity.X > 0 || Velocity.Y > 0)
2904 UpdateMovementAnimations();
2905 }
2906
2907 public void setHealthWithUpdate(float health)
2908 {
2909 Health = health;
2910 ControllingClient.SendHealth(Health);
2911 }
2912
2913 public void Close()
2914 {
2915 lock (m_attachments)
2916 {
2917 // Delete attachments from scene
2918 // Don't try to save, as this thread won't live long
2919 // enough to complete the save. This would cause no copy
2920 // attachments to poof!
2921 //
2922 foreach (SceneObjectGroup grp in m_attachments)
2923 {
2924 m_scene.DeleteSceneObject(grp, false);
2925 }
2926 m_attachments.Clear();
2927 }
2928 lock (m_knownChildRegions)
2929 {
2930 m_knownChildRegions.Clear();
2931 }
2932 lock (m_updateTimes)
2933 {
2934 m_updateTimes.Clear();
2935 }
2936 lock (m_partsUpdateQueue)
2937 {
2938 m_partsUpdateQueue.Clear();
2939 }
2940
2941 RemoveFromPhysicalScene();
2942 GC.Collect();
2943 }
2944
2945 public ScenePresence()
2946 {
2947/* JB
2948 if (Animations == null)
2949 {
2950 Animations = new AvatarAnimations();
2951 Animations.LoadAnims();
2952 }
2953*/
2954 if (DefaultTexture == null)
2955 {
2956 Primitive.TextureEntry textu = AvatarAppearance.GetDefaultTexture();
2957 DefaultTexture = textu.ToBytes();
2958 }
2959 }
2960
2961 public void AddAttachment(SceneObjectGroup gobj)
2962 {
2963 lock (m_attachments)
2964 {
2965 m_attachments.Add(gobj);
2966 }
2967 }
2968
2969 public bool HasAttachments()
2970 {
2971 return m_attachments.Count > 0;
2972 }
2973
2974 public bool HasScriptedAttachments()
2975 {
2976 lock (m_attachments)
2977 {
2978 foreach (SceneObjectGroup gobj in m_attachments)
2979 {
2980 if (gobj != null)
2981 {
2982 if (gobj.RootPart.Inventory.ContainsScripts())
2983 return true;
2984 }
2985 }
2986 }
2987 return false;
2988 }
2989
2990 public void RemoveAttachment(SceneObjectGroup gobj)
2991 {
2992 lock (m_attachments)
2993 {
2994 if (m_attachments.Contains(gobj))
2995 {
2996 m_attachments.Remove(gobj);
2997 }
2998 }
2999 }
3000
3001 public bool ValidateAttachments()
3002 {
3003 lock (m_attachments)
3004 {
3005 // Validate
3006 foreach (SceneObjectGroup gobj in m_attachments)
3007 {
3008 if (gobj == null)
3009 return false;
3010
3011 if (gobj.IsDeleted)
3012 return false;
3013 }
3014 }
3015 return true;
3016 }
3017
3018 public bool CrossAttachmentsIntoNewRegion(ulong regionHandle, bool silent)
3019 {
3020 lock (m_attachments)
3021 {
3022 // Validate
3023 foreach (SceneObjectGroup gobj in m_attachments)
3024 {
3025 if (gobj == null || gobj.IsDeleted)
3026 return false;
3027 }
3028
3029 foreach (SceneObjectGroup gobj in m_attachments)
3030 {
3031 // If the prim group is null then something must have happened to it!
3032 if (gobj != null && gobj.RootPart != null)
3033 {
3034 // Set the parent localID to 0 so it transfers over properly.
3035 gobj.RootPart.SetParentLocalId(0);
3036 gobj.RootPart.IsAttachment = false;
3037 gobj.AbsolutePosition = gobj.RootPart.AttachedPos;
3038 gobj.RootPart.LastOwnerID = gobj.GetFromAssetID();
3039 m_log.DebugFormat("[ATTACHMENT]: Sending attachment {0} to region {1}", gobj.UUID, regionHandle);
3040 m_scene.CrossPrimGroupIntoNewRegion(regionHandle, gobj, silent);
3041 }
3042 }
3043 m_attachments.Clear();
3044
3045 return true;
3046 }
3047 }
3048
3049 public void initializeScenePresence(IClientAPI client, RegionInfo region, Scene scene)
3050 {
3051 m_controllingClient = client;
3052 m_regionInfo = region;
3053 m_scene = scene;
3054
3055 RegisterToEvents();
3056
3057 /*
3058 AbsolutePosition = client.StartPos;
3059
3060 Animations = new AvatarAnimations();
3061 Animations.LoadAnims();
3062
3063 m_animations = new List<UUID>();
3064 m_animations.Add(Animations.AnimsUUID["STAND"]);
3065 m_animationSeqs.Add(m_controllingClient.NextAnimationSequenceNumber);
3066
3067 SetDirectionVectors();
3068 */
3069 }
3070
3071 protected ScenePresence(SerializationInfo info, StreamingContext context)
3072 : base (info, context)
3073 {
3074 //System.Console.WriteLine("ScenePresence Deserialize BGN");
3075
3076 if (info == null)
3077 {
3078 throw new ArgumentNullException("info");
3079 }
3080/* JB
3081 if (Animations == null)
3082 {
3083 Animations = new AvatarAnimations();
3084 Animations.LoadAnims();
3085 }
3086*/
3087 if (DefaultTexture == null)
3088 {
3089 Primitive.TextureEntry textu = AvatarAppearance.GetDefaultTexture();
3090 DefaultTexture = textu.ToBytes();
3091 }
3092
3093 m_animations = (AnimationSet)info.GetValue("m_animations", typeof(AnimationSet));
3094 m_updateflag = (bool)info.GetValue("m_updateflag", typeof(bool));
3095 m_movementflag = (byte)info.GetValue("m_movementflag", typeof(byte));
3096 m_forcesList = (List<NewForce>)info.GetValue("m_forcesList", typeof(List<NewForce>));
3097 m_updateCount = (short)info.GetValue("m_updateCount", typeof(short));
3098 m_requestedSitTargetID = (uint)info.GetValue("m_requestedSitTargetID", typeof(uint));
3099
3100 m_requestedSitOffset
3101 = new Vector3(
3102 (float)info.GetValue("m_requestedSitOffset.X", typeof(float)),
3103 (float)info.GetValue("m_requestedSitOffset.Y", typeof(float)),
3104 (float)info.GetValue("m_requestedSitOffset.Z", typeof(float)));
3105
3106 m_sitAvatarHeight = (float)info.GetValue("m_sitAvatarHeight", typeof(float));
3107 m_godlevel = (float)info.GetValue("m_godlevel", typeof(float));
3108 m_setAlwaysRun = (bool)info.GetValue("m_setAlwaysRun", typeof(bool));
3109
3110 m_bodyRot
3111 = new Quaternion(
3112 (float)info.GetValue("m_bodyRot.X", typeof(float)),
3113 (float)info.GetValue("m_bodyRot.Y", typeof(float)),
3114 (float)info.GetValue("m_bodyRot.Z", typeof(float)),
3115 (float)info.GetValue("m_bodyRot.W", typeof(float)));
3116
3117 IsRestrictedToRegion = (bool)info.GetValue("IsRestrictedToRegion", typeof(bool));
3118 m_newForce = (bool)info.GetValue("m_newForce", typeof(bool));
3119 //m_newAvatar = (bool)info.GetValue("m_newAvatar", typeof(bool));
3120 m_newCoarseLocations = (bool)info.GetValue("m_newCoarseLocations", typeof(bool));
3121 m_avHeight = (float)info.GetValue("m_avHeight", typeof(float));
3122 crossingFromRegion = (ulong)info.GetValue("crossingFromRegion", typeof(ulong));
3123
3124 List<float[]> Dir_Vectors_work = (List<float[]>)info.GetValue("Dir_Vectors", typeof(List<float[]>));
3125 List<Vector3> Dir_Vectors_work2 = new List<Vector3>();
3126
3127 foreach (float[] f3 in Dir_Vectors_work)
3128 {
3129 Dir_Vectors_work2.Add(new Vector3(f3[0], f3[1], f3[2]));
3130 }
3131
3132 Dir_Vectors = Dir_Vectors_work2.ToArray();
3133
3134 lastPhysPos
3135 = new Vector3(
3136 (float)info.GetValue("lastPhysPos.X", typeof(float)),
3137 (float)info.GetValue("lastPhysPos.Y", typeof(float)),
3138 (float)info.GetValue("lastPhysPos.Z", typeof(float)));
3139
3140 // Possibly we should store lastPhysRot. But there may well be not much point since rotation changes
3141 // wouldn't carry us across borders anyway
3142
3143 m_CameraCenter
3144 = new Vector3(
3145 (float)info.GetValue("m_CameraCenter.X", typeof(float)),
3146 (float)info.GetValue("m_CameraCenter.Y", typeof(float)),
3147 (float)info.GetValue("m_CameraCenter.Z", typeof(float)));
3148
3149 m_CameraAtAxis
3150 = new Vector3(
3151 (float)info.GetValue("m_CameraAtAxis.X", typeof(float)),
3152 (float)info.GetValue("m_CameraAtAxis.Y", typeof(float)),
3153 (float)info.GetValue("m_CameraAtAxis.Z", typeof(float)));
3154
3155 m_CameraLeftAxis
3156 = new Vector3(
3157 (float)info.GetValue("m_CameraLeftAxis.X", typeof(float)),
3158 (float)info.GetValue("m_CameraLeftAxis.Y", typeof(float)),
3159 (float)info.GetValue("m_CameraLeftAxis.Z", typeof(float)));
3160
3161 m_CameraUpAxis
3162 = new Vector3(
3163 (float)info.GetValue("m_CameraUpAxis.X", typeof(float)),
3164 (float)info.GetValue("m_CameraUpAxis.Y", typeof(float)),
3165 (float)info.GetValue("m_CameraUpAxis.Z", typeof(float)));
3166
3167 m_DrawDistance = (float)info.GetValue("m_DrawDistance", typeof(float));
3168 m_appearance = (AvatarAppearance)info.GetValue("m_appearance", typeof(AvatarAppearance));
3169
3170 m_knownChildRegions = (Dictionary<ulong, string>)info.GetValue("m_knownChildRegions", typeof(Dictionary<ulong, string>));
3171
3172 posLastSignificantMove
3173 = new Vector3(
3174 (float)info.GetValue("posLastSignificantMove.X", typeof(float)),
3175 (float)info.GetValue("posLastSignificantMove.Y", typeof(float)),
3176 (float)info.GetValue("posLastSignificantMove.Z", typeof(float)));
3177
3178 // m_partsUpdateQueue = (UpdateQueue)info.GetValue("m_partsUpdateQueue", typeof(UpdateQueue));
3179
3180 /*
3181 Dictionary<Guid, ScenePartUpdate> updateTimes_work
3182 = (Dictionary<Guid, ScenePartUpdate>)info.GetValue("m_updateTimes", typeof(Dictionary<Guid, ScenePartUpdate>));
3183
3184 foreach (Guid id in updateTimes_work.Keys)
3185 {
3186 m_updateTimes.Add(new UUID(id), updateTimes_work[id]);
3187 }
3188 */
3189 m_regionHandle = (ulong)info.GetValue("m_regionHandle", typeof(ulong));
3190 m_firstname = (string)info.GetValue("m_firstname", typeof(string));
3191 m_lastname = (string)info.GetValue("m_lastname", typeof(string));
3192 m_allowMovement = (bool)info.GetValue("m_allowMovement", typeof(bool));
3193 m_parentPosition = new Vector3((float)info.GetValue("m_parentPosition.X", typeof(float)),
3194 (float)info.GetValue("m_parentPosition.Y", typeof(float)),
3195 (float)info.GetValue("m_parentPosition.Z", typeof(float)));
3196
3197 m_isChildAgent = (bool)info.GetValue("m_isChildAgent", typeof(bool));
3198 m_parentID = (uint)info.GetValue("m_parentID", typeof(uint));
3199
3200// for OpenSim_v0.5
3201 currentParcelUUID = new UUID((Guid)info.GetValue("currentParcelUUID", typeof(Guid)));
3202
3203 lastKnownAllowedPosition
3204 = new Vector3(
3205 (float)info.GetValue("lastKnownAllowedPosition.X", typeof(float)),
3206 (float)info.GetValue("lastKnownAllowedPosition.Y", typeof(float)),
3207 (float)info.GetValue("lastKnownAllowedPosition.Z", typeof(float)));
3208
3209 sentMessageAboutRestrictedParcelFlyingDown = (bool)info.GetValue("sentMessageAboutRestrictedParcelFlyingDown", typeof(bool));
3210
3211 m_LastChildAgentUpdatePosition
3212 = new Vector3(
3213 (float)info.GetValue("m_LastChildAgentUpdatePosition.X", typeof(float)),
3214 (float)info.GetValue("m_LastChildAgentUpdatePosition.Y", typeof(float)),
3215 (float)info.GetValue("m_LastChildAgentUpdatePosition.Z", typeof(float)));
3216
3217 m_perfMonMS = (int)info.GetValue("m_perfMonMS", typeof(int));
3218 m_AgentControlFlags = (uint)info.GetValue("m_AgentControlFlags", typeof(uint));
3219
3220 m_headrotation
3221 = new Quaternion(
3222 (float)info.GetValue("m_headrotation.X", typeof(float)),
3223 (float)info.GetValue("m_headrotation.Y", typeof(float)),
3224 (float)info.GetValue("m_headrotation.Z", typeof(float)),
3225 (float)info.GetValue("m_headrotation.W", typeof(float)));
3226
3227 m_state = (byte)info.GetValue("m_state", typeof(byte));
3228
3229 //System.Console.WriteLine("ScenePresence Deserialize END");
3230 }
3231
3232 [SecurityPermission(SecurityAction.LinkDemand,
3233 Flags = SecurityPermissionFlag.SerializationFormatter)]
3234 public override void GetObjectData(
3235 SerializationInfo info, StreamingContext context)
3236 {
3237 if (info == null)
3238 {
3239 throw new ArgumentNullException("info");
3240 }
3241
3242 base.GetObjectData(info, context);
3243
3244 info.AddValue("m_animations", m_animations);
3245 info.AddValue("m_updateflag", m_updateflag);
3246 info.AddValue("m_movementflag", m_movementflag);
3247 info.AddValue("m_forcesList", m_forcesList);
3248 info.AddValue("m_updateCount", m_updateCount);
3249 info.AddValue("m_requestedSitTargetID", m_requestedSitTargetID);
3250
3251 // Vector3
3252 info.AddValue("m_requestedSitOffset.X", m_requestedSitOffset.X);
3253 info.AddValue("m_requestedSitOffset.Y", m_requestedSitOffset.Y);
3254 info.AddValue("m_requestedSitOffset.Z", m_requestedSitOffset.Z);
3255
3256 info.AddValue("m_sitAvatarHeight", m_sitAvatarHeight);
3257 info.AddValue("m_godlevel", m_godlevel);
3258 info.AddValue("m_setAlwaysRun", m_setAlwaysRun);
3259
3260 // Quaternion
3261 info.AddValue("m_bodyRot.X", m_bodyRot.X);
3262 info.AddValue("m_bodyRot.Y", m_bodyRot.Y);
3263 info.AddValue("m_bodyRot.Z", m_bodyRot.Z);
3264 info.AddValue("m_bodyRot.W", m_bodyRot.W);
3265
3266 info.AddValue("IsRestrictedToRegion", IsRestrictedToRegion);
3267 info.AddValue("m_newForce", m_newForce);
3268 //info.AddValue("m_newAvatar", m_newAvatar);
3269 info.AddValue("m_newCoarseLocations", m_newCoarseLocations);
3270 info.AddValue("m_gotAPrimitivesInScene", false);
3271 info.AddValue("m_avHeight", m_avHeight);
3272
3273 // info.AddValue("m_regionInfo", m_regionInfo);
3274
3275 info.AddValue("crossingFromRegion", crossingFromRegion);
3276
3277 List<float[]> Dir_Vectors_work = new List<float[]>();
3278
3279 foreach (Vector3 v3 in Dir_Vectors)
3280 {
3281 Dir_Vectors_work.Add(new float[] { v3.X, v3.Y, v3.Z });
3282 }
3283
3284 info.AddValue("Dir_Vectors", Dir_Vectors_work);
3285
3286 // Vector3
3287 info.AddValue("lastPhysPos.X", lastPhysPos.X);
3288 info.AddValue("lastPhysPos.Y", lastPhysPos.Y);
3289 info.AddValue("lastPhysPos.Z", lastPhysPos.Z);
3290
3291 // Possibly we should retrieve lastPhysRot. But there may well be not much point since rotation changes
3292 // wouldn't carry us across borders anyway
3293
3294 // Vector3
3295 info.AddValue("m_CameraCenter.X", m_CameraCenter.X);
3296 info.AddValue("m_CameraCenter.Y", m_CameraCenter.Y);
3297 info.AddValue("m_CameraCenter.Z", m_CameraCenter.Z);
3298
3299 // Vector3
3300 info.AddValue("m_CameraAtAxis.X", m_CameraAtAxis.X);
3301 info.AddValue("m_CameraAtAxis.Y", m_CameraAtAxis.Y);
3302 info.AddValue("m_CameraAtAxis.Z", m_CameraAtAxis.Z);
3303
3304 // Vector3
3305 info.AddValue("m_CameraLeftAxis.X", m_CameraLeftAxis.X);
3306 info.AddValue("m_CameraLeftAxis.Y", m_CameraLeftAxis.Y);
3307 info.AddValue("m_CameraLeftAxis.Z", m_CameraLeftAxis.Z);
3308
3309 // Vector3
3310 info.AddValue("m_CameraUpAxis.X", m_CameraUpAxis.X);
3311 info.AddValue("m_CameraUpAxis.Y", m_CameraUpAxis.Y);
3312 info.AddValue("m_CameraUpAxis.Z", m_CameraUpAxis.Z);
3313
3314 info.AddValue("m_DrawDistance", m_DrawDistance);
3315 info.AddValue("m_appearance", m_appearance);
3316 info.AddValue("m_knownChildRegions", m_knownChildRegions);
3317
3318 // Vector3
3319 info.AddValue("posLastSignificantMove.X", posLastSignificantMove.X);
3320 info.AddValue("posLastSignificantMove.Y", posLastSignificantMove.Y);
3321 info.AddValue("posLastSignificantMove.Z", posLastSignificantMove.Z);
3322
3323 //info.AddValue("m_partsUpdateQueue", m_partsUpdateQueue);
3324
3325 /*
3326 Dictionary<Guid, ScenePartUpdate> updateTimes_work = new Dictionary<Guid, ScenePartUpdate>();
3327
3328 foreach (UUID id in m_updateTimes.Keys)
3329 {
3330 updateTimes_work.Add(id.UUID, m_updateTimes[id]);
3331 }
3332
3333 info.AddValue("m_updateTimes", updateTimes_work);
3334 */
3335
3336 info.AddValue("m_regionHandle", m_regionHandle);
3337 info.AddValue("m_firstname", m_firstname);
3338 info.AddValue("m_lastname", m_lastname);
3339 info.AddValue("m_allowMovement", m_allowMovement);
3340 //info.AddValue("m_physicsActor", m_physicsActor);
3341 info.AddValue("m_parentPosition.X", m_parentPosition.X);
3342 info.AddValue("m_parentPosition.Y", m_parentPosition.Y);
3343 info.AddValue("m_parentPosition.Z", m_parentPosition.Z);
3344 info.AddValue("m_isChildAgent", m_isChildAgent);
3345 info.AddValue("m_parentID", m_parentID);
3346
3347// for OpenSim_v0.5
3348 info.AddValue("currentParcelUUID", currentParcelUUID.Guid);
3349
3350 info.AddValue("lastKnownAllowedPosition.X", lastKnownAllowedPosition.X);
3351 info.AddValue("lastKnownAllowedPosition.Y", lastKnownAllowedPosition.Y);
3352 info.AddValue("lastKnownAllowedPosition.Z", lastKnownAllowedPosition.Z);
3353
3354 info.AddValue("sentMessageAboutRestrictedParcelFlyingDown", sentMessageAboutRestrictedParcelFlyingDown);
3355
3356 info.AddValue("m_LastChildAgentUpdatePosition.X", m_LastChildAgentUpdatePosition.X);
3357 info.AddValue("m_LastChildAgentUpdatePosition.Y", m_LastChildAgentUpdatePosition.Y);
3358 info.AddValue("m_LastChildAgentUpdatePosition.Z", m_LastChildAgentUpdatePosition.Z);
3359
3360 info.AddValue("m_perfMonMS", m_perfMonMS);
3361 info.AddValue("m_AgentControlFlags", m_AgentControlFlags);
3362
3363 info.AddValue("m_headrotation.W", m_headrotation.W);
3364 info.AddValue("m_headrotation.X", m_headrotation.X);
3365 info.AddValue("m_headrotation.Y", m_headrotation.Y);
3366 info.AddValue("m_headrotation.Z", m_headrotation.Z);
3367
3368 info.AddValue("m_state", m_state);
3369
3370 List<Guid> knownPrimUUID_work = new List<Guid>();
3371
3372 info.AddValue("m_knownPrimUUID", knownPrimUUID_work);
3373 }
3374
3375 internal void PushForce(PhysicsVector impulse)
3376 {
3377 if (PhysicsActor != null)
3378 {
3379 PhysicsActor.AddForce(impulse,true);
3380 }
3381 }
3382
3383 public void RegisterControlEventsToScript(int controls, int accept, int pass_on, uint Obj_localID, UUID Script_item_UUID)
3384 {
3385 ScriptControllers obj = new ScriptControllers();
3386 obj.ignoreControls = ScriptControlled.CONTROL_ZERO;
3387 obj.eventControls = ScriptControlled.CONTROL_ZERO;
3388
3389 obj.itemID = Script_item_UUID;
3390 obj.objID = Obj_localID;
3391 if (pass_on == 0 && accept == 0)
3392 {
3393 IgnoredControls |= (ScriptControlled)controls;
3394 obj.ignoreControls = (ScriptControlled)controls;
3395 }
3396
3397 if (pass_on == 0 && accept == 1)
3398 {
3399 IgnoredControls |= (ScriptControlled)controls;
3400 obj.ignoreControls = (ScriptControlled)controls;
3401 obj.eventControls = (ScriptControlled)controls;
3402 }
3403 if (pass_on == 1 && accept == 1)
3404 {
3405 IgnoredControls = ScriptControlled.CONTROL_ZERO;
3406 obj.eventControls = (ScriptControlled)controls;
3407 obj.ignoreControls = ScriptControlled.CONTROL_ZERO;
3408 }
3409
3410 lock (scriptedcontrols)
3411 {
3412 if (pass_on == 1 && accept == 0)
3413 {
3414 IgnoredControls &= ~(ScriptControlled)controls;
3415 if (scriptedcontrols.ContainsKey(Script_item_UUID))
3416 scriptedcontrols.Remove(Script_item_UUID);
3417
3418 }
3419 else
3420 {
3421
3422 if (scriptedcontrols.ContainsKey(Script_item_UUID))
3423 {
3424 scriptedcontrols[Script_item_UUID] = obj;
3425 }
3426 else
3427 {
3428 scriptedcontrols.Add(Script_item_UUID, obj);
3429 }
3430 }
3431 }
3432 ControllingClient.SendTakeControls(controls, pass_on == 1 ? true : false, true);
3433 }
3434
3435 public void HandleForceReleaseControls(IClientAPI remoteClient, UUID agentID)
3436 {
3437 IgnoredControls = ScriptControlled.CONTROL_ZERO;
3438 lock (scriptedcontrols)
3439 {
3440 scriptedcontrols.Clear();
3441 }
3442 ControllingClient.SendTakeControls(int.MaxValue, false, false);
3443 }
3444
3445 public void UnRegisterControlEventsToScript(uint Obj_localID, UUID Script_item_UUID)
3446 {
3447 lock (scriptedcontrols)
3448 {
3449 if (scriptedcontrols.ContainsKey(Script_item_UUID))
3450 {
3451 ScriptControllers takecontrolls = scriptedcontrols[Script_item_UUID];
3452 ScriptControlled sctc = takecontrolls.eventControls;
3453 ControllingClient.SendTakeControls((int)sctc, false, false);
3454 ControllingClient.SendTakeControls((int)sctc, true, false);
3455
3456 scriptedcontrols.Remove(Script_item_UUID);
3457 IgnoredControls = ScriptControlled.CONTROL_ZERO;
3458 foreach (ScriptControllers scData in scriptedcontrols.Values)
3459 {
3460 IgnoredControls |= scData.ignoreControls;
3461 }
3462 }
3463
3464 }
3465 }
3466
3467 internal void SendControlToScripts(uint flags)
3468 {
3469
3470 ScriptControlled allflags = ScriptControlled.CONTROL_ZERO;
3471
3472 if (MouseDown)
3473 {
3474 allflags = LastCommands & (ScriptControlled.CONTROL_ML_LBUTTON | ScriptControlled.CONTROL_LBUTTON);
3475 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP) != 0 || (flags & unchecked((uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP)) != 0)
3476 {
3477 allflags = ScriptControlled.CONTROL_ZERO;
3478 MouseDown = true;
3479 }
3480 }
3481
3482 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN) != 0)
3483 {
3484 allflags |= ScriptControlled.CONTROL_ML_LBUTTON;
3485 MouseDown = true;
3486 }
3487 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0)
3488 {
3489 allflags |= ScriptControlled.CONTROL_LBUTTON;
3490 MouseDown = true;
3491 }
3492
3493 // find all activated controls, whether the scripts are interested in them or not
3494 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) != 0)
3495 {
3496 allflags |= ScriptControlled.CONTROL_FWD;
3497 }
3498 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG) != 0)
3499 {
3500 allflags |= ScriptControlled.CONTROL_BACK;
3501 }
3502 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS) != 0)
3503 {
3504 allflags |= ScriptControlled.CONTROL_UP;
3505 }
3506 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)
3507 {
3508 allflags |= ScriptControlled.CONTROL_DOWN;
3509 }
3510 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS) != 0)
3511 {
3512 allflags |= ScriptControlled.CONTROL_LEFT;
3513 }
3514 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) != 0)
3515 {
3516 allflags |= ScriptControlled.CONTROL_RIGHT;
3517 }
3518 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0)
3519 {
3520 allflags |= ScriptControlled.CONTROL_ROT_RIGHT;
3521 }
3522 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0)
3523 {
3524 allflags |= ScriptControlled.CONTROL_ROT_LEFT;
3525 }
3526 // optimization; we have to check per script, but if nothing is pressed and nothing changed, we can skip that
3527 if (allflags != ScriptControlled.CONTROL_ZERO || allflags != LastCommands)
3528 {
3529 lock (scriptedcontrols)
3530 {
3531 foreach (UUID scriptUUID in scriptedcontrols.Keys)
3532 {
3533 ScriptControllers scriptControlData = scriptedcontrols[scriptUUID];
3534 ScriptControlled localHeld = allflags & scriptControlData.eventControls; // the flags interesting for us
3535 ScriptControlled localLast = LastCommands & scriptControlData.eventControls; // the activated controls in the last cycle
3536 ScriptControlled localChange = localHeld ^ localLast; // the changed bits
3537 if (localHeld != ScriptControlled.CONTROL_ZERO || localChange != ScriptControlled.CONTROL_ZERO)
3538 {
3539 // only send if still pressed or just changed
3540 m_scene.EventManager.TriggerControlEvent(scriptControlData.objID, scriptUUID, UUID, (uint)localHeld, (uint)localChange);
3541 }
3542 }
3543 }
3544 }
3545
3546 LastCommands = allflags;
3547 }
3548
3549 internal uint RemoveIgnoredControls(uint flags, ScriptControlled Ignored)
3550 {
3551 if (Ignored == ScriptControlled.CONTROL_ZERO)
3552 return flags;
3553 if ((Ignored & ScriptControlled.CONTROL_BACK) != 0)
3554 flags &= ~((uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG | (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG);
3555 if ((Ignored & ScriptControlled.CONTROL_FWD) != 0)
3556 flags &= ~((uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS | (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS);
3557 if ((Ignored & ScriptControlled.CONTROL_DOWN) != 0)
3558 flags &= ~((uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG | (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG);
3559 if ((Ignored & ScriptControlled.CONTROL_UP) != 0)
3560 flags &= ~((uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS | (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_POS);
3561 if ((Ignored & ScriptControlled.CONTROL_LEFT) != 0)
3562 flags &= ~((uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS | (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS);
3563 if ((Ignored & ScriptControlled.CONTROL_RIGHT) != 0)
3564 flags &= ~((uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG | (uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG);
3565 if ((Ignored & ScriptControlled.CONTROL_ROT_LEFT) != 0)
3566 flags &= ~((uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG);
3567 if ((Ignored & ScriptControlled.CONTROL_ROT_RIGHT) != 0)
3568 flags &= ~((uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS);
3569 if ((Ignored & ScriptControlled.CONTROL_ML_LBUTTON) != 0)
3570 flags &= ~((uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN);
3571 if ((Ignored & ScriptControlled.CONTROL_LBUTTON) != 0)
3572 flags &= ~((uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP | (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN);
3573 //DIR_CONTROL_FLAG_FORWARD = AgentManager.ControlFlags.AGENT_CONTROL_AT_POS,
3574 //DIR_CONTROL_FLAG_BACK = AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG,
3575 //DIR_CONTROL_FLAG_LEFT = AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS,
3576 //DIR_CONTROL_FLAG_RIGHT = AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG,
3577 //DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS,
3578 //DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG,
3579 //DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG
3580 return flags;
3581 }
3582
3583 private void ItemReceived(UUID itemID)
3584 {
3585 if (IsChildAgent)
3586 return;
3587
3588 if (null == m_appearance)
3589 {
3590 m_log.Warn("[ATTACHMENT] Appearance has not been initialized");
3591 return;
3592 }
3593
3594 int attachpoint = m_appearance.GetAttachpoint(itemID);
3595 if (attachpoint == 0)
3596 return;
3597
3598 UUID asset = m_appearance.GetAttachedAsset(attachpoint);
3599 if (UUID.Zero == asset) // We have just logged in
3600 {
3601 try
3602 {
3603 // Rez from inventory
3604 asset = m_scene.RezSingleAttachment(ControllingClient,
3605 itemID, (uint)attachpoint);
3606 // Corner case: We are not yet a Scene Entity
3607 // Setting attachment info in RezSingleAttachment will fail
3608 // Set it here
3609 //
3610 m_appearance.SetAttachment((int)attachpoint, itemID,
3611 asset);
3612 m_log.InfoFormat("[ATTACHMENT] Rezzed attachment {0}, inworld asset {1}",
3613 itemID.ToString(), asset);
3614
3615 }
3616 catch (Exception e)
3617 {
3618 m_log.ErrorFormat("[ATTACHMENT] Unable to rez attachment: {0}", e.ToString());
3619 }
3620
3621 return;
3622 }
3623
3624 SceneObjectPart att = m_scene.GetSceneObjectPart(asset);
3625
3626
3627 // If this is null, then the asset has not yet appeared in world
3628 // so we revisit this when it does
3629 //
3630 if (att != null && att.UUID != asset) // Yes. It's really needed
3631 {
3632 m_log.DebugFormat("[ATTACHMENT]: Attach from in world: ItemID {0}, Asset ID {1}, Attachment inworld: {2}", itemID.ToString(), asset.ToString(), att.UUID.ToString());
3633
3634 // This will throw if crossing katty-korner
3635 // So catch it here to avoid the noid
3636 //
3637 try
3638 {
3639 // Attach from world, if not already attached
3640 if (att.ParentGroup != null && !att.IsAttachment)
3641 m_scene.AttachObject(ControllingClient, att.ParentGroup.LocalId, (uint)0, Quaternion.Identity, att.ParentGroup.AbsolutePosition, false);
3642 }
3643 catch (NullReferenceException)
3644 {
3645 }
3646 }
3647 }
3648 }
3649}
diff --git a/OpenSim/Region/Framework/Scenes/SceneXmlLoader.cs b/OpenSim/Region/Framework/Scenes/SceneXmlLoader.cs
new file mode 100644
index 0000000..7d9d247
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SceneXmlLoader.cs
@@ -0,0 +1,289 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Xml;
33using OpenMetaverse;
34using log4net;
35using OpenSim.Framework;
36using OpenSim.Region.Physics.Manager;
37
38namespace OpenSim.Region.Framework.Scenes
39{
40 /// <summary>
41 /// Static methods to serialize and deserialize scene objects to and from XML
42 /// </summary>
43 public class SceneXmlLoader
44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46
47 public static void LoadPrimsFromXml(Scene scene, string fileName, bool newIDS, Vector3 loadOffset)
48 {
49 XmlDocument doc = new XmlDocument();
50 XmlNode rootNode;
51
52 if (fileName.StartsWith("http:") || File.Exists(fileName))
53 {
54 XmlTextReader reader = new XmlTextReader(fileName);
55 reader.WhitespaceHandling = WhitespaceHandling.None;
56 doc.Load(reader);
57 reader.Close();
58 rootNode = doc.FirstChild;
59 foreach (XmlNode aPrimNode in rootNode.ChildNodes)
60 {
61 SceneObjectGroup obj = new SceneObjectGroup(aPrimNode.OuterXml, true);
62
63 if (newIDS)
64 {
65 obj.ResetIDs();
66 }
67 //if we want this to be a import method then we need new uuids for the object to avoid any clashes
68 //obj.RegenerateFullIDs();
69
70 scene.AddNewSceneObject(obj, true);
71 }
72 }
73 else
74 {
75 throw new Exception("Could not open file " + fileName + " for reading");
76 }
77 }
78
79 public static void SavePrimsToXml(Scene scene, string fileName)
80 {
81 FileStream file = new FileStream(fileName, FileMode.Create);
82 StreamWriter stream = new StreamWriter(file);
83 int primCount = 0;
84 stream.WriteLine("<scene>\n");
85
86 List<EntityBase> EntityList = scene.GetEntities();
87
88 foreach (EntityBase ent in EntityList)
89 {
90 if (ent is SceneObjectGroup)
91 {
92 stream.WriteLine(((SceneObjectGroup) ent).ToXmlString());
93 primCount++;
94 }
95 }
96 stream.WriteLine("</scene>\n");
97 stream.Close();
98 file.Close();
99 }
100
101 public static string SaveGroupToXml2(SceneObjectGroup grp)
102 {
103 return grp.ToXmlString2();
104 }
105
106 public static SceneObjectGroup DeserializeGroupFromXml2(string xmlString)
107 {
108 XmlDocument doc = new XmlDocument();
109 XmlNode rootNode;
110
111 XmlTextReader reader = new XmlTextReader(new StringReader(xmlString));
112 reader.WhitespaceHandling = WhitespaceHandling.None;
113 doc.Load(reader);
114 reader.Close();
115 rootNode = doc.FirstChild;
116
117 // This is to deal with neighbouring regions that are still surrounding the group xml with the <scene>
118 // tag. It should be possible to remove the first part of this if statement once we go past 0.5.9 (or
119 // when some other changes forces all regions to upgrade).
120 // This might seem rather pointless since prim crossing from this revision to an earlier revision remains
121 // broken. But it isn't much work to accomodate the old format here.
122 if (rootNode.LocalName.Equals("scene"))
123 {
124 foreach (XmlNode aPrimNode in rootNode.ChildNodes)
125 {
126 // There is only ever one prim. This oddity should be removeable post 0.5.9
127 return new SceneObjectGroup(aPrimNode.OuterXml);
128 }
129
130 return null;
131 }
132 else
133 {
134 return new SceneObjectGroup(rootNode.OuterXml);
135 }
136 }
137
138 /// <summary>
139 /// Load prims from the xml2 format
140 /// </summary>
141 /// <param name="scene"></param>
142 /// <param name="fileName"></param>
143 public static void LoadPrimsFromXml2(Scene scene, string fileName)
144 {
145 LoadPrimsFromXml2(scene, new XmlTextReader(fileName), false);
146 }
147
148 /// <summary>
149 /// Load prims from the xml2 format
150 /// </summary>
151 /// <param name="scene"></param>
152 /// <param name="reader"></param>
153 /// <param name="startScripts"></param>
154 public static void LoadPrimsFromXml2(Scene scene, TextReader reader, bool startScripts)
155 {
156 LoadPrimsFromXml2(scene, new XmlTextReader(reader), startScripts);
157 }
158
159 /// <summary>
160 /// Load prims from the xml2 format. This method will close the reader
161 /// </summary>
162 /// <param name="scene"></param>
163 /// <param name="reader"></param>
164 /// <param name="startScripts"></param>
165 protected static void LoadPrimsFromXml2(Scene scene, XmlTextReader reader, bool startScripts)
166 {
167 XmlDocument doc = new XmlDocument();
168 reader.WhitespaceHandling = WhitespaceHandling.None;
169 doc.Load(reader);
170 reader.Close();
171 XmlNode rootNode = doc.FirstChild;
172
173 ICollection<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
174 foreach (XmlNode aPrimNode in rootNode.ChildNodes)
175 {
176 SceneObjectGroup obj = CreatePrimFromXml2(scene, aPrimNode.OuterXml);
177 if (obj != null && startScripts)
178 sceneObjects.Add(obj);
179 }
180
181 foreach (SceneObjectGroup sceneObject in sceneObjects)
182 {
183 sceneObject.CreateScriptInstances(0, true, scene.DefaultScriptEngine, 0);
184 }
185 }
186
187 /// <summary>
188 /// Create a prim from the xml2 representation.
189 /// </summary>
190 /// <param name="scene"></param>
191 /// <param name="xmlData"></param>
192 /// <returns>The scene object created. null if the scene object already existed</returns>
193 protected static SceneObjectGroup CreatePrimFromXml2(Scene scene, string xmlData)
194 {
195 SceneObjectGroup obj = new SceneObjectGroup(xmlData);
196
197 if (scene.AddRestoredSceneObject(obj, true, false))
198 return obj;
199 else
200 return null;
201 }
202
203 public static void SavePrimsToXml2(Scene scene, string fileName)
204 {
205 List<EntityBase> EntityList = scene.GetEntities();
206
207 SavePrimListToXml2(EntityList, fileName);
208 }
209
210 public static void SavePrimsToXml2(Scene scene, TextWriter stream, Vector3 min, Vector3 max)
211 {
212 List<EntityBase> EntityList = scene.GetEntities();
213
214 SavePrimListToXml2(EntityList, stream, min, max);
215 }
216
217 public static void SaveNamedPrimsToXml2(Scene scene, string primName, string fileName)
218 {
219 m_log.InfoFormat(
220 "[SERIALISER]: Saving prims with name {0} in xml2 format for region {1} to {2}",
221 primName, scene.RegionInfo.RegionName, fileName);
222
223 List<EntityBase> entityList = scene.GetEntities();
224 List<EntityBase> primList = new List<EntityBase>();
225
226 foreach (EntityBase ent in entityList)
227 {
228 if (ent is SceneObjectGroup)
229 {
230 if (ent.Name == primName)
231 {
232 primList.Add(ent);
233 }
234 }
235 }
236
237 SavePrimListToXml2(primList, fileName);
238 }
239
240 public static void SavePrimListToXml2(List<EntityBase> entityList, string fileName)
241 {
242 FileStream file = new FileStream(fileName, FileMode.Create);
243 try
244 {
245 StreamWriter stream = new StreamWriter(file);
246 try
247 {
248 SavePrimListToXml2(entityList, stream, Vector3.Zero, Vector3.Zero);
249 }
250 finally
251 {
252 stream.Close();
253 }
254 }
255 finally
256 {
257 file.Close();
258 }
259 }
260
261 public static void SavePrimListToXml2(List<EntityBase> entityList, TextWriter stream, Vector3 min, Vector3 max)
262 {
263 int primCount = 0;
264 stream.WriteLine("<scene>\n");
265
266 foreach (EntityBase ent in entityList)
267 {
268 if (ent is SceneObjectGroup)
269 {
270 SceneObjectGroup g = (SceneObjectGroup)ent;
271 if (!min.Equals(Vector3.Zero) || !max.Equals(Vector3.Zero))
272 {
273 Vector3 pos = g.RootPart.GetWorldPosition();
274 if (min.X > pos.X || min.Y > pos.Y || min.Z > pos.Z)
275 continue;
276 if (max.X < pos.X || max.Y < pos.Y || max.Z < pos.Z)
277 continue;
278 }
279
280 stream.WriteLine(g.ToXmlString2());
281 primCount++;
282 }
283 }
284 stream.WriteLine("</scene>\n");
285 stream.Flush();
286 }
287
288 }
289}
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs b/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs
new file mode 100644
index 0000000..440820b
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scripting/IScriptHost.cs
@@ -0,0 +1,46 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenMetaverse;
29
30namespace OpenSim.Region.Framework.Scenes.Scripting
31{
32 public interface IScriptHost
33 {
34 string Name { get; set; }
35 string Description { get; set; }
36
37 UUID UUID { get; }
38 UUID ObjectOwner { get; }
39 UUID ObjectCreator { get; }
40 Vector3 AbsolutePosition { get; }
41
42 string SitName { get; set; }
43 string TouchName { get; set; }
44 void SetText(string text, Vector3 color, double alpha);
45 }
46}
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs b/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs
new file mode 100644
index 0000000..fd7ff96
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs
@@ -0,0 +1,86 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenMetaverse;
30
31namespace OpenSim.Region.Framework.Scenes.Scripting
32{
33 public class NullScriptHost : IScriptHost
34 {
35 private Vector3 m_pos = new Vector3(128, 128, 30);
36
37 public string Name
38 {
39 get { return "Object"; }
40 set { }
41 }
42
43 public string SitName
44 {
45 get { return String.Empty; }
46 set { }
47 }
48
49 public string TouchName
50 {
51 get { return String.Empty; }
52 set { }
53 }
54
55 public string Description
56 {
57 get { return String.Empty; }
58 set { }
59 }
60
61 public UUID UUID
62 {
63 get { return UUID.Zero; }
64 }
65
66 public UUID ObjectOwner
67 {
68 get { return UUID.Zero; }
69 }
70
71 public UUID ObjectCreator
72 {
73 get { return UUID.Zero; }
74 }
75
76 public Vector3 AbsolutePosition
77 {
78 get { return m_pos; }
79 }
80
81 public void SetText(string text, Vector3 color, double alpha)
82 {
83 Console.WriteLine("Tried to SetText [{0}] on NullScriptHost", text);
84 }
85 }
86}
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs b/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs
new file mode 100644
index 0000000..d358187
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineInterface.cs
@@ -0,0 +1,38 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28//TODO: WHERE TO PLACE THIS?
29
30namespace OpenSim.Region.Framework.Scenes.Scripting
31{
32 public interface ScriptEngineInterface
33 {
34 void InitializeEngine(Scene Sceneworld);
35 void Shutdown();
36// void StartScript(string ScriptID, IScriptHost ObjectID);
37 }
38}
diff --git a/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs b/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs
new file mode 100644
index 0000000..58228cc
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Scripting/ScriptEngineLoader.cs
@@ -0,0 +1,119 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/* Original code: Tedd Hansen */
29using System;
30using System.IO;
31using System.Reflection;
32using log4net;
33
34namespace OpenSim.Region.Framework.Scenes.Scripting
35{
36 public class ScriptEngineLoader
37 {
38 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
39
40 public ScriptEngineInterface LoadScriptEngine(string EngineName)
41 {
42 ScriptEngineInterface ret = null;
43 try
44 {
45 ret =
46 LoadAndInitAssembly(
47 Path.Combine("ScriptEngines", "OpenSim.Region.ScriptEngine." + EngineName + ".dll"),
48 "OpenSim.Region.ScriptEngine." + EngineName + ".ScriptEngine");
49 }
50 catch (Exception e)
51 {
52 m_log.Error("[ScriptEngine]: " +
53 "Error loading assembly \"" + EngineName + "\": " + e.Message + ", " +
54 e.StackTrace.ToString());
55 }
56 return ret;
57 }
58
59 /// <summary>
60 /// Does actual loading and initialization of script Assembly
61 /// </summary>
62 /// <param name="FreeAppDomain">AppDomain to load script into</param>
63 /// <param name="FileName">FileName of script assembly (.dll)</param>
64 /// <returns></returns>
65 private ScriptEngineInterface LoadAndInitAssembly(string FileName, string NameSpace)
66 {
67 //Common.SendToDebug("Loading ScriptEngine Assembly " + FileName);
68 // Load .Net Assembly (.dll)
69 // Initialize and return it
70
71 // TODO: Add error handling
72
73 Assembly a;
74 //try
75 //{
76
77
78 // Load to default appdomain (temporary)
79 a = Assembly.LoadFrom(FileName);
80 // Load to specified appdomain
81 // TODO: Insert security
82 //a = FreeAppDomain.Load(FileName);
83 //}
84 //catch (Exception e)
85 //{
86 // m_log.Error("[ScriptEngine]: Error loading assembly \String.Empty + FileName + "\": " + e.ToString());
87 //}
88
89
90 //Console.WriteLine("Loading: " + FileName);
91 //foreach (Type _t in a.GetTypes())
92 //{
93 // Console.WriteLine("Type: " + _t.ToString());
94 //}
95
96 Type t;
97 //try
98 //{
99 t = a.GetType(NameSpace, true);
100 //}
101 //catch (Exception e)
102 //{
103 // m_log.Error("[ScriptEngine]: Error initializing type \String.Empty + NameSpace + "\" from \String.Empty + FileName + "\": " + e.ToString());
104 //}
105
106 ScriptEngineInterface ret;
107 //try
108 //{
109 ret = (ScriptEngineInterface) Activator.CreateInstance(t);
110 //}
111 //catch (Exception e)
112 //{
113 // m_log.Error("[ScriptEngine]: Error initializing type \String.Empty + NameSpace + "\" from \String.Empty + FileName + "\": " + e.ToString());
114 //}
115
116 return ret;
117 }
118 }
119}
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
new file mode 100644
index 0000000..b2cea5d
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs
@@ -0,0 +1,450 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29//using System.Collections.Generic;
30using System.Timers;
31using OpenMetaverse.Packets;
32using OpenSim.Framework;
33using OpenSim.Framework.Statistics;
34using OpenSim.Region.Framework.Interfaces;
35
36namespace OpenSim.Region.Framework.Scenes
37{
38 public class SimStatsReporter
39 {
40 public delegate void SendStatResult(SimStats stats);
41
42 public delegate void YourStatsAreWrong();
43
44 public event SendStatResult OnSendStatsResult;
45
46 public event YourStatsAreWrong OnStatsIncorrect;
47
48 private SendStatResult handlerSendStatResult = null;
49
50 private YourStatsAreWrong handlerStatsIncorrect = null;
51
52 private enum Stats : uint
53 {
54 TimeDilation = 0,
55 SimFPS = 1,
56 PhysicsFPS = 2,
57 AgentUpdates = 3,
58 FrameMS = 4,
59 NetMS = 5,
60 OtherMS = 6,
61 PhysicsMS = 7,
62 AgentMS = 8,
63 ImageMS = 9,
64 ScriptMS = 10,
65 TotalPrim = 11,
66 ActivePrim = 12,
67 Agents = 13,
68 ChildAgents = 14,
69 ActiveScripts = 15,
70 ScriptLinesPerSecond = 16,
71 InPacketsPerSecond = 17,
72 OutPacketsPerSecond = 18,
73 PendingDownloads = 19,
74 PendingUploads = 20,
75 UnAckedBytes = 24,
76 }
77
78 // Sending a stats update every 3 seconds
79 private int statsUpdatesEveryMS = 3000;
80 private float statsUpdateFactor = 0;
81 private float m_timeDilation = 0;
82 private int m_fps = 0;
83 // saved last reported value so there is something available for llGetRegionFPS
84 private float lastReportedSimFPS = 0;
85 private float m_pfps = 0;
86 private int m_agentUpdates = 0;
87
88 private int m_frameMS = 0;
89 private int m_netMS = 0;
90 private int m_agentMS = 0;
91 private int m_physicsMS = 0;
92 private int m_imageMS = 0;
93 private int m_otherMS = 0;
94
95//Ckrinke: (3-21-08) Comment out to remove a compiler warning. Bring back into play when needed.
96//Ckrinke private int m_scriptMS = 0;
97
98 private int m_rootAgents = 0;
99 private int m_childAgents = 0;
100 private int m_numPrim = 0;
101 private int m_inPacketsPerSecond = 0;
102 private int m_outPacketsPerSecond = 0;
103 private int m_activePrim = 0;
104 private int m_unAckedBytes = 0;
105 private int m_pendingDownloads = 0;
106 private int m_pendingUploads = 0;
107 private int m_activeScripts = 0;
108 private int m_scriptLinesPerSecond = 0;
109
110 private int objectCapacity = 45000;
111
112 private Scene m_scene;
113
114 private RegionInfo ReportingRegion;
115
116 private Timer m_report = new Timer();
117
118
119 public SimStatsReporter(Scene scene)
120 {
121 statsUpdateFactor = (float)(statsUpdatesEveryMS / 1000);
122 m_scene = scene;
123 ReportingRegion = scene.RegionInfo;
124
125 m_report.AutoReset = true;
126 m_report.Interval = statsUpdatesEveryMS;
127 m_report.Elapsed += new ElapsedEventHandler(statsHeartBeat);
128 m_report.Enabled = true;
129
130 if (StatsManager.SimExtraStats != null)
131 OnSendStatsResult += StatsManager.SimExtraStats.ReceiveClassicSimStatsPacket;
132 }
133
134 public void SetUpdateMS(int ms)
135 {
136 statsUpdatesEveryMS = ms;
137 statsUpdateFactor = (float)(statsUpdatesEveryMS / 1000);
138 m_report.Interval = statsUpdatesEveryMS;
139 }
140
141 private void statsHeartBeat(object sender, EventArgs e)
142 {
143 SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[21];
144 SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock();
145
146 // Know what's not thread safe in Mono... modifying timers.
147 // System.Console.WriteLine("Firing Stats Heart Beat");
148 lock (m_report)
149 {
150 uint regionFlags = 0;
151
152 try
153 {
154 IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
155 regionFlags = estateModule != null ? estateModule.GetRegionFlags() : (uint) 0;
156 }
157 catch (Exception)
158 {
159 // leave region flags at 0
160 }
161
162#region various statistic googly moogly
163
164 // Our FPS is actually 10fps, so multiplying by 5 to get the amount that people expect there
165 // 0-50 is pretty close to 0-45
166 float simfps = (int) ((m_fps * 5));
167 // save the reported value so there is something available for llGetRegionFPS
168 lastReportedSimFPS = (float)simfps / statsUpdateFactor;
169
170 //if (simfps > 45)
171 //simfps = simfps - (simfps - 45);
172 //if (simfps < 0)
173 //simfps = 0;
174
175 //
176 float physfps = ((m_pfps / 1000));
177
178 //if (physfps > 600)
179 //physfps = physfps - (physfps - 600);
180
181 if (physfps < 0)
182 physfps = 0;
183
184#endregion
185
186 //Our time dilation is 0.91 when we're running a full speed,
187 // therefore to make sure we get an appropriate range,
188 // we have to factor in our error. (0.10f * statsUpdateFactor)
189 // multiplies the fix for the error times the amount of times it'll occur a second
190 // / 10 divides the value by the number of times the sim heartbeat runs (10fps)
191 // Then we divide the whole amount by the amount of seconds pass in between stats updates.
192
193 for (int i = 0; i<21;i++)
194 {
195 sb[i] = new SimStatsPacket.StatBlock();
196 }
197
198 sb[0].StatID = (uint) Stats.TimeDilation;
199 sb[0].StatValue = (Single.IsNaN(m_timeDilation)) ? 0.1f : m_timeDilation ; //((((m_timeDilation + (0.10f * statsUpdateFactor)) /10) / statsUpdateFactor));
200
201 sb[1].StatID = (uint) Stats.SimFPS;
202 sb[1].StatValue = simfps/statsUpdateFactor;
203
204 sb[2].StatID = (uint) Stats.PhysicsFPS;
205 sb[2].StatValue = physfps / statsUpdateFactor;
206
207 sb[3].StatID = (uint) Stats.AgentUpdates;
208 sb[3].StatValue = (m_agentUpdates / statsUpdateFactor);
209
210 sb[4].StatID = (uint) Stats.Agents;
211 sb[4].StatValue = m_rootAgents;
212
213 sb[5].StatID = (uint) Stats.ChildAgents;
214 sb[5].StatValue = m_childAgents;
215
216 sb[6].StatID = (uint) Stats.TotalPrim;
217 sb[6].StatValue = m_numPrim;
218
219 sb[7].StatID = (uint) Stats.ActivePrim;
220 sb[7].StatValue = m_activePrim;
221
222 sb[8].StatID = (uint)Stats.FrameMS;
223 sb[8].StatValue = m_frameMS / statsUpdateFactor;
224
225 sb[9].StatID = (uint)Stats.NetMS;
226 sb[9].StatValue = m_netMS / statsUpdateFactor;
227
228 sb[10].StatID = (uint)Stats.PhysicsMS;
229 sb[10].StatValue = m_physicsMS / statsUpdateFactor;
230
231 sb[11].StatID = (uint)Stats.ImageMS ;
232 sb[11].StatValue = m_imageMS / statsUpdateFactor;
233
234 sb[12].StatID = (uint)Stats.OtherMS;
235 sb[12].StatValue = m_otherMS / statsUpdateFactor;
236
237 sb[13].StatID = (uint)Stats.InPacketsPerSecond;
238 sb[13].StatValue = (m_inPacketsPerSecond);
239
240 sb[14].StatID = (uint)Stats.OutPacketsPerSecond;
241 sb[14].StatValue = (m_outPacketsPerSecond / statsUpdateFactor);
242
243 sb[15].StatID = (uint)Stats.UnAckedBytes;
244 sb[15].StatValue = m_unAckedBytes;
245
246 sb[16].StatID = (uint)Stats.AgentMS;
247 sb[16].StatValue = m_agentMS / statsUpdateFactor;
248
249 sb[17].StatID = (uint)Stats.PendingDownloads;
250 sb[17].StatValue = m_pendingDownloads;
251
252 sb[18].StatID = (uint)Stats.PendingUploads;
253 sb[18].StatValue = m_pendingUploads;
254
255 sb[19].StatID = (uint)Stats.ActiveScripts;
256 sb[19].StatValue = m_activeScripts;
257
258 sb[20].StatID = (uint)Stats.ScriptLinesPerSecond;
259 sb[20].StatValue = m_scriptLinesPerSecond / statsUpdateFactor;
260
261 SimStats simStats
262 = new SimStats(
263 ReportingRegion.RegionLocX, ReportingRegion.RegionLocY, regionFlags, (uint)objectCapacity, rb, sb, m_scene.RegionInfo.originRegionID);
264
265 handlerSendStatResult = OnSendStatsResult;
266 if (handlerSendStatResult != null)
267 {
268 handlerSendStatResult(simStats);
269 }
270 resetvalues();
271 }
272 }
273
274 private void resetvalues()
275 {
276 m_timeDilation = 0;
277 m_fps = 0;
278 m_pfps = 0;
279 m_agentUpdates = 0;
280 m_inPacketsPerSecond = 0;
281 m_outPacketsPerSecond = 0;
282 m_unAckedBytes = 0;
283 m_scriptLinesPerSecond = 0;
284
285 m_frameMS = 0;
286 m_agentMS = 0;
287 m_netMS = 0;
288 m_physicsMS = 0;
289 m_imageMS = 0;
290 m_otherMS = 0;
291
292//Ckrinke This variable is not used, so comment to remove compiler warning until it is used.
293//Ckrinke m_scriptMS = 0;
294 }
295
296 # region methods called from Scene
297 // The majority of these functions are additive
298 // so that you can easily change the amount of
299 // seconds in between sim stats updates
300
301 public void AddTimeDilation(float td)
302 {
303 //float tdsetting = td;
304 //if (tdsetting > 1.0f)
305 //tdsetting = (tdsetting - (tdsetting - 0.91f));
306
307 //if (tdsetting < 0)
308 //tdsetting = 0.0f;
309 m_timeDilation = td;
310 }
311
312 public void SetRootAgents(int rootAgents)
313 {
314 m_rootAgents = rootAgents;
315 CheckStatSanity();
316
317 }
318
319 internal void CheckStatSanity()
320 {
321 if (m_rootAgents < 0 || m_childAgents < 0)
322 {
323 handlerStatsIncorrect = OnStatsIncorrect;
324 if (handlerStatsIncorrect != null)
325 {
326 handlerStatsIncorrect();
327 }
328 }
329 if (m_rootAgents == 0 && m_childAgents == 0)
330 {
331 m_unAckedBytes = 0;
332 }
333 }
334
335 public void SetChildAgents(int childAgents)
336 {
337 m_childAgents = childAgents;
338 CheckStatSanity();
339 }
340
341 public void SetObjects(int objects)
342 {
343 m_numPrim = objects;
344 }
345
346 public void SetActiveObjects(int objects)
347 {
348 m_activePrim = objects;
349 }
350
351 public void AddFPS(int frames)
352 {
353 m_fps += frames;
354 }
355
356 public void AddPhysicsFPS(float frames)
357 {
358 m_pfps += frames;
359 }
360
361 public void AddAgentUpdates(int numUpdates)
362 {
363 m_agentUpdates += numUpdates;
364 }
365
366 public void AddInPackets(int numPackets)
367 {
368 m_inPacketsPerSecond += numPackets;
369 }
370
371 public void AddOutPackets(int numPackets)
372 {
373 m_outPacketsPerSecond += numPackets;
374 }
375
376 public void AddunAckedBytes(int numBytes)
377 {
378 m_unAckedBytes += numBytes;
379 if (m_unAckedBytes < 0) m_unAckedBytes = 0;
380 }
381
382 public void addFrameMS(int ms)
383 {
384 m_frameMS += ms;
385 }
386 public void addNetMS(int ms)
387 {
388 m_netMS += ms;
389 }
390 public void addAgentMS(int ms)
391 {
392 m_agentMS += ms;
393 }
394 public void addPhysicsMS(int ms)
395 {
396 m_physicsMS += ms;
397 }
398 public void addImageMS(int ms)
399 {
400 m_imageMS += ms;
401 }
402 public void addOtherMS(int ms)
403 {
404 m_otherMS += ms;
405 }
406
407// private static readonly log4net.ILog m_log
408// = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
409
410 public void addPendingDownload(int count)
411 {
412 m_pendingDownloads += count;
413 if (m_pendingDownloads < 0) m_pendingDownloads = 0;
414 //m_log.InfoFormat("[stats]: Adding {0} to pending downloads to make {1}", count, m_pendingDownloads);
415 }
416
417 public void addScriptLines(int count)
418 {
419 m_scriptLinesPerSecond += count;
420 }
421
422 public void SetActiveScripts(int count)
423 {
424 m_activeScripts = count;
425 }
426
427 public void SetObjectCapacity(int objects)
428 {
429 objectCapacity = objects;
430 }
431
432 /// <summary>
433 /// This is for llGetRegionFPS
434 /// </summary>
435 public float getLastReportedSimFPS()
436 {
437 return lastReportedSimFPS;
438 }
439
440 public void AddPacketsFromClientStats(int inPackets, int outPackets, int unAckedBytes)
441 {
442 AddInPackets(inPackets);
443 AddOutPackets(outPackets);
444 AddunAckedBytes(unAckedBytes);
445
446 }
447
448 #endregion
449 }
450}
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
new file mode 100644
index 0000000..55c5181
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
@@ -0,0 +1,242 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenSim.Framework;
29using OpenSim.Region.Framework.Interfaces;
30using System;
31using System.Text;
32using System.Xml;
33using System.IO;
34using System.Xml.Serialization;
35
36namespace OpenSim.Region.Framework.Scenes
37{
38 /// <summary>
39 /// A new version of the old Channel class, simplified
40 /// </summary>
41 public class TerrainChannel : ITerrainChannel
42 {
43 private readonly bool[,] taint;
44 private double[,] map;
45
46 public TerrainChannel()
47 {
48 map = new double[Constants.RegionSize, Constants.RegionSize];
49 taint = new bool[Constants.RegionSize / 16,Constants.RegionSize / 16];
50
51 int x;
52 for (x = 0; x < Constants.RegionSize; x++)
53 {
54 int y;
55 for (y = 0; y < Constants.RegionSize; y++)
56 {
57 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
58 double spherFacA = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01;
59 double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001;
60 if (map[x, y] < spherFacA)
61 map[x, y] = spherFacA;
62 if (map[x, y] < spherFacB)
63 map[x, y] = spherFacB;
64 }
65 }
66 }
67
68 public TerrainChannel(double[,] import)
69 {
70 map = import;
71 taint = new bool[import.GetLength(0),import.GetLength(1)];
72 }
73
74 public TerrainChannel(bool createMap)
75 {
76 if (createMap)
77 {
78 map = new double[Constants.RegionSize,Constants.RegionSize];
79 taint = new bool[Constants.RegionSize / 16,Constants.RegionSize / 16];
80 }
81 }
82
83 public TerrainChannel(int w, int h)
84 {
85 map = new double[w,h];
86 taint = new bool[w / 16,h / 16];
87 }
88
89 #region ITerrainChannel Members
90
91 public int Width
92 {
93 get { return map.GetLength(0); }
94 }
95
96 public int Height
97 {
98 get { return map.GetLength(1); }
99 }
100
101 public ITerrainChannel MakeCopy()
102 {
103 TerrainChannel copy = new TerrainChannel(false);
104 copy.map = (double[,]) map.Clone();
105
106 return copy;
107 }
108
109 public float[] GetFloatsSerialised()
110 {
111 // Move the member variables into local variables, calling
112 // member variables 256*256 times gets expensive
113 int w = Width;
114 int h = Height;
115 float[] heights = new float[w * h];
116
117 int i, j; // map coordinates
118 int idx = 0; // index into serialized array
119 for (i = 0; i < h; i++)
120 {
121 for (j = 0; j < w; j++)
122 {
123 heights[idx++] = (float)map[j, i];
124 }
125 }
126
127 return heights;
128 }
129
130 public double[,] GetDoubles()
131 {
132 return map;
133 }
134
135 public double this[int x, int y]
136 {
137 get { return map[x, y]; }
138 set
139 {
140 // Will "fix" terrain hole problems. Although not fantastically.
141 if (Double.IsNaN(value) || Double.IsInfinity(value))
142 return;
143
144 if (map[x, y] != value)
145 {
146 taint[x / 16, y / 16] = true;
147 map[x, y] = value;
148 }
149 }
150 }
151
152 public bool Tainted(int x, int y)
153 {
154 if (taint[x / 16, y / 16])
155 {
156 taint[x / 16, y / 16] = false;
157 return true;
158 }
159 return false;
160 }
161
162 #endregion
163
164 public TerrainChannel Copy()
165 {
166 TerrainChannel copy = new TerrainChannel(false);
167 copy.map = (double[,]) map.Clone();
168
169 return copy;
170 }
171
172 public string SaveToXmlString()
173 {
174 XmlWriterSettings settings = new XmlWriterSettings();
175 settings.Encoding = Encoding.UTF8;
176 using (StringWriter sw = new StringWriter())
177 {
178 using (XmlWriter writer = XmlWriter.Create(sw, settings))
179 {
180 WriteXml(writer);
181 }
182 string output = sw.ToString();
183 return output;
184 }
185 }
186
187 private void WriteXml(XmlWriter writer)
188 {
189 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
190 ToXml(writer);
191 writer.WriteEndElement();
192 }
193
194 public void LoadFromXmlString(string data)
195 {
196 StringReader sr = new StringReader(data);
197 XmlTextReader reader = new XmlTextReader(sr);
198 reader.Read();
199
200 ReadXml(reader);
201 reader.Close();
202 sr.Close();
203 }
204
205 private void ReadXml(XmlReader reader)
206 {
207 reader.ReadStartElement("TerrainMap");
208 FromXml(reader);
209 }
210
211 private void ToXml(XmlWriter xmlWriter)
212 {
213 float[] mapData = GetFloatsSerialised();
214 byte[] buffer = new byte[mapData.Length * 4];
215 for (int i = 0; i < mapData.Length; i++)
216 {
217 byte[] value = BitConverter.GetBytes(mapData[i]);
218 Array.Copy(value, 0, buffer, (i * 4), 4);
219 }
220 XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
221 serializer.Serialize(xmlWriter, buffer);
222 }
223
224 private void FromXml(XmlReader xmlReader)
225 {
226 XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
227 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
228 int index = 0;
229
230 for (int y = 0; y < Height; y++)
231 {
232 for (int x = 0; x < Width; x++)
233 {
234 float value;
235 value = BitConverter.ToSingle(dataArray, index);
236 index += 4;
237 this[x, y] = (double)value;
238 }
239 }
240 }
241 }
242}
diff --git a/OpenSim/Region/Framework/Scenes/TerrainUtil.cs b/OpenSim/Region/Framework/Scenes/TerrainUtil.cs
new file mode 100644
index 0000000..318a682
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/TerrainUtil.cs
@@ -0,0 +1,132 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenSim.Region.Framework.Interfaces;
30
31namespace OpenSim.Region.Framework.Scenes
32{
33 public static class TerrainUtil
34 {
35 public static double MetersToSphericalStrength(double size)
36 {
37 //return Math.Pow(2, size);
38 return (size + 1) * 1.35; // MCP: a more useful brush size range
39 }
40
41 public static double SphericalFactor(double x, double y, double rx, double ry, double size)
42 {
43 return size * size - ((x - rx) * (x - rx) + (y - ry) * (y - ry));
44 }
45
46 public static double GetBilinearInterpolate(double x, double y, ITerrainChannel map)
47 {
48 int w = map.Width;
49 int h = map.Height;
50
51 if (x > w - 2.0)
52 x = w - 2.0;
53 if (y > h - 2.0)
54 y = h - 2.0;
55 if (x < 0.0)
56 x = 0.0;
57 if (y < 0.0)
58 y = 0.0;
59
60 const int stepSize = 1;
61 double h00 = map[(int) x, (int) y];
62 double h10 = map[(int) x + stepSize, (int) y];
63 double h01 = map[(int) x, (int) y + stepSize];
64 double h11 = map[(int) x + stepSize, (int) y + stepSize];
65 double h1 = h00;
66 double h2 = h10;
67 double h3 = h01;
68 double h4 = h11;
69 double a00 = h1;
70 double a10 = h2 - h1;
71 double a01 = h3 - h1;
72 double a11 = h1 - h2 - h3 + h4;
73 double partialx = x - (int) x;
74 double partialz = y - (int) y;
75 double hi = a00 + (a10 * partialx) + (a01 * partialz) + (a11 * partialx * partialz);
76 return hi;
77 }
78
79 private static double Noise(double x, double y)
80 {
81 int n = (int) x + (int) (y * 749);
82 n = (n << 13) ^ n;
83 return (1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
84 }
85
86 private static double SmoothedNoise1(double x, double y)
87 {
88 double corners = (Noise(x - 1, y - 1) + Noise(x + 1, y - 1) + Noise(x - 1, y + 1) + Noise(x + 1, y + 1)) / 16;
89 double sides = (Noise(x - 1, y) + Noise(x + 1, y) + Noise(x, y - 1) + Noise(x, y + 1)) / 8;
90 double center = Noise(x, y) / 4;
91 return corners + sides + center;
92 }
93
94 private static double Interpolate(double x, double y, double z)
95 {
96 return (x * (1.0 - z)) + (y * z);
97 }
98
99 public static double InterpolatedNoise(double x, double y)
100 {
101 int integer_X = (int) (x);
102 double fractional_X = x - integer_X;
103
104 int integer_Y = (int) y;
105 double fractional_Y = y - integer_Y;
106
107 double v1 = SmoothedNoise1(integer_X, integer_Y);
108 double v2 = SmoothedNoise1(integer_X + 1, integer_Y);
109 double v3 = SmoothedNoise1(integer_X, integer_Y + 1);
110 double v4 = SmoothedNoise1(integer_X + 1, integer_Y + 1);
111
112 double i1 = Interpolate(v1, v2, fractional_X);
113 double i2 = Interpolate(v3, v4, fractional_X);
114
115 return Interpolate(i1, i2, fractional_Y);
116 }
117
118 public static double PerlinNoise2D(double x, double y, int octaves, double persistence)
119 {
120 double total = 0.0;
121
122 for (int i = 0; i < octaves; i++)
123 {
124 double frequency = Math.Pow(2, i);
125 double amplitude = Math.Pow(persistence, i);
126
127 total += InterpolatedNoise(x * frequency, y * frequency) * amplitude;
128 }
129 return total;
130 }
131 }
132}
diff --git a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs
new file mode 100644
index 0000000..2c6ccc8
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs
@@ -0,0 +1,176 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Threading;
30using System.Text;
31using System.Collections.Generic;
32using Nini.Config;
33using NUnit.Framework;
34using NUnit.Framework.SyntaxHelpers;
35using OpenMetaverse;
36using OpenSim.Framework;
37using OpenSim.Framework.Communications;
38using OpenSim.Region.Framework.Scenes;
39using OpenSim.Tests.Common.Setup;
40
41namespace OpenSim.Region.Framework.Scenes.Tests
42{
43 [TestFixture]
44 public class EntityManagerTests
45 {
46 static public Random random;
47 SceneObjectGroup found;
48 Scene scene = SceneSetupHelpers.SetupScene();
49
50 [Test]
51 public void T010_AddObjects()
52 {
53 random = new Random();
54 SceneObjectGroup found;
55 EntityManager entman = new EntityManager();
56 SceneObjectGroup sog = NewSOG();
57 UUID obj1 = sog.UUID;
58 uint li1 = sog.LocalId;
59 entman.Add(sog);
60 sog = NewSOG();
61 UUID obj2 = sog.UUID;
62 uint li2 = sog.LocalId;
63 entman.Add(sog);
64
65 found = (SceneObjectGroup)entman[obj1];
66 Assert.That(found.UUID ,Is.EqualTo(obj1) );
67 found = (SceneObjectGroup)entman[li1];
68 Assert.That(found.UUID ,Is.EqualTo(obj1) );
69 found = (SceneObjectGroup)entman[obj2];
70 Assert.That(found.UUID ,Is.EqualTo(obj2) );
71 found = (SceneObjectGroup)entman[li2];
72 Assert.That(found.UUID ,Is.EqualTo(obj2) );
73
74 entman.Remove(obj1);
75 entman.Remove(li2);
76
77 Assert.That(entman.ContainsKey(obj1), Is.False);
78 Assert.That(entman.ContainsKey(li1), Is.False);
79 Assert.That(entman.ContainsKey(obj2), Is.False);
80 Assert.That(entman.ContainsKey(li2), Is.False);
81 }
82
83 [Test]
84 public void T011_ThreadAddRemoveTest()
85 {
86 // This test adds and removes with mutiple threads, attempting to break the
87 // uuid and localid dictionary coherence.
88 EntityManager entman = new EntityManager();
89 SceneObjectGroup sog = NewSOG();
90 for (int j=0; j<20; j++)
91 {
92 List<Thread> trdlist = new List<Thread>();
93
94 for (int i=0; i<4; i++)
95 {
96 // Adds scene object
97 NewTestThreads test = new NewTestThreads(entman,sog);
98 Thread start = new Thread(new ThreadStart(test.TestAddSceneObject));
99 start.Start();
100 trdlist.Add(start);
101
102 // Removes it
103 test = new NewTestThreads(entman,sog);
104 start = new Thread(new ThreadStart(test.TestRemoveSceneObject));
105 start.Start();
106 trdlist.Add(start);
107 }
108 foreach (Thread thread in trdlist)
109 {
110 thread.Join();
111 }
112 if (entman.ContainsKey(sog.UUID) || entman.ContainsKey(sog.LocalId)) {
113 found = (SceneObjectGroup)entman[sog.UUID];
114 Assert.That(found.UUID,Is.EqualTo(sog.UUID));
115 found = (SceneObjectGroup)entman[sog.LocalId];
116 Assert.That(found.UUID,Is.EqualTo(sog.UUID));
117 }
118 }
119 }
120
121 private SceneObjectGroup NewSOG()
122 {
123 SceneObjectGroup sog = new SceneObjectGroup();
124 SceneObjectPart sop = new SceneObjectPart(UUID.Random(), PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero);
125 sop.Name = RandomName();
126 sop.Description = sop.Name;
127 sop.Text = RandomName();
128 sop.SitName = RandomName();
129 sop.TouchName = RandomName();
130 sop.ObjectFlags |= (uint)PrimFlags.Phantom;
131
132 sog.SetRootPart(sop);
133
134 scene.AddNewSceneObject(sog, false);
135
136 return sog;
137 }
138
139 private static string RandomName()
140 {
141 StringBuilder name = new StringBuilder();
142 int size = random.Next(40,80);
143 char ch ;
144 for (int i=0; i<size; i++)
145 {
146 ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))) ;
147 name.Append(ch);
148 }
149 return name.ToString();
150 }
151 }
152
153 public class NewTestThreads
154 {
155 private EntityManager entman;
156 private SceneObjectGroup sog;
157 private Random random;
158
159 public NewTestThreads(EntityManager entman, SceneObjectGroup sog)
160 {
161 this.entman = entman;
162 this.sog = sog;
163 this.random = new Random();
164 }
165 public void TestAddSceneObject()
166 {
167 Thread.Sleep(random.Next(0,50));
168 entman.Add(sog);
169 }
170 public void TestRemoveSceneObject()
171 {
172 Thread.Sleep(random.Next(0,50));
173 entman.Remove(sog.UUID);
174 }
175 }
176} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs
new file mode 100644
index 0000000..d063eae
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs
@@ -0,0 +1,139 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using NUnit.Framework;
30using NUnit.Framework.SyntaxHelpers;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Framework.Communications;
34using OpenSim.Framework.Communications.Cache;
35using OpenSim.Region.Communications.Local;
36using OpenSim.Region.Environment.Scenes;
37using OpenSim.Tests.Common.Mock;
38using OpenSim.Tests.Common.Setup;
39
40namespace OpenSim.Region.Environment.Scenes.Tests
41{
42 /// <summary>
43 /// Basic scene object tests (create, read and delete but not update).
44 /// </summary>
45 [TestFixture]
46 public class SceneObjectTests
47 {
48 /// <summary>
49 /// Test adding an object to a scene.
50 /// </summary>
51 [Test]
52 public void TestAddSceneObject()
53 {
54 Scene scene = SceneSetupHelpers.SetupScene();
55 SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene);
56 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
57
58 //System.Console.WriteLine("retrievedPart : {0}", retrievedPart);
59 // If the parts have the same UUID then we will consider them as one and the same
60 Assert.That(retrievedPart.UUID, Is.EqualTo(part.UUID));
61 }
62
63 /// <summary>
64 /// Test deleting an object from a scene.
65 /// </summary>
66 [Test]
67 public void TestDeleteSceneObject()
68 {
69 TestScene scene = SceneSetupHelpers.SetupScene();
70 SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene);
71 scene.DeleteSceneObject(part.ParentGroup, false);
72
73 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
74 Assert.That(retrievedPart, Is.Null);
75 }
76
77 /// <summary>
78 /// Test deleting an object asynchronously
79 /// </summary>
80 [Test]
81 public void TestDeleteSceneObjectAsync()
82 {
83 UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001");
84
85 TestScene scene = SceneSetupHelpers.SetupScene();
86
87 // Turn off the timer on the async sog deleter - we'll crank it by hand for this test.
88 AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter;
89 sogd.Enabled = false;
90
91 SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene);
92
93 IClientAPI client = SceneSetupHelpers.AddRootAgent(scene, agentId);
94 scene.DeRezObject(client, part.LocalId, UUID.Zero, DeRezAction.Delete, UUID.Zero);
95
96 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
97 Assert.That(retrievedPart, Is.Not.Null);
98
99 sogd.InventoryDeQueueAndDelete();
100 SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId);
101 Assert.That(retrievedPart2, Is.Null);
102 }
103
104 /// <summary>
105 /// Test deleting an object asynchronously to user inventory.
106 /// </summary>
107 [Test]
108 public void TestDeleteSceneObjectAsyncToUserInventory()
109 {
110 //log4net.Config.XmlConfigurator.Configure();
111
112 UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001");
113 string myObjectName = "Fred";
114
115 TestScene scene = SceneSetupHelpers.SetupScene();
116 SceneObjectPart part = SceneSetupHelpers.AddSceneObject(scene, myObjectName);
117
118 Assert.That(
119 scene.CommsManager.UserAdminService.AddUser(
120 "Bob", "Hoskins", "test", "test@test.com", 1000, 1000, agentId),
121 Is.EqualTo(agentId));
122
123 IClientAPI client = SceneSetupHelpers.AddRootAgent(scene, agentId);
124
125 CachedUserInfo userInfo = scene.CommsManager.UserProfileCacheService.GetUserDetails(agentId);
126 Assert.That(userInfo, Is.Not.Null);
127 Assert.That(userInfo.RootFolder, Is.Not.Null);
128
129 SceneSetupHelpers.DeleteSceneObjectAsync(scene, part, DeRezAction.Take, userInfo.RootFolder.ID, client);
130
131 // Check that we now have the taken part in our inventory
132 Assert.That(myObjectName, Is.EqualTo(userInfo.RootFolder.FindItemByPath(myObjectName).Name));
133
134 // Check that the taken part has actually disappeared
135 SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId);
136 Assert.That(retrievedPart, Is.Null);
137 }
138 }
139} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
new file mode 100644
index 0000000..30b0987
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
@@ -0,0 +1,249 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using NUnit.Framework;
30using NUnit.Framework.SyntaxHelpers;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Framework.Communications;
34using OpenSim.Framework.Communications.Cache;
35using OpenSim.Region.Communications.Local;
36using OpenSim.Region.Environment.Scenes;
37using OpenSim.Tests.Common.Mock;
38using OpenSim.Tests.Common.Setup;
39
40namespace OpenSim.Region.Environment.Scenes.Tests
41{
42 /// <summary>
43 /// Linking tests
44 /// </summary>
45 [TestFixture]
46 public class SceneObjectLinkingTests
47 {
48 [Test]
49 public void TestLinkDelink2SceneObjects()
50 {
51 bool debugtest = false;
52
53 Scene scene = SceneSetupHelpers.SetupScene();
54 SceneObjectPart part1 = SceneSetupHelpers.AddSceneObject(scene);
55 SceneObjectGroup grp1 = part1.ParentGroup;
56 SceneObjectPart part2 = SceneSetupHelpers.AddSceneObject(scene);
57 SceneObjectGroup grp2 = part2.ParentGroup;
58
59 grp1.AbsolutePosition = new Vector3(10, 10, 10);
60 grp2.AbsolutePosition = Vector3.Zero;
61
62 // <90,0,0>
63 grp1.Rotation = (Quaternion.CreateFromEulers(90 * Utils.DEG_TO_RAD, 0, 0));
64
65 // <180,0,0>
66 grp2.UpdateGroupRotation(Quaternion.CreateFromEulers(180 * Utils.DEG_TO_RAD, 0, 0));
67
68 // Required for linking
69 grp1.RootPart.UpdateFlag = 0;
70 grp2.RootPart.UpdateFlag = 0;
71
72 // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated.
73 grp1.LinkToGroup(grp2);
74
75 // FIXME: Can't do this test yet since group 2 still has its root part! We can't yet null this since
76 // it might cause SOG.ProcessBackup() to fail due to the race condition. This really needs to be fixed.
77 Assert.That(grp2.IsDeleted, "SOG 2 was not registered as deleted after link.");
78 Assert.That(grp2.Children.Count, Is.EqualTo(0), "Group 2 still contained children after delink.");
79 Assert.That(grp1.Children.Count == 2);
80
81 if (debugtest)
82 {
83 System.Console.WriteLine("parts: {0}", grp1.Children.Count);
84 System.Console.WriteLine("Group1: Pos:{0}, Rot:{1}", grp1.AbsolutePosition, grp1.Rotation);
85 System.Console.WriteLine("Group1: Prim1: OffsetPosition:{0}, OffsetRotation:{1}", part1.OffsetPosition, part1.RotationOffset);
86 System.Console.WriteLine("Group1: Prim2: OffsetPosition:{0}, OffsetRotation:{1}", part2.OffsetPosition, part2.RotationOffset);
87 }
88
89 // root part should have no offset position or rotation
90 Assert.That(part1.OffsetPosition == Vector3.Zero && part1.RotationOffset == Quaternion.Identity);
91
92 // offset position should be root part position - part2.absolute position.
93 Assert.That(part2.OffsetPosition == new Vector3(-10, -10, -10));
94
95 float roll = 0;
96 float pitch = 0;
97 float yaw = 0;
98
99 // There's a euler anomoly at 180, 0, 0 so expect 180 to turn into -180.
100 part1.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw);
101 Vector3 rotEuler1 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG);
102
103 if (debugtest)
104 System.Console.WriteLine(rotEuler1);
105
106 part2.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw);
107 Vector3 rotEuler2 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG);
108
109 if (debugtest)
110 System.Console.WriteLine(rotEuler2);
111
112 Assert.That(rotEuler2.ApproxEquals(new Vector3(-180, 0, 0), 0.001f) || rotEuler2.ApproxEquals(new Vector3(180, 0, 0), 0.001f));
113
114 // Delink part 2
115 grp1.DelinkFromGroup(part2.LocalId);
116
117 if (debugtest)
118 System.Console.WriteLine("Group2: Prim2: OffsetPosition:{0}, OffsetRotation:{1}", part2.AbsolutePosition, part2.RotationOffset);
119
120 Assert.That(grp1.Children.Count, Is.EqualTo(1), "Group 1 still contained part2 after delink.");
121 Assert.That(part2.AbsolutePosition == Vector3.Zero);
122 }
123
124 [Test]
125 public void TestLinkDelink2groups4SceneObjects()
126 {
127 bool debugtest = false;
128
129 Scene scene = SceneSetupHelpers.SetupScene();
130 SceneObjectPart part1 = SceneSetupHelpers.AddSceneObject(scene);
131 SceneObjectGroup grp1 = part1.ParentGroup;
132 SceneObjectPart part2 = SceneSetupHelpers.AddSceneObject(scene);
133 SceneObjectGroup grp2 = part2.ParentGroup;
134 SceneObjectPart part3 = SceneSetupHelpers.AddSceneObject(scene);
135 SceneObjectGroup grp3 = part3.ParentGroup;
136 SceneObjectPart part4 = SceneSetupHelpers.AddSceneObject(scene);
137 SceneObjectGroup grp4 = part4.ParentGroup;
138
139 grp1.AbsolutePosition = new Vector3(10, 10, 10);
140 grp2.AbsolutePosition = Vector3.Zero;
141 grp3.AbsolutePosition = new Vector3(20, 20, 20);
142 grp4.AbsolutePosition = new Vector3(40, 40, 40);
143
144 // <90,0,0>
145 grp1.Rotation = (Quaternion.CreateFromEulers(90 * Utils.DEG_TO_RAD, 0, 0));
146
147 // <180,0,0>
148 grp2.UpdateGroupRotation(Quaternion.CreateFromEulers(180 * Utils.DEG_TO_RAD, 0, 0));
149
150 // <270,0,0>
151 grp3.Rotation = (Quaternion.CreateFromEulers(270 * Utils.DEG_TO_RAD, 0, 0));
152
153 // <0,90,0>
154 grp4.UpdateGroupRotation(Quaternion.CreateFromEulers(0, 90 * Utils.DEG_TO_RAD, 0));
155
156 // Required for linking
157 grp1.RootPart.UpdateFlag = 0;
158 grp2.RootPart.UpdateFlag = 0;
159 grp3.RootPart.UpdateFlag = 0;
160 grp4.RootPart.UpdateFlag = 0;
161
162 // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated.
163 grp1.LinkToGroup(grp2);
164
165 // Link grp4 to grp3.
166 grp3.LinkToGroup(grp4);
167
168 // At this point we should have 4 parts total in two groups.
169 Assert.That(grp1.Children.Count == 2);
170 Assert.That(grp2.IsDeleted, "Group 2 was not registered as deleted after link.");
171 Assert.That(grp2.Children.Count, Is.EqualTo(0), "Group 2 still contained parts after delink.");
172 Assert.That(grp3.Children.Count == 2);
173 Assert.That(grp4.IsDeleted, "Group 4 was not registered as deleted after link.");
174 Assert.That(grp4.Children.Count, Is.EqualTo(0), "Group 4 still contained parts after delink.");
175
176 if (debugtest)
177 {
178 System.Console.WriteLine("--------After Link-------");
179 System.Console.WriteLine("Group1: parts: {0}", grp1.Children.Count);
180 System.Console.WriteLine("Group1: Pos:{0}, Rot:{1}", grp1.AbsolutePosition, grp1.Rotation);
181 System.Console.WriteLine("Group1: Prim1: OffsetPosition:{0}, OffsetRotation:{1}", part1.OffsetPosition, part1.RotationOffset);
182 System.Console.WriteLine("Group1: Prim2: OffsetPosition:{0}, OffsetRotation:{1}", part2.OffsetPosition, part2.RotationOffset);
183
184 System.Console.WriteLine("Group3: parts: {0}", grp3.Children.Count);
185 System.Console.WriteLine("Group3: Pos:{0}, Rot:{1}", grp3.AbsolutePosition, grp3.Rotation);
186 System.Console.WriteLine("Group3: Prim1: OffsetPosition:{0}, OffsetRotation:{1}", part3.OffsetPosition, part3.RotationOffset);
187 System.Console.WriteLine("Group3: Prim2: OffsetPosition:{0}, OffsetRotation:{1}", part4.OffsetPosition, part4.RotationOffset);
188 }
189
190 // Required for linking
191 grp1.RootPart.UpdateFlag = 0;
192 grp3.RootPart.UpdateFlag = 0;
193
194 // root part should have no offset position or rotation
195 Assert.That(part1.OffsetPosition == Vector3.Zero && part1.RotationOffset == Quaternion.Identity);
196
197 // offset position should be root part position - part2.absolute position.
198 Assert.That(part2.OffsetPosition == new Vector3(-10, -10, -10));
199
200 float roll = 0;
201 float pitch = 0;
202 float yaw = 0;
203
204 // There's a euler anomoly at 180, 0, 0 so expect 180 to turn into -180.
205 part1.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw);
206 Vector3 rotEuler1 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG);
207
208 if (debugtest)
209 System.Console.WriteLine(rotEuler1);
210
211 part2.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw);
212 Vector3 rotEuler2 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG);
213
214 if (debugtest)
215 System.Console.WriteLine(rotEuler2);
216
217 Assert.That(rotEuler2.ApproxEquals(new Vector3(-180, 0, 0), 0.001f) || rotEuler2.ApproxEquals(new Vector3(180, 0, 0), 0.001f));
218
219 // Now we're linking the first group to the third group. This will make the first group child parts of the third one.
220 grp3.LinkToGroup(grp1);
221
222 // Delink parts 2 and 3
223 grp3.DelinkFromGroup(part2.LocalId);
224 grp3.DelinkFromGroup(part3.LocalId);
225
226 if (debugtest)
227 {
228 System.Console.WriteLine("--------After De-Link-------");
229 System.Console.WriteLine("Group1: parts: {0}", grp1.Children.Count);
230 System.Console.WriteLine("Group1: Pos:{0}, Rot:{1}", grp1.AbsolutePosition, grp1.Rotation);
231 System.Console.WriteLine("Group1: Prim1: OffsetPosition:{0}, OffsetRotation:{1}", part1.OffsetPosition, part1.RotationOffset);
232 System.Console.WriteLine("NoGroup: Prim2: AbsolutePosition:{0}, OffsetRotation:{1}", part2.AbsolutePosition, part2.RotationOffset);
233
234 System.Console.WriteLine("Group3: parts: {0}", grp3.Children.Count);
235 System.Console.WriteLine("Group3: Pos:{0}, Rot:{1}", grp3.AbsolutePosition, grp3.Rotation);
236 System.Console.WriteLine("Group3: Prim1: OffsetPosition:{0}, OffsetRotation:{1}", part3.OffsetPosition, part3.RotationOffset);
237 System.Console.WriteLine("Group3: Prim2: OffsetPosition:{0}, OffsetRotation:{1}", part4.OffsetPosition, part4.RotationOffset);
238 }
239
240 Assert.That(part2.AbsolutePosition == Vector3.Zero);
241 Assert.That(part4.OffsetPosition == new Vector3(20, 20, 20));
242 Quaternion compareQuaternion = new Quaternion(0, 0.7071068f, 0, 0.7071068f);
243 Assert.That((part4.RotationOffset.X - compareQuaternion.X < 0.00003)
244 && (part4.RotationOffset.Y - compareQuaternion.Y < 0.00003)
245 && (part4.RotationOffset.Z - compareQuaternion.Z < 0.00003)
246 && (part4.RotationOffset.W - compareQuaternion.W < 0.00003));
247 }
248 }
249}
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs
new file mode 100644
index 0000000..dc8df32
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs
@@ -0,0 +1,292 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using Nini.Config;
29using System;
30using System.Collections.Generic;
31using System.Text;
32using NUnit.Framework;
33using NUnit.Framework.SyntaxHelpers;
34using OpenMetaverse;
35using OpenSim.Framework;
36using OpenSim.Framework.Communications;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.Framework.Interfaces;
39using OpenSim.Region.Environment.Modules.Communications.Local;
40using OpenSim.Region.Environment.Modules.World.Serialiser;
41using OpenSim.Tests.Common.Mock;
42using OpenSim.Tests.Common.Setup;
43
44namespace OpenSim.Region.Framework.Scenes.Tests
45{
46 /// <summary>
47 /// Scene presence tests
48 /// </summary>
49 [TestFixture]
50 public class ScenePresenceTests
51 {
52 public Scene scene, scene2, scene3;
53 public UUID agent1, agent2, agent3;
54 public static Random random;
55 public ulong region1,region2,region3;
56 public CommunicationsManager cm;
57 public AgentCircuitData acd1;
58 public SceneObjectGroup sog1, sog2, sog3;
59 public TestClient testclient;
60
61 [TestFixtureSetUp]
62 public void Init()
63 {
64 cm = new TestCommunicationsManager();
65 scene = SceneSetupHelpers.SetupScene("Neighbour x", UUID.Random(), 1000, 1000, cm);
66 scene2 = SceneSetupHelpers.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000, cm);
67 scene3 = SceneSetupHelpers.SetupScene("Neighbour x-1", UUID.Random(), 999, 1000, cm);
68
69 agent1 = UUID.Random();
70 agent2 = UUID.Random();
71 agent3 = UUID.Random();
72 random = new Random();
73 sog1 = NewSOG(UUID.Random(), scene, agent1);
74 sog2 = NewSOG(UUID.Random(), scene, agent1);
75 sog3 = NewSOG(UUID.Random(), scene, agent1);
76
77 //ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize));
78 region1 = scene.RegionInfo.RegionHandle;
79 region2 = scene2.RegionInfo.RegionHandle;
80 region3 = scene3.RegionInfo.RegionHandle;
81 }
82
83 /// <summary>
84 /// Test adding a root agent to a scene. Doesn't yet actually complete crossing the agent into the scene.
85 /// </summary>
86 [Test]
87 public void T010_TestAddRootAgent()
88 {
89 string firstName = "testfirstname";
90
91 AgentCircuitData agent = new AgentCircuitData();
92 agent.AgentID = agent1;
93 agent.firstname = firstName;
94 agent.lastname = "testlastname";
95 agent.SessionID = UUID.Zero;
96 agent.SecureSessionID = UUID.Zero;
97 agent.circuitcode = 123;
98 agent.BaseFolder = UUID.Zero;
99 agent.InventoryFolder = UUID.Zero;
100 agent.startpos = Vector3.Zero;
101 agent.CapsPath = GetRandomCapsObjectPath();
102
103 scene.NewUserConnection(agent);
104 testclient = new TestClient(agent, scene);
105 scene.AddNewClient(testclient);
106
107 ScenePresence presence = scene.GetScenePresence(agent1);
108
109 Assert.That(presence, Is.Not.Null, "presence is null");
110 Assert.That(presence.Firstname, Is.EqualTo(firstName), "First name not same");
111 acd1 = agent;
112 }
113
114 /// <summary>
115 /// Test removing an uncrossed root agent from a scene.
116 /// </summary>
117 [Test]
118 public void T011_TestRemoveRootAgent()
119 {
120 scene.RemoveClient(agent1);
121
122 ScenePresence presence = scene.GetScenePresence(agent1);
123
124 Assert.That(presence, Is.Null, "presence is not null");
125 }
126
127 [Test]
128 public void T012_TestAddNeighbourRegion()
129 {
130 SceneSetupHelpers.AddRootAgent(scene,agent1);
131
132 ScenePresence presence = scene.GetScenePresence(agent1);
133
134 string cap = presence.ControllingClient.RequestClientInfo().CapsPath;
135
136 presence.AddNeighbourRegion(region2, cap);
137 presence.AddNeighbourRegion(region3, cap);
138
139 List<ulong> neighbours = presence.GetKnownRegionList();
140
141 Assert.That(neighbours.Count, Is.EqualTo(2));
142 }
143
144 [Test]
145 public void T013_TestRemoveNeighbourRegion()
146 {
147 ScenePresence presence = scene.GetScenePresence(agent1);
148 presence.RemoveNeighbourRegion(region3);
149
150 List<ulong> neighbours = presence.GetKnownRegionList();
151 Assert.That(neighbours.Count,Is.EqualTo(1));
152 /*
153 presence.MakeChildAgent;
154 presence.MakeRootAgent;
155 CompleteAvatarMovement
156 */
157 }
158
159 [Test]
160 public void T020_TestMakeRootAgent()
161 {
162 ScenePresence presence = scene.GetScenePresence(agent1);
163 Assert.That(presence.IsChildAgent, Is.False, "Starts out as a root agent");
164
165 presence.MakeChildAgent();
166 Assert.That(presence.IsChildAgent, Is.True, "Did not change to child agent after MakeChildAgent");
167
168 // Accepts 0 but rejects Constants.RegionSize
169 Vector3 pos = new Vector3(0,Constants.RegionSize-1,0);
170 presence.MakeRootAgent(pos,true);
171 Assert.That(presence.IsChildAgent, Is.False, "Did not go back to root agent");
172 Assert.That(presence.AbsolutePosition, Is.EqualTo(pos), "Position is not the same one entered");
173 }
174
175 [Test]
176 public void T021_TestCrossToNewRegion()
177 {
178 // Adding child agent to region 1001
179 scene2.NewUserConnection(acd1);
180 scene2.AddNewClient(testclient);
181
182 ScenePresence presence = scene.GetScenePresence(agent1);
183 ScenePresence presence2 = scene2.GetScenePresence(agent1);
184
185 // Adding neighbour region caps info to presence2
186 string cap = presence.ControllingClient.RequestClientInfo().CapsPath;
187 presence2.AddNeighbourRegion(region1, cap);
188
189 Assert.That(presence.IsChildAgent, Is.False, "Did not start root in origin region.");
190 Assert.That(presence2.IsChildAgent, Is.True, "Is not a child on destination region.");
191
192 // Cross to x+1
193 presence.AbsolutePosition = new Vector3(Constants.RegionSize+1,3,100);
194 scene.RegisterRegionWithGrid();
195 scene2.RegisterRegionWithGrid();
196 presence.Update();
197
198 Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected.");
199 Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent.");
200
201 // Cross Back
202 presence2.AbsolutePosition = new Vector3(-1, 3, 100);
203 presence2.Update();
204
205 Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected.");
206 Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again.");
207 }
208
209 [Test]
210 public void T030_TestAddAttachments()
211 {
212 ScenePresence presence = scene.GetScenePresence(agent1);
213
214 presence.AddAttachment(sog1);
215 presence.AddAttachment(sog2);
216 presence.AddAttachment(sog3);
217
218 Assert.That(presence.HasAttachments(), Is.True);
219 Assert.That(presence.ValidateAttachments(), Is.True);
220 }
221
222 [Test]
223 public void T031_RemoveAttachments()
224 {
225 ScenePresence presence = scene.GetScenePresence(agent1);
226 presence.RemoveAttachment(sog1);
227 presence.RemoveAttachment(sog2);
228 presence.RemoveAttachment(sog3);
229 Assert.That(presence.HasAttachments(), Is.False);
230 }
231
232 [Test]
233 public void T032_CrossAttachments()
234 {
235 ScenePresence presence = scene.GetScenePresence(agent1);
236 ScenePresence presence2 = scene2.GetScenePresence(agent1);
237 presence2.AddAttachment(sog1);
238 presence2.AddAttachment(sog2);
239
240 IRegionModule serialiser = new SerialiserModule();
241 SceneSetupHelpers.SetupSceneModules(scene, new IniConfigSource(), serialiser);
242 SceneSetupHelpers.SetupSceneModules(scene2, new IniConfigSource(), serialiser);
243
244 Assert.That(presence.HasAttachments(), Is.False, "Presence has attachments before cross");
245
246 Assert.That(presence2.CrossAttachmentsIntoNewRegion(region1, true), Is.True, "Cross was not successful");
247 Assert.That(presence2.HasAttachments(), Is.False, "Presence2 objects were not deleted");
248 Assert.That(presence.HasAttachments(), Is.True, "Presence has not received new objects");
249 }
250
251 public static string GetRandomCapsObjectPath()
252 {
253 UUID caps = UUID.Random();
254 string capsPath = caps.ToString();
255 capsPath = capsPath.Remove(capsPath.Length - 4, 4);
256 return capsPath;
257 }
258
259 private SceneObjectGroup NewSOG(UUID uuid, Scene scene, UUID agent)
260 {
261 SceneObjectPart sop = new SceneObjectPart();
262 sop.Name = RandomName();
263 sop.Description = RandomName();
264 sop.Text = RandomName();
265 sop.SitName = RandomName();
266 sop.TouchName = RandomName();
267 sop.UUID = uuid;
268 sop.Shape = PrimitiveBaseShape.Default;
269 sop.Shape.State = 1;
270 sop.OwnerID = agent;
271
272 SceneObjectGroup sog = new SceneObjectGroup();
273 sog.SetScene(scene);
274 sog.SetRootPart(sop);
275
276 return sog;
277 }
278
279 private static string RandomName()
280 {
281 StringBuilder name = new StringBuilder();
282 int size = random.Next(5,12);
283 char ch ;
284 for (int i=0; i<size; i++)
285 {
286 ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))) ;
287 name.Append(ch);
288 }
289 return name.ToString();
290 }
291 }
292}
diff --git a/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs
new file mode 100644
index 0000000..a78faa6
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Tests/StandaloneTeleportTests.cs
@@ -0,0 +1,105 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using Nini.Config;
29using NUnit.Framework;
30using NUnit.Framework.SyntaxHelpers;
31using OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Framework.Communications;
34using OpenSim.Region.Environment;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Environment.Modules.Communications.REST;
37using OpenSim.Tests.Common.Mock;
38using OpenSim.Tests.Common.Setup;
39
40namespace OpenSim.Region.Framework.Scenes.Tests
41{
42 /// <summary>
43 /// Teleport tests in a standalone OpenSim
44 /// </summary>
45 [TestFixture]
46 public class StandaloneTeleportTests
47 {
48 /// <summary>
49 /// Test a teleport between two regions that are not neighbours and do not share any neighbours in common.
50 /// </summary>
51 /// Does not yet do what is says on the tin.
52 [Test]
53 public void TestSimpleNotNeighboursTeleport()
54 {
55 //log4net.Config.XmlConfigurator.Configure();
56
57 UUID sceneAId = UUID.Parse("00000000-0000-0000-0000-000000000100");
58 UUID sceneBId = UUID.Parse("00000000-0000-0000-0000-000000000200");
59 CommunicationsManager cm = new TestCommunicationsManager();
60
61 // shared module
62 IRegionModule interregionComms = new RESTInterregionComms();
63
64 Scene sceneA = SceneSetupHelpers.SetupScene("sceneA", sceneAId, 1000, 1000, cm);
65 SceneSetupHelpers.SetupSceneModules(sceneA, new IniConfigSource(), interregionComms);
66 sceneA.RegisterRegionWithGrid();
67
68 Scene sceneB = SceneSetupHelpers.SetupScene("sceneB", sceneBId, 1010, 1010, cm);
69 SceneSetupHelpers.SetupSceneModules(sceneB, new IniConfigSource(), interregionComms);
70 sceneB.RegisterRegionWithGrid();
71
72 UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000041");
73 TestClient client = SceneSetupHelpers.AddRootAgent(sceneA, agentId);
74
75 ICapabilitiesModule sceneACapsModule = sceneA.RequestModuleInterface<ICapabilitiesModule>();
76
77 Assert.That(
78 sceneACapsModule.GetCapsPath(agentId),
79 Is.EqualTo(client.CapsSeedUrl),
80 "Incorrect caps object path set up in sceneA");
81
82 // FIXME: This is a hack to get the test working - really the normal OpenSim mechanisms should be used.
83 client.TeleportTargetScene = sceneB;
84 client.Teleport(sceneB.RegionInfo.RegionHandle, new Vector3(100, 100, 100), new Vector3(40, 40, 40));
85
86 Assert.That(sceneB.GetScenePresence(agentId), Is.Not.Null, "Client does not have an agent in sceneB");
87 Assert.That(sceneA.GetScenePresence(agentId), Is.Null, "Client still had an agent in sceneA");
88
89 ICapabilitiesModule sceneBCapsModule = sceneB.RequestModuleInterface<ICapabilitiesModule>();
90
91 // Temporary assertion - caps url construction should at least be doable through a method.
92 Assert.That(
93 "http://" + sceneB.RegionInfo.ExternalHostName + ":" + sceneB.RegionInfo.HttpPort + "/CAPS/" + sceneBCapsModule.GetCapsPath(agentId) + "0000/",
94 Is.EqualTo(client.CapsSeedUrl),
95 "Incorrect caps object path set up in sceneB");
96
97 // This assertion will currently fail since we don't remove the caps paths when no longer needed
98 //Assert.That(sceneACapsModule.GetCapsPath(agentId), Is.Null, "sceneA still had a caps object path");
99
100 // TODO: Check that more of everything is as it should be
101
102 // TODO: test what happens if we try to teleport to a region that doesn't exist
103 }
104 }
105} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Types/BasicQuadTreeNode.cs b/OpenSim/Region/Framework/Scenes/Types/BasicQuadTreeNode.cs
new file mode 100644
index 0000000..9fbbb15
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Types/BasicQuadTreeNode.cs
@@ -0,0 +1,269 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenSim.Region.Framework.Scenes;
31
32namespace OpenSim.Region.Framework.Scenes.Types
33{
34 public class BasicQuadTreeNode
35 {
36 private List<SceneObjectGroup> m_objects = new List<SceneObjectGroup>();
37 private BasicQuadTreeNode[] m_childNodes = null;
38 private BasicQuadTreeNode m_parent = null;
39
40 private short m_leftX;
41 private short m_leftY;
42 private short m_width;
43 private short m_height;
44 //private int m_quadNumber;
45 private string m_quadID;
46
47 public BasicQuadTreeNode(BasicQuadTreeNode parent, string quadID, short leftX, short leftY, short width,
48 short height)
49 {
50 m_parent = parent;
51 m_quadID = quadID;
52 m_leftX = leftX;
53 m_leftY = leftY;
54 m_width = width;
55 m_height = height;
56 // Console.WriteLine("creating quadtree node " + m_quadID);
57 }
58
59 public void AddObject(SceneObjectGroup obj)
60 {
61 if (m_childNodes == null)
62 {
63 if (!m_objects.Contains(obj))
64 {
65 m_objects.Add(obj);
66 }
67 }
68 else
69 {
70 if (obj.AbsolutePosition.X < (m_leftX + (m_width/2)))
71 {
72 if (obj.AbsolutePosition.Y < (m_leftY + (m_height/2)))
73 {
74 m_childNodes[0].AddObject(obj);
75 }
76 else
77 {
78 m_childNodes[2].AddObject(obj);
79 }
80 }
81 else
82 {
83 if (obj.AbsolutePosition.Y < (m_leftY + (m_height/2)))
84 {
85 m_childNodes[1].AddObject(obj);
86 }
87 else
88 {
89 m_childNodes[3].AddObject(obj);
90 }
91 }
92 }
93 }
94
95 public void Subdivide()
96 {
97 if (m_childNodes == null)
98 {
99 m_childNodes = new BasicQuadTreeNode[4];
100 m_childNodes[0] =
101 new BasicQuadTreeNode(this, m_quadID + "1/", m_leftX, m_leftY, (short) (m_width/2),
102 (short) (m_height/2));
103 m_childNodes[1] =
104 new BasicQuadTreeNode(this, m_quadID + "2/", (short) (m_leftX + (m_width/2)), m_leftY,
105 (short) (m_width/2), (short) (m_height/2));
106 m_childNodes[2] =
107 new BasicQuadTreeNode(this, m_quadID + "3/", m_leftX, (short) (m_leftY + (m_height/2)),
108 (short) (m_width/2), (short) (m_height/2));
109 m_childNodes[3] =
110 new BasicQuadTreeNode(this, m_quadID + "4/", (short) (m_leftX + (m_width/2)),
111 (short) (m_height + (m_height/2)), (short) (m_width/2), (short) (m_height/2));
112 }
113 else
114 {
115 for (int i = 0; i < m_childNodes.Length; i++)
116 {
117 m_childNodes[i].Subdivide();
118 }
119 }
120 }
121
122 public List<SceneObjectGroup> GetObjectsFrom(float x, float y)
123 {
124 if (m_childNodes == null)
125 {
126 return new List<SceneObjectGroup>(m_objects);
127 }
128 else
129 {
130 if (x < m_leftX + (m_width/2))
131 {
132 if (y < m_leftY + (m_height/2))
133 {
134 return m_childNodes[0].GetObjectsFrom(x, y);
135 }
136 else
137 {
138 return m_childNodes[2].GetObjectsFrom(x, y);
139 }
140 }
141 else
142 {
143 if (y < m_leftY + (m_height/2))
144 {
145 return m_childNodes[1].GetObjectsFrom(x, y);
146 }
147 else
148 {
149 return m_childNodes[3].GetObjectsFrom(x, y);
150 }
151 }
152 }
153 }
154
155 public List<SceneObjectGroup> GetObjectsFrom(string nodeName)
156 {
157 if (nodeName == m_quadID)
158 {
159 return new List<SceneObjectGroup>(m_objects);
160 }
161 else if (m_childNodes != null)
162 {
163 for (int i = 0; i < 4; i++)
164 {
165 List<SceneObjectGroup> retVal;
166 retVal = m_childNodes[i].GetObjectsFrom(nodeName);
167 if (retVal != null)
168 {
169 return retVal;
170 }
171 }
172 }
173 return null;
174 }
175
176 public string GetNodeID(float x, float y)
177 {
178 if (m_childNodes == null)
179 {
180 return m_quadID;
181 }
182 else
183 {
184 if (x < m_leftX + (m_width/2))
185 {
186 if (y < m_leftY + (m_height/2))
187 {
188 return m_childNodes[0].GetNodeID(x, y);
189 }
190 else
191 {
192 return m_childNodes[2].GetNodeID(x, y);
193 }
194 }
195 else
196 {
197 if (y < m_leftY + (m_height/2))
198 {
199 return m_childNodes[1].GetNodeID(x, y);
200 }
201 else
202 {
203 return m_childNodes[3].GetNodeID(x, y);
204 }
205 }
206 }
207 }
208
209 public void Update()
210 {
211 if (m_childNodes != null)
212 {
213 for (int i = 0; i < 4; i++)
214 {
215 m_childNodes[i].Update();
216 }
217 }
218 else
219 {
220 List<SceneObjectGroup> outBounds = new List<SceneObjectGroup>();
221 foreach (SceneObjectGroup group in m_objects)
222 {
223 if (((group.AbsolutePosition.X > m_leftX) && (group.AbsolutePosition.X < (m_leftX + m_width))) &&
224 ((group.AbsolutePosition.Y > m_leftY) && (group.AbsolutePosition.Y < (m_leftY + m_height))))
225 {
226 //still in bounds
227 }
228 else
229 {
230 outBounds.Add(group);
231 }
232 }
233
234 foreach (SceneObjectGroup removee in outBounds)
235 {
236 m_objects.Remove(removee);
237 if (m_parent != null)
238 {
239 m_parent.PassUp(removee);
240 }
241 }
242 outBounds.Clear();
243 }
244 }
245
246 public void PassUp(SceneObjectGroup group)
247 {
248 if (((group.AbsolutePosition.X > m_leftX) && (group.AbsolutePosition.X < (m_leftX + m_width))) &&
249 ((group.AbsolutePosition.Y > m_leftY) && (group.AbsolutePosition.Y < (m_leftY + m_height))))
250 {
251 AddObject(group);
252 }
253 else
254 {
255 if (m_parent != null)
256 {
257 m_parent.PassUp(group);
258 }
259 }
260 }
261
262 public string[] GetNeighbours(string nodeName)
263 {
264 string[] retVal = new string[1];
265 retVal[0] = String.Empty;
266 return retVal;
267 }
268 }
269}
diff --git a/OpenSim/Region/Framework/Scenes/Types/UpdateQueue.cs b/OpenSim/Region/Framework/Scenes/Types/UpdateQueue.cs
new file mode 100644
index 0000000..452ada9
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Types/UpdateQueue.cs
@@ -0,0 +1,134 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Runtime.Serialization;
31using System.Security.Permissions;
32using OpenMetaverse;
33using OpenSim.Region.Framework.Scenes;
34
35namespace OpenSim.Region.Framework.Scenes.Types
36{
37 [Serializable]
38 public class UpdateQueue : ISerializable
39 {
40 private Queue<SceneObjectPart> m_queue;
41
42 private List<UUID> m_ids;
43
44 private object m_syncObject = new object();
45
46 public int Count
47 {
48 get { return m_queue.Count; }
49 }
50
51 public UpdateQueue()
52 {
53 m_queue = new Queue<SceneObjectPart>();
54 m_ids = new List<UUID>();
55 }
56
57 public void Clear()
58 {
59 lock (m_syncObject)
60 {
61 m_ids.Clear();
62 m_queue.Clear();
63 }
64 }
65
66 public void Enqueue(SceneObjectPart part)
67 {
68 lock (m_syncObject)
69 {
70 if (!m_ids.Contains(part.UUID))
71 {
72 m_ids.Add(part.UUID);
73 m_queue.Enqueue(part);
74 }
75 }
76 }
77
78 public SceneObjectPart Dequeue()
79 {
80 SceneObjectPart part = null;
81 lock (m_syncObject)
82 {
83 if (m_queue.Count > 0)
84 {
85 part = m_queue.Dequeue();
86 m_ids.Remove(part.UUID);
87 }
88 }
89
90 return part;
91 }
92
93 protected UpdateQueue(SerializationInfo info, StreamingContext context)
94 {
95 //System.Console.WriteLine("UpdateQueue Deserialize BGN");
96
97 if (info == null)
98 {
99 throw new ArgumentNullException("info");
100 }
101
102 m_queue = (Queue<SceneObjectPart>)info.GetValue("m_queue", typeof(Queue<SceneObjectPart>));
103 List<Guid> ids_work = (List<Guid>)info.GetValue("m_ids", typeof(List<Guid>));
104
105 foreach (Guid guid in ids_work)
106 {
107 m_ids.Add(new UUID(guid));
108 }
109
110 //System.Console.WriteLine("UpdateQueue Deserialize END");
111 }
112
113 [SecurityPermission(SecurityAction.LinkDemand,
114 Flags = SecurityPermissionFlag.SerializationFormatter)]
115 public virtual void GetObjectData(
116 SerializationInfo info, StreamingContext context)
117 {
118 if (info == null)
119 {
120 throw new ArgumentNullException("info");
121 }
122
123 List<Guid> ids_work = new List<Guid>();
124
125 foreach (UUID uuid in m_ids)
126 {
127 ids_work.Add(uuid.Guid);
128 }
129
130 info.AddValue("m_queue", m_queue);
131 info.AddValue("m_ids", ids_work);
132 }
133 }
134}
diff --git a/OpenSim/Region/Framework/Scenes/UndoState.cs b/OpenSim/Region/Framework/Scenes/UndoState.cs
new file mode 100644
index 0000000..3d48229
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/UndoState.cs
@@ -0,0 +1,116 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using OpenMetaverse;
29
30namespace OpenSim.Region.Framework.Scenes
31{
32 public class UndoState
33 {
34 public Vector3 Position = Vector3.Zero;
35 public Vector3 Scale = Vector3.Zero;
36 public Quaternion Rotation = Quaternion.Identity;
37
38 public UndoState(Vector3 pos, Quaternion rot, Vector3 scale)
39 {
40 Position = pos;
41 Rotation = rot;
42 Scale = scale;
43 }
44
45 public UndoState(SceneObjectPart part)
46 {
47 if (part != null)
48 {
49 if (part.ParentID == 0)
50 {
51 Position = part.AbsolutePosition;
52 Rotation = part.RotationOffset;
53
54 }
55 else
56 {
57 Position = part.GroupPosition;
58 Rotation = part.RotationOffset;
59 Scale = part.Shape.Scale;
60
61 }
62 }
63 }
64
65 public bool Compare(SceneObjectPart part)
66 {
67 if (part != null)
68 {
69 if (part.ParentID == 0)
70 {
71 if (Position == part.AbsolutePosition && Rotation == part.RotationOffset)
72 return true;
73 else
74 return false;
75 }
76 else
77 {
78 if (Position == part.GroupPosition && Rotation == part.RotationOffset && Scale == part.Shape.Scale)
79 return true;
80 else
81 return false;
82
83 }
84 }
85 return false;
86 }
87
88 public void PlaybackState(SceneObjectPart part)
89 {
90 if (part != null)
91 {
92 part.Undoing = true;
93
94 if (part.ParentID == 0)
95 {
96 part.ParentGroup.AbsolutePosition = Position;
97 part.UpdateRotation(Rotation);
98 part.ParentGroup.ScheduleGroupForTerseUpdate();
99 }
100 else
101 {
102 part.OffsetPosition = Position;
103 part.UpdateRotation(Rotation);
104 part.Resize(Scale);
105 part.ScheduleTerseUpdate();
106 }
107 part.Undoing = false;
108
109 }
110 }
111
112 public UndoState()
113 {
114 }
115 }
116}