diff options
Diffstat (limited to 'OpenSim/Region')
113 files changed, 9484 insertions, 3518 deletions
diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 7361f50..0ed85b8 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs | |||
@@ -504,9 +504,6 @@ namespace OpenSim | |||
504 | scene.SnmpService.LinkUp(scene); | 504 | scene.SnmpService.LinkUp(scene); |
505 | } | 505 | } |
506 | 506 | ||
507 | scene.Start(); | ||
508 | scene.StartScripts(); | ||
509 | |||
510 | return clientServers; | 507 | return clientServers; |
511 | } | 508 | } |
512 | 509 | ||
@@ -821,7 +818,7 @@ namespace OpenSim | |||
821 | 818 | ||
822 | if (foundClientServer) | 819 | if (foundClientServer) |
823 | { | 820 | { |
824 | m_clientServers[clientServerElement].NetworkStop(); | 821 | m_clientServers[clientServerElement].Stop(); |
825 | m_clientServers.RemoveAt(clientServerElement); | 822 | m_clientServers.RemoveAt(clientServerElement); |
826 | } | 823 | } |
827 | } | 824 | } |
@@ -835,6 +832,7 @@ namespace OpenSim | |||
835 | ShutdownClientServer(whichRegion); | 832 | ShutdownClientServer(whichRegion); |
836 | IScene scene; | 833 | IScene scene; |
837 | CreateRegion(whichRegion, true, out scene); | 834 | CreateRegion(whichRegion, true, out scene); |
835 | scene.Start(); | ||
838 | } | 836 | } |
839 | 837 | ||
840 | # region Setup methods | 838 | # region Setup methods |
diff --git a/OpenSim/Region/ClientStack/IClientNetworkServer.cs b/OpenSim/Region/ClientStack/IClientNetworkServer.cs index 54a441b..bb7e6d0 100644 --- a/OpenSim/Region/ClientStack/IClientNetworkServer.cs +++ b/OpenSim/Region/ClientStack/IClientNetworkServer.cs | |||
@@ -38,11 +38,22 @@ namespace OpenSim.Region.ClientStack | |||
38 | IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, | 38 | IPAddress _listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, |
39 | AgentCircuitManager authenticateClass); | 39 | AgentCircuitManager authenticateClass); |
40 | 40 | ||
41 | void NetworkStop(); | ||
42 | bool HandlesRegion(Location x); | 41 | bool HandlesRegion(Location x); |
43 | void AddScene(IScene x); | ||
44 | 42 | ||
43 | /// <summary> | ||
44 | /// Add the given scene to be handled by this IClientNetworkServer. | ||
45 | /// </summary> | ||
46 | /// <param name='scene'></param> | ||
47 | void AddScene(IScene scene); | ||
48 | |||
49 | /// <summary> | ||
50 | /// Start sending and receiving data. | ||
51 | /// </summary> | ||
45 | void Start(); | 52 | void Start(); |
53 | |||
54 | /// <summary> | ||
55 | /// Stop sending and receiving data. | ||
56 | /// </summary> | ||
46 | void Stop(); | 57 | void Stop(); |
47 | } | 58 | } |
48 | } | 59 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.cs new file mode 100644 index 0000000..9f2aed0 --- /dev/null +++ b/OpenSim/Region/ClientStack/Linden/Caps/AvatarPickerSearchModule.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 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
33 | using System.Reflection; | ||
34 | using System.IO; | ||
35 | using System.Web; | ||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using Mono.Addins; | ||
39 | using OpenMetaverse; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using OpenSim.Framework; | ||
42 | using OpenSim.Framework.Servers; | ||
43 | using OpenSim.Framework.Servers.HttpServer; | ||
44 | using OpenSim.Region.Framework.Interfaces; | ||
45 | using OpenSim.Region.Framework.Scenes; | ||
46 | using OpenSim.Services.Interfaces; | ||
47 | using Caps = OpenSim.Framework.Capabilities.Caps; | ||
48 | using OpenSim.Capabilities.Handlers; | ||
49 | |||
50 | namespace OpenSim.Region.ClientStack.Linden | ||
51 | { | ||
52 | |||
53 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AvatarPickerSearchModule")] | ||
54 | public class AvatarPickerSearchModule : INonSharedRegionModule | ||
55 | { | ||
56 | private static readonly ILog m_log = | ||
57 | LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
58 | |||
59 | private Scene m_scene; | ||
60 | private IPeople m_People; | ||
61 | private bool m_Enabled = false; | ||
62 | |||
63 | private string m_URL; | ||
64 | |||
65 | #region ISharedRegionModule Members | ||
66 | |||
67 | public void Initialise(IConfigSource source) | ||
68 | { | ||
69 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
70 | if (config == null) | ||
71 | return; | ||
72 | |||
73 | m_URL = config.GetString("Cap_AvatarPickerSearch", string.Empty); | ||
74 | // Cap doesn't exist | ||
75 | if (m_URL != string.Empty) | ||
76 | m_Enabled = true; | ||
77 | } | ||
78 | |||
79 | public void AddRegion(Scene s) | ||
80 | { | ||
81 | if (!m_Enabled) | ||
82 | return; | ||
83 | |||
84 | m_scene = s; | ||
85 | } | ||
86 | |||
87 | public void RemoveRegion(Scene s) | ||
88 | { | ||
89 | if (!m_Enabled) | ||
90 | return; | ||
91 | |||
92 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | ||
93 | m_scene = null; | ||
94 | } | ||
95 | |||
96 | public void RegionLoaded(Scene s) | ||
97 | { | ||
98 | if (!m_Enabled) | ||
99 | return; | ||
100 | |||
101 | m_People = m_scene.RequestModuleInterface<IPeople>(); | ||
102 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | ||
103 | } | ||
104 | |||
105 | public void PostInitialise() | ||
106 | { | ||
107 | } | ||
108 | |||
109 | public void Close() { } | ||
110 | |||
111 | public string Name { get { return "AvatarPickerSearchModule"; } } | ||
112 | |||
113 | public Type ReplaceableInterface | ||
114 | { | ||
115 | get { return null; } | ||
116 | } | ||
117 | |||
118 | #endregion | ||
119 | |||
120 | public void RegisterCaps(UUID agentID, Caps caps) | ||
121 | { | ||
122 | UUID capID = UUID.Random(); | ||
123 | |||
124 | if (m_URL == "localhost") | ||
125 | { | ||
126 | m_log.DebugFormat("[AVATAR PICKER SEARCH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); | ||
127 | caps.RegisterHandler( | ||
128 | "AvatarPickerSearch", | ||
129 | new AvatarPickerSearchHandler("/CAPS/" + capID + "/", m_People, "AvatarPickerSearch", "Search for avatars by name")); | ||
130 | } | ||
131 | else | ||
132 | { | ||
133 | // m_log.DebugFormat("[AVATAR PICKER SEARCH]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); | ||
134 | caps.RegisterHandler("AvatarPickerSearch", m_URL); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | } | ||
139 | } | ||
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 707cc93..bba8ff1 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs | |||
@@ -71,6 +71,11 @@ namespace OpenSim.Region.ClientStack.Linden | |||
71 | private IInventoryService m_InventoryService; | 71 | private IInventoryService m_InventoryService; |
72 | private ILibraryService m_LibraryService; | 72 | private ILibraryService m_LibraryService; |
73 | 73 | ||
74 | private bool m_Enabled; | ||
75 | |||
76 | private string m_fetchInventoryDescendents2Url; | ||
77 | private string m_webFetchInventoryDescendentsUrl; | ||
78 | |||
74 | private static WebFetchInvDescHandler m_webFetchHandler; | 79 | private static WebFetchInvDescHandler m_webFetchHandler; |
75 | 80 | ||
76 | private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); | 81 | private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); |
@@ -83,22 +88,46 @@ namespace OpenSim.Region.ClientStack.Linden | |||
83 | 88 | ||
84 | public void Initialise(IConfigSource source) | 89 | public void Initialise(IConfigSource source) |
85 | { | 90 | { |
91 | IConfig config = source.Configs["ClientStack.LindenCaps"]; | ||
92 | if (config == null) | ||
93 | return; | ||
94 | |||
95 | m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty); | ||
96 | m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty); | ||
97 | |||
98 | if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty) | ||
99 | { | ||
100 | m_Enabled = true; | ||
101 | } | ||
86 | } | 102 | } |
87 | 103 | ||
88 | public void AddRegion(Scene s) | 104 | public void AddRegion(Scene s) |
89 | { | 105 | { |
106 | if (!m_Enabled) | ||
107 | return; | ||
108 | |||
90 | m_scene = s; | 109 | m_scene = s; |
91 | } | 110 | } |
92 | 111 | ||
93 | public void RemoveRegion(Scene s) | 112 | public void RemoveRegion(Scene s) |
94 | { | 113 | { |
114 | if (!m_Enabled) | ||
115 | return; | ||
116 | |||
95 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | 117 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; |
96 | m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; | 118 | m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; |
119 | |||
120 | foreach (Thread t in m_workerThreads) | ||
121 | Watchdog.AbortThread(t.ManagedThreadId); | ||
122 | |||
97 | m_scene = null; | 123 | m_scene = null; |
98 | } | 124 | } |
99 | 125 | ||
100 | public void RegionLoaded(Scene s) | 126 | public void RegionLoaded(Scene s) |
101 | { | 127 | { |
128 | if (!m_Enabled) | ||
129 | return; | ||
130 | |||
102 | m_InventoryService = m_scene.InventoryService; | 131 | m_InventoryService = m_scene.InventoryService; |
103 | m_LibraryService = m_scene.LibraryService; | 132 | m_LibraryService = m_scene.LibraryService; |
104 | 133 | ||
@@ -140,12 +169,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
140 | 169 | ||
141 | #endregion | 170 | #endregion |
142 | 171 | ||
143 | ~WebFetchInvDescModule() | ||
144 | { | ||
145 | foreach (Thread t in m_workerThreads) | ||
146 | Watchdog.AbortThread(t.ManagedThreadId); | ||
147 | } | ||
148 | |||
149 | private class PollServiceInventoryEventArgs : PollServiceEventArgs | 172 | private class PollServiceInventoryEventArgs : PollServiceEventArgs |
150 | { | 173 | { |
151 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 174 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -284,6 +307,9 @@ namespace OpenSim.Region.ClientStack.Linden | |||
284 | 307 | ||
285 | private void RegisterCaps(UUID agentID, Caps caps) | 308 | private void RegisterCaps(UUID agentID, Caps caps) |
286 | { | 309 | { |
310 | if (m_fetchInventoryDescendents2Url == "") | ||
311 | return; | ||
312 | |||
287 | string capUrl = "/CAPS/" + UUID.Random() + "/"; | 313 | string capUrl = "/CAPS/" + UUID.Random() + "/"; |
288 | 314 | ||
289 | // Register this as a poll service | 315 | // Register this as a poll service |
@@ -302,6 +328,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
302 | port = MainServer.Instance.SSLPort; | 328 | port = MainServer.Instance.SSLPort; |
303 | protocol = "https"; | 329 | protocol = "https"; |
304 | } | 330 | } |
331 | |||
305 | caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); | 332 | caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); |
306 | 333 | ||
307 | m_capsDict[agentID] = capUrl; | 334 | m_capsDict[agentID] = capUrl; |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs index 3995620..dfc4419 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/J2KImage.cs | |||
@@ -429,7 +429,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
429 | if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) | 429 | if (!assetServerURL.EndsWith("/") && !assetServerURL.EndsWith("=")) |
430 | assetServerURL = assetServerURL + "/"; | 430 | assetServerURL = assetServerURL + "/"; |
431 | 431 | ||
432 | m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); | 432 | // m_log.DebugFormat("[J2KIMAGE]: texture {0} not found in local asset storage. Trying user's storage.", assetServerURL + id); |
433 | AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived); | 433 | AssetService.Get(assetServerURL + id, InventoryAccessModule, AssetReceived); |
434 | return; | 434 | return; |
435 | } | 435 | } |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index eebb8ae..45c901e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs | |||
@@ -84,6 +84,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
84 | public event ModifyTerrain OnModifyTerrain; | 84 | public event ModifyTerrain OnModifyTerrain; |
85 | public event Action<IClientAPI> OnRegionHandShakeReply; | 85 | public event Action<IClientAPI> OnRegionHandShakeReply; |
86 | public event GenericCall1 OnRequestWearables; | 86 | public event GenericCall1 OnRequestWearables; |
87 | public event CachedTextureRequest OnCachedTextureRequest; | ||
87 | public event SetAppearance OnSetAppearance; | 88 | public event SetAppearance OnSetAppearance; |
88 | public event AvatarNowWearing OnAvatarNowWearing; | 89 | public event AvatarNowWearing OnAvatarNowWearing; |
89 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; | 90 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; |
@@ -820,12 +821,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
820 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); | 821 | handshake.RegionInfo3.ProductName = Util.StringToBytes256(regionInfo.RegionType); |
821 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; | 822 | handshake.RegionInfo3.ProductSKU = Utils.EmptyBytes; |
822 | 823 | ||
823 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[0]; | 824 | handshake.RegionInfo4 = new RegionHandshakePacket.RegionInfo4Block[1]; |
824 | // OutPacket(handshake, ThrottleOutPacketType.Task); | 825 | handshake.RegionInfo4[0] = new RegionHandshakePacket.RegionInfo4Block(); |
825 | // use same as MoveAgentIntoRegion (both should be task ) | 826 | handshake.RegionInfo4[0].RegionFlagsExtended = args.regionFlags; |
827 | handshake.RegionInfo4[0].RegionProtocols = 0; // 1 here would indicate that SSB is supported | ||
828 | |||
826 | OutPacket(handshake, ThrottleOutPacketType.Unknown); | 829 | OutPacket(handshake, ThrottleOutPacketType.Unknown); |
827 | } | 830 | } |
828 | 831 | ||
832 | |||
829 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) | 833 | public void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look) |
830 | { | 834 | { |
831 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); | 835 | AgentMovementCompletePacket mov = (AgentMovementCompletePacket)PacketPool.Instance.GetPacket(PacketType.AgentMovementComplete); |
@@ -1580,7 +1584,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1580 | OutPacket(pc, ThrottleOutPacketType.Unknown); | 1584 | OutPacket(pc, ThrottleOutPacketType.Unknown); |
1581 | } | 1585 | } |
1582 | 1586 | ||
1583 | public void SendKillObject(ulong regionHandle, List<uint> localIDs) | 1587 | public void SendKillObject(List<uint> localIDs) |
1584 | { | 1588 | { |
1585 | // foreach (uint id in localIDs) | 1589 | // foreach (uint id in localIDs) |
1586 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); | 1590 | // m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle); |
@@ -4862,7 +4866,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4862 | 4866 | ||
4863 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) | 4867 | public void SendForceClientSelectObjects(List<uint> ObjectIDs) |
4864 | { | 4868 | { |
4865 | m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); | 4869 | // m_log.DebugFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); |
4866 | 4870 | ||
4867 | bool firstCall = true; | 4871 | bool firstCall = true; |
4868 | const int MAX_OBJECTS_PER_PACKET = 251; | 4872 | const int MAX_OBJECTS_PER_PACKET = 251; |
@@ -11717,8 +11721,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11717 | } | 11721 | } |
11718 | 11722 | ||
11719 | /// <summary> | 11723 | /// <summary> |
11720 | /// Send a response back to a client when it asks the asset server (via the region server) if it has | ||
11721 | /// its appearance texture cached. | ||
11722 | /// </summary> | 11724 | /// </summary> |
11723 | /// <remarks> | 11725 | /// <remarks> |
11724 | /// At the moment, we always reply that there is no cached texture. | 11726 | /// At the moment, we always reply that there is no cached texture. |
@@ -11726,6 +11728,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11726 | /// <param name="simclient"></param> | 11728 | /// <param name="simclient"></param> |
11727 | /// <param name="packet"></param> | 11729 | /// <param name="packet"></param> |
11728 | /// <returns></returns> | 11730 | /// <returns></returns> |
11731 | // TODO: Convert old handler to use new method | ||
11732 | /*protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | ||
11733 | { | ||
11734 | AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet; | ||
11735 | |||
11736 | if (cachedtex.AgentData.SessionID != SessionId) | ||
11737 | return false; | ||
11738 | |||
11739 | |||
11740 | List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>(); | ||
11741 | |||
11742 | for (int i = 0; i < cachedtex.WearableData.Length; i++) | ||
11743 | { | ||
11744 | CachedTextureRequestArg arg = new CachedTextureRequestArg(); | ||
11745 | arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex; | ||
11746 | arg.WearableHashID = cachedtex.WearableData[i].ID; | ||
11747 | |||
11748 | requestArgs.Add(arg); | ||
11749 | } | ||
11750 | |||
11751 | CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest; | ||
11752 | if (handlerCachedTextureRequest != null) | ||
11753 | { | ||
11754 | handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs); | ||
11755 | } | ||
11756 | |||
11757 | return true; | ||
11758 | }*/ | ||
11759 | |||
11729 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) | 11760 | protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet) |
11730 | { | 11761 | { |
11731 | //m_log.Debug("texture cached: " + packet.ToString()); | 11762 | //m_log.Debug("texture cached: " + packet.ToString()); |
@@ -11884,6 +11915,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11884 | return true; | 11915 | return true; |
11885 | } | 11916 | } |
11886 | 11917 | ||
11918 | /// <summary> | ||
11919 | /// Send a response back to a client when it asks the asset server (via the region server) if it has | ||
11920 | /// its appearance texture cached. | ||
11921 | /// </summary> | ||
11922 | /// <param name="avatar"></param> | ||
11923 | /// <param name="serial"></param> | ||
11924 | /// <param name="cachedTextures"></param> | ||
11925 | /// <returns></returns> | ||
11926 | public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures) | ||
11927 | { | ||
11928 | ScenePresence presence = avatar as ScenePresence; | ||
11929 | if (presence == null) | ||
11930 | return; | ||
11931 | |||
11932 | AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse); | ||
11933 | |||
11934 | // TODO: don't create new blocks if recycling an old packet | ||
11935 | cachedresp.AgentData.AgentID = m_agentId; | ||
11936 | cachedresp.AgentData.SessionID = m_sessionId; | ||
11937 | cachedresp.AgentData.SerialNum = serial; | ||
11938 | cachedresp.WearableData = new AgentCachedTextureResponsePacket.WearableDataBlock[cachedTextures.Count]; | ||
11939 | |||
11940 | for (int i = 0; i < cachedTextures.Count; i++) | ||
11941 | { | ||
11942 | cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock(); | ||
11943 | cachedresp.WearableData[i].TextureIndex = (byte)cachedTextures[i].BakedTextureIndex; | ||
11944 | cachedresp.WearableData[i].TextureID = cachedTextures[i].BakedTextureID; | ||
11945 | cachedresp.WearableData[i].HostName = new byte[0]; | ||
11946 | } | ||
11947 | |||
11948 | cachedresp.Header.Zerocoded = true; | ||
11949 | OutPacket(cachedresp, ThrottleOutPacketType.Task); | ||
11950 | } | ||
11951 | |||
11887 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) | 11952 | protected bool HandleMultipleObjUpdate(IClientAPI simClient, Packet packet) |
11888 | { | 11953 | { |
11889 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; | 11954 | MultipleObjectUpdatePacket multipleupdate = (MultipleObjectUpdatePacket)packet; |
@@ -11909,8 +11974,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11909 | if (part == null) | 11974 | if (part == null) |
11910 | { | 11975 | { |
11911 | // It's a ghost! tell the client to delete it from view. | 11976 | // It's a ghost! tell the client to delete it from view. |
11912 | simClient.SendKillObject(Scene.RegionInfo.RegionHandle, | 11977 | simClient.SendKillObject(new List<uint> { localId }); |
11913 | new List<uint> { localId }); | ||
11914 | } | 11978 | } |
11915 | else | 11979 | else |
11916 | { | 11980 | { |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 4154ef2..d008702 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -62,11 +62,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
62 | m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); | 62 | m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); |
63 | } | 63 | } |
64 | 64 | ||
65 | public void NetworkStop() | ||
66 | { | ||
67 | m_udpServer.Stop(); | ||
68 | } | ||
69 | |||
70 | public void AddScene(IScene scene) | 65 | public void AddScene(IScene scene) |
71 | { | 66 | { |
72 | m_udpServer.AddScene(scene); | 67 | m_udpServer.AddScene(scene); |
@@ -1421,7 +1416,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1421 | 1416 | ||
1422 | // We only want to send initial data to new clients, not ones which are being converted from child to root. | 1417 | // We only want to send initial data to new clients, not ones which are being converted from child to root. |
1423 | if (client != null) | 1418 | if (client != null) |
1424 | client.SceneAgent.SendInitialDataToMe(); | 1419 | { |
1420 | AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code); | ||
1421 | bool tp = (aCircuit.teleportFlags > 0); | ||
1422 | if (!tp) | ||
1423 | client.SceneAgent.SendInitialDataToMe(); | ||
1424 | } | ||
1425 | 1425 | ||
1426 | // Now we know we can handle more data | 1426 | // Now we know we can handle more data |
1427 | Thread.Sleep(200); | 1427 | Thread.Sleep(200); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index 7d9f581..a0e0078 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs | |||
@@ -75,6 +75,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests | |||
75 | [SetUp] | 75 | [SetUp] |
76 | public void SetUp() | 76 | public void SetUp() |
77 | { | 77 | { |
78 | base.SetUp(); | ||
79 | |||
78 | UUID userId = TestHelpers.ParseTail(0x3); | 80 | UUID userId = TestHelpers.ParseTail(0x3); |
79 | 81 | ||
80 | J2KDecoderModule j2kdm = new J2KDecoderModule(); | 82 | J2KDecoderModule j2kdm = new J2KDecoderModule(); |
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index f2f789b..a60b314 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs | |||
@@ -841,7 +841,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments | |||
841 | m_scene.ForEachClient( | 841 | m_scene.ForEachClient( |
842 | client => | 842 | client => |
843 | { if (client.AgentId != so.AttachedAvatar) | 843 | { if (client.AgentId != so.AttachedAvatar) |
844 | client.SendKillObject(m_scene.RegionInfo.RegionHandle, new List<uint>() { so.LocalId }); | 844 | client.SendKillObject(new List<uint>() { so.LocalId }); |
845 | }); | 845 | }); |
846 | } | 846 | } |
847 | 847 | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 1a38619..8f9b17e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs | |||
@@ -833,11 +833,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests | |||
833 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); | 833 | UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); |
834 | 834 | ||
835 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); | 835 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); |
836 | TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); | 836 | TestClient tc = new TestClient(acd, sceneA); |
837 | List<TestClient> destinationTestClients = new List<TestClient>(); | 837 | List<TestClient> destinationTestClients = new List<TestClient>(); |
838 | EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); | 838 | EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); |
839 | 839 | ||
840 | ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); | 840 | ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); |
841 | beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); | 841 | beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); |
842 | 842 | ||
843 | InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); | 843 | InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); |
diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index bc79944..09cc998 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs | |||
@@ -55,6 +55,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
55 | 55 | ||
56 | private int m_savetime = 5; // seconds to wait before saving changed appearance | 56 | private int m_savetime = 5; // seconds to wait before saving changed appearance |
57 | private int m_sendtime = 2; // seconds to wait before sending changed appearance | 57 | private int m_sendtime = 2; // seconds to wait before sending changed appearance |
58 | private bool m_reusetextures = false; | ||
58 | 59 | ||
59 | private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates | 60 | private int m_checkTime = 500; // milliseconds to wait between checks for appearance updates |
60 | private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); | 61 | private System.Timers.Timer m_updateTimer = new System.Timers.Timer(); |
@@ -73,6 +74,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
73 | { | 74 | { |
74 | m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); | 75 | m_savetime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSave",Convert.ToString(m_savetime))); |
75 | m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); | 76 | m_sendtime = Convert.ToInt32(appearanceConfig.GetString("DelayBeforeAppearanceSend",Convert.ToString(m_sendtime))); |
77 | m_reusetextures = appearanceConfig.GetBoolean("ReuseTextures",m_reusetextures); | ||
78 | |||
76 | // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); | 79 | // m_log.InfoFormat("[AVFACTORY] configured for {0} save and {1} send",m_savetime,m_sendtime); |
77 | } | 80 | } |
78 | 81 | ||
@@ -131,6 +134,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
131 | client.OnRequestWearables += Client_OnRequestWearables; | 134 | client.OnRequestWearables += Client_OnRequestWearables; |
132 | client.OnSetAppearance += Client_OnSetAppearance; | 135 | client.OnSetAppearance += Client_OnSetAppearance; |
133 | client.OnAvatarNowWearing += Client_OnAvatarNowWearing; | 136 | client.OnAvatarNowWearing += Client_OnAvatarNowWearing; |
137 | client.OnCachedTextureRequest += Client_OnCachedTextureRequest; | ||
134 | } | 138 | } |
135 | 139 | ||
136 | #endregion | 140 | #endregion |
@@ -1068,6 +1072,61 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory | |||
1068 | QueueAppearanceSave(client.AgentId); | 1072 | QueueAppearanceSave(client.AgentId); |
1069 | } | 1073 | } |
1070 | } | 1074 | } |
1075 | |||
1076 | /// <summary> | ||
1077 | /// Respond to the cached textures request from the client | ||
1078 | /// </summary> | ||
1079 | /// <param name="client"></param> | ||
1080 | /// <param name="serial"></param> | ||
1081 | /// <param name="cachedTextureRequest"></param> | ||
1082 | private void Client_OnCachedTextureRequest(IClientAPI client, int serial, List<CachedTextureRequestArg> cachedTextureRequest) | ||
1083 | { | ||
1084 | // m_log.WarnFormat("[AVFACTORY]: Client_OnCachedTextureRequest called for {0} ({1})", client.Name, client.AgentId); | ||
1085 | ScenePresence sp = m_scene.GetScenePresence(client.AgentId); | ||
1086 | |||
1087 | List<CachedTextureResponseArg> cachedTextureResponse = new List<CachedTextureResponseArg>(); | ||
1088 | foreach (CachedTextureRequestArg request in cachedTextureRequest) | ||
1089 | { | ||
1090 | UUID texture = UUID.Zero; | ||
1091 | int index = request.BakedTextureIndex; | ||
1092 | |||
1093 | if (m_reusetextures) | ||
1094 | { | ||
1095 | // this is the most insanely dumb way to do this... however it seems to | ||
1096 | // actually work. if the appearance has been reset because wearables have | ||
1097 | // changed then the texture entries are zero'd out until the bakes are | ||
1098 | // uploaded. on login, if the textures exist in the cache (eg if you logged | ||
1099 | // into the simulator recently, then the appearance will pull those and send | ||
1100 | // them back in the packet and you won't have to rebake. if the textures aren't | ||
1101 | // in the cache then the intial makeroot() call in scenepresence will zero | ||
1102 | // them out. | ||
1103 | // | ||
1104 | // a better solution (though how much better is an open question) is to | ||
1105 | // store the hashes in the appearance and compare them. Thats's coming. | ||
1106 | |||
1107 | Primitive.TextureEntryFace face = sp.Appearance.Texture.FaceTextures[index]; | ||
1108 | if (face != null) | ||
1109 | texture = face.TextureID; | ||
1110 | |||
1111 | // m_log.WarnFormat("[AVFACTORY]: reuse texture {0} for index {1}",texture,index); | ||
1112 | } | ||
1113 | |||
1114 | CachedTextureResponseArg response = new CachedTextureResponseArg(); | ||
1115 | response.BakedTextureIndex = index; | ||
1116 | response.BakedTextureID = texture; | ||
1117 | response.HostName = null; | ||
1118 | |||
1119 | cachedTextureResponse.Add(response); | ||
1120 | } | ||
1121 | |||
1122 | // m_log.WarnFormat("[AVFACTORY]: serial is {0}",serial); | ||
1123 | // The serial number appears to be used to match requests and responses | ||
1124 | // in the texture transaction. We just send back the serial number | ||
1125 | // that was provided in the request. The viewer bumps this for us. | ||
1126 | client.SendCachedTextureResponse(sp, serial, cachedTextureResponse); | ||
1127 | } | ||
1128 | |||
1129 | |||
1071 | #endregion | 1130 | #endregion |
1072 | 1131 | ||
1073 | public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction) | 1132 | public void WriteBakedTexturesReport(IScenePresence sp, ReportOutputAction outputAction) |
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 8056030..41ea2a2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs | |||
@@ -371,7 +371,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends | |||
371 | foreach (string fid in outstanding) | 371 | foreach (string fid in outstanding) |
372 | { | 372 | { |
373 | UUID fromAgentID; | 373 | UUID fromAgentID; |
374 | string firstname = "Unknown", lastname = "User"; | 374 | string firstname = "Unknown", lastname = "UserFMSFOIN"; |
375 | if (!GetAgentInfo(client.Scene.RegionInfo.ScopeID, fid, out fromAgentID, out firstname, out lastname)) | 375 | if (!GetAgentInfo(client.Scene.RegionInfo.ScopeID, fid, out fromAgentID, out firstname, out lastname)) |
376 | { | 376 | { |
377 | m_log.DebugFormat("[FRIENDS MODULE]: skipping malformed friend {0}", fid); | 377 | m_log.DebugFormat("[FRIENDS MODULE]: skipping malformed friend {0}", fid); |
@@ -397,7 +397,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends | |||
397 | 397 | ||
398 | protected virtual bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) | 398 | protected virtual bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) |
399 | { | 399 | { |
400 | first = "Unknown"; last = "User"; | 400 | first = "Unknown"; last = "UserFMGAI"; |
401 | if (!UUID.TryParse(fid, out agentID)) | 401 | if (!UUID.TryParse(fid, out agentID)) |
402 | return false; | 402 | return false; |
403 | 403 | ||
@@ -685,7 +685,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends | |||
685 | // | 685 | // |
686 | 686 | ||
687 | // Try local | 687 | // Try local |
688 | if (LocalFriendshipTerminated(exfriendID)) | 688 | if (LocalFriendshipTerminated(client.AgentId, exfriendID)) |
689 | return; | 689 | return; |
690 | 690 | ||
691 | PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { exfriendID.ToString() }); | 691 | PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { exfriendID.ToString() }); |
@@ -827,13 +827,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends | |||
827 | return false; | 827 | return false; |
828 | } | 828 | } |
829 | 829 | ||
830 | public bool LocalFriendshipTerminated(UUID exfriendID) | 830 | public bool LocalFriendshipTerminated(UUID userID, UUID exfriendID) |
831 | { | 831 | { |
832 | IClientAPI friendClient = LocateClientObject(exfriendID); | 832 | IClientAPI friendClient = LocateClientObject(exfriendID); |
833 | if (friendClient != null) | 833 | if (friendClient != null) |
834 | { | 834 | { |
835 | // the friend in this sim as root agent | 835 | // the friend in this sim as root agent |
836 | friendClient.SendTerminateFriend(exfriendID); | 836 | friendClient.SendTerminateFriend(userID); |
837 | // update local cache | 837 | // update local cache |
838 | RecacheFriends(friendClient); | 838 | RecacheFriends(friendClient); |
839 | // we're done | 839 | // we're done |
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs index 637beef..08196f1 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsRequestHandler.cs | |||
@@ -193,7 +193,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends | |||
193 | if (!UUID.TryParse(request["ToID"].ToString(), out toID)) | 193 | if (!UUID.TryParse(request["ToID"].ToString(), out toID)) |
194 | return FailureResult(); | 194 | return FailureResult(); |
195 | 195 | ||
196 | if (m_FriendsModule.LocalFriendshipTerminated(toID)) | 196 | if (m_FriendsModule.LocalFriendshipTerminated(fromID, toID)) |
197 | return SuccessResult(); | 197 | return SuccessResult(); |
198 | 198 | ||
199 | return FailureResult(); | 199 | return FailureResult(); |
diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index bf5c0bb..b3e3aa2 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs | |||
@@ -293,7 +293,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends | |||
293 | 293 | ||
294 | protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) | 294 | protected override bool GetAgentInfo(UUID scopeID, string fid, out UUID agentID, out string first, out string last) |
295 | { | 295 | { |
296 | first = "Unknown"; last = "User"; | 296 | first = "Unknown"; last = "UserHGGAI"; |
297 | if (base.GetAgentInfo(scopeID, fid, out agentID, out first, out last)) | 297 | if (base.GetAgentInfo(scopeID, fid, out agentID, out first, out last)) |
298 | return true; | 298 | return true; |
299 | 299 | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs index fa8c3f3..5b12ecb 100644 --- a/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Gods/GodsModule.cs | |||
@@ -26,27 +26,25 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | ||
30 | using Nini.Config; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Framework.Scenes; | ||
34 | using OpenSim.Region.Framework.Interfaces; | ||
35 | using System; | ||
36 | using System.Reflection; | ||
37 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | ||
38 | using System.Collections.Specialized; | 31 | using System.Collections.Specialized; |
39 | using System.Reflection; | ||
40 | using System.IO; | 32 | using System.IO; |
33 | using System.Reflection; | ||
41 | using System.Web; | 34 | using System.Web; |
42 | using System.Xml; | 35 | using System.Xml; |
43 | using log4net; | 36 | using log4net; |
44 | using Mono.Addins; | 37 | using Mono.Addins; |
38 | using Nini.Config; | ||
39 | using OpenMetaverse; | ||
45 | using OpenMetaverse.Messages.Linden; | 40 | using OpenMetaverse.Messages.Linden; |
46 | using OpenMetaverse.StructuredData; | 41 | using OpenMetaverse.StructuredData; |
42 | using OpenSim.Framework; | ||
47 | using OpenSim.Framework.Capabilities; | 43 | using OpenSim.Framework.Capabilities; |
48 | using OpenSim.Framework.Servers; | 44 | using OpenSim.Framework.Servers; |
49 | using OpenSim.Framework.Servers.HttpServer; | 45 | using OpenSim.Framework.Servers.HttpServer; |
46 | using OpenSim.Region.Framework.Scenes; | ||
47 | using OpenSim.Region.Framework.Interfaces; | ||
50 | using Caps = OpenSim.Framework.Capabilities.Caps; | 48 | using Caps = OpenSim.Framework.Capabilities.Caps; |
51 | using OSDArray = OpenMetaverse.StructuredData.OSDArray; | 49 | using OSDArray = OpenMetaverse.StructuredData.OSDArray; |
52 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | 50 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs index f122d00..e285f21 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/InventoryTransferModule.cs | |||
@@ -47,10 +47,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
47 | 47 | ||
48 | /// <summary> | 48 | /// <summary> |
49 | private List<Scene> m_Scenelist = new List<Scene>(); | 49 | private List<Scene> m_Scenelist = new List<Scene>(); |
50 | // private Dictionary<UUID, Scene> m_AgentRegions = | ||
51 | // new Dictionary<UUID, Scene>(); | ||
52 | 50 | ||
53 | private IMessageTransferModule m_TransferModule = null; | 51 | private IMessageTransferModule m_TransferModule; |
54 | private bool m_Enabled = true; | 52 | private bool m_Enabled = true; |
55 | 53 | ||
56 | #region Region Module interface | 54 | #region Region Module interface |
@@ -81,9 +79,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
81 | // scene.RegisterModuleInterface<IInventoryTransferModule>(this); | 79 | // scene.RegisterModuleInterface<IInventoryTransferModule>(this); |
82 | 80 | ||
83 | scene.EventManager.OnNewClient += OnNewClient; | 81 | scene.EventManager.OnNewClient += OnNewClient; |
84 | // scene.EventManager.OnClientClosed += ClientLoggedOut; | ||
85 | scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; | 82 | scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; |
86 | // scene.EventManager.OnSetRootAgentScene += OnSetRootAgentScene; | ||
87 | } | 83 | } |
88 | 84 | ||
89 | public void RegionLoaded(Scene scene) | 85 | public void RegionLoaded(Scene scene) |
@@ -96,11 +92,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
96 | m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only"); | 92 | m_log.Error("[INVENTORY TRANSFER]: No Message transfer module found, transfers will be local only"); |
97 | m_Enabled = false; | 93 | m_Enabled = false; |
98 | 94 | ||
99 | m_Scenelist.Clear(); | 95 | // m_Scenelist.Clear(); |
100 | scene.EventManager.OnNewClient -= OnNewClient; | 96 | // scene.EventManager.OnNewClient -= OnNewClient; |
101 | // scene.EventManager.OnClientClosed -= ClientLoggedOut; | ||
102 | scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; | 97 | scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; |
103 | // scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene; | ||
104 | } | 98 | } |
105 | } | 99 | } |
106 | } | 100 | } |
@@ -108,9 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
108 | public void RemoveRegion(Scene scene) | 102 | public void RemoveRegion(Scene scene) |
109 | { | 103 | { |
110 | scene.EventManager.OnNewClient -= OnNewClient; | 104 | scene.EventManager.OnNewClient -= OnNewClient; |
111 | // scene.EventManager.OnClientClosed -= ClientLoggedOut; | ||
112 | scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; | 105 | scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage; |
113 | // scene.EventManager.OnSetRootAgentScene -= OnSetRootAgentScene; | ||
114 | m_Scenelist.Remove(scene); | 106 | m_Scenelist.Remove(scene); |
115 | } | 107 | } |
116 | 108 | ||
@@ -139,11 +131,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
139 | // Inventory giving is conducted via instant message | 131 | // Inventory giving is conducted via instant message |
140 | client.OnInstantMessage += OnInstantMessage; | 132 | client.OnInstantMessage += OnInstantMessage; |
141 | } | 133 | } |
142 | |||
143 | // protected void OnSetRootAgentScene(UUID id, Scene scene) | ||
144 | // { | ||
145 | // m_AgentRegions[id] = scene; | ||
146 | // } | ||
147 | 134 | ||
148 | private Scene FindClientScene(UUID agentId) | 135 | private Scene FindClientScene(UUID agentId) |
149 | { | 136 | { |
@@ -188,9 +175,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
188 | { | 175 | { |
189 | UUID folderID = new UUID(im.binaryBucket, 1); | 176 | UUID folderID = new UUID(im.binaryBucket, 1); |
190 | 177 | ||
191 | m_log.DebugFormat("[INVENTORY TRANSFER]: Inserting original folder {0} "+ | 178 | m_log.DebugFormat( |
192 | "into agent {1}'s inventory", | 179 | "[INVENTORY TRANSFER]: Inserting original folder {0} into agent {1}'s inventory", |
193 | folderID, new UUID(im.toAgentID)); | 180 | folderID, new UUID(im.toAgentID)); |
194 | 181 | ||
195 | InventoryFolderBase folderCopy | 182 | InventoryFolderBase folderCopy |
196 | = scene.GiveInventoryFolder(recipientID, client.AgentId, folderID, UUID.Zero); | 183 | = scene.GiveInventoryFolder(recipientID, client.AgentId, folderID, UUID.Zero); |
@@ -213,7 +200,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
213 | user.ControllingClient.SendBulkUpdateInventory(folderCopy); | 200 | user.ControllingClient.SendBulkUpdateInventory(folderCopy); |
214 | 201 | ||
215 | // HACK!! | 202 | // HACK!! |
216 | // Insert the ID of the copied item into the IM so that we know which item to move to trash if it | 203 | // Insert the ID of the copied folder into the IM so that we know which item to move to trash if it |
217 | // is rejected. | 204 | // is rejected. |
218 | // XXX: This is probably a misuse of the session ID slot. | 205 | // XXX: This is probably a misuse of the session ID slot. |
219 | im.imSessionID = copyID.Guid; | 206 | im.imSessionID = copyID.Guid; |
@@ -425,7 +412,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
425 | { | 412 | { |
426 | folder = new InventoryFolderBase(inventoryID, client.AgentId); | 413 | folder = new InventoryFolderBase(inventoryID, client.AgentId); |
427 | folder = invService.GetFolder(folder); | 414 | folder = invService.GetFolder(folder); |
428 | 415 | ||
429 | if (folder != null & trashFolder != null) | 416 | if (folder != null & trashFolder != null) |
430 | { | 417 | { |
431 | previousParentFolderID = folder.ParentID; | 418 | previousParentFolderID = folder.ParentID; |
@@ -477,70 +464,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer | |||
477 | } | 464 | } |
478 | } | 465 | } |
479 | 466 | ||
480 | // public bool NeedSceneCacheClear(UUID agentID, Scene scene) | ||
481 | // { | ||
482 | // if (!m_AgentRegions.ContainsKey(agentID)) | ||
483 | // { | ||
484 | // // Since we can get here two ways, we need to scan | ||
485 | // // the scenes here. This is somewhat more expensive | ||
486 | // // but helps avoid a nasty bug | ||
487 | // // | ||
488 | // | ||
489 | // foreach (Scene s in m_Scenelist) | ||
490 | // { | ||
491 | // ScenePresence presence; | ||
492 | // | ||
493 | // if (s.TryGetScenePresence(agentID, out presence)) | ||
494 | // { | ||
495 | // // If the agent is in this scene, then we | ||
496 | // // are being called twice in a single | ||
497 | // // teleport. This is wasteful of cycles | ||
498 | // // but harmless due to this 2nd level check | ||
499 | // // | ||
500 | // // If the agent is found in another scene | ||
501 | // // then the list wasn't current | ||
502 | // // | ||
503 | // // If the agent is totally unknown, then what | ||
504 | // // are we even doing here?? | ||
505 | // // | ||
506 | // if (s == scene) | ||
507 | // { | ||
508 | // //m_log.Debug("[INVTRANSFERMOD]: s == scene. Returning true in " + scene.RegionInfo.RegionName); | ||
509 | // return true; | ||
510 | // } | ||
511 | // else | ||
512 | // { | ||
513 | // //m_log.Debug("[INVTRANSFERMOD]: s != scene. Returning false in " + scene.RegionInfo.RegionName); | ||
514 | // return false; | ||
515 | // } | ||
516 | // } | ||
517 | // } | ||
518 | // //m_log.Debug("[INVTRANSFERMOD]: agent not in scene. Returning true in " + scene.RegionInfo.RegionName); | ||
519 | // return true; | ||
520 | // } | ||
521 | // | ||
522 | // // The agent is left in current Scene, so we must be | ||
523 | // // going to another instance | ||
524 | // // | ||
525 | // if (m_AgentRegions[agentID] == scene) | ||
526 | // { | ||
527 | // //m_log.Debug("[INVTRANSFERMOD]: m_AgentRegions[agentID] == scene. Returning true in " + scene.RegionInfo.RegionName); | ||
528 | // m_AgentRegions.Remove(agentID); | ||
529 | // return true; | ||
530 | // } | ||
531 | // | ||
532 | // // Another region has claimed the agent | ||
533 | // // | ||
534 | // //m_log.Debug("[INVTRANSFERMOD]: last resort. Returning false in " + scene.RegionInfo.RegionName); | ||
535 | // return false; | ||
536 | // } | ||
537 | // | ||
538 | // public void ClientLoggedOut(UUID agentID, Scene scene) | ||
539 | // { | ||
540 | // if (m_AgentRegions.ContainsKey(agentID)) | ||
541 | // m_AgentRegions.Remove(agentID); | ||
542 | // } | ||
543 | |||
544 | /// <summary> | 467 | /// <summary> |
545 | /// | 468 | /// |
546 | /// </summary> | 469 | /// </summary> |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs new file mode 100644 index 0000000..162a0c3 --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Transfer/Tests/InventoryTransferModuleTests.cs | |||
@@ -0,0 +1,449 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using log4net.Config; | ||
32 | using Nini.Config; | ||
33 | using NUnit.Framework; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.Assets; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.CoreModules.Avatar.Inventory.Transfer; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using OpenSim.Tests.Common; | ||
42 | using OpenSim.Tests.Common.Mock; | ||
43 | |||
44 | namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer.Tests | ||
45 | { | ||
46 | [TestFixture] | ||
47 | public class InventoryTransferModuleTests : OpenSimTestCase | ||
48 | { | ||
49 | protected TestScene m_scene; | ||
50 | |||
51 | [SetUp] | ||
52 | public override void SetUp() | ||
53 | { | ||
54 | base.SetUp(); | ||
55 | |||
56 | IConfigSource config = new IniConfigSource(); | ||
57 | config.AddConfig("Messaging"); | ||
58 | config.Configs["Messaging"].Set("InventoryTransferModule", "InventoryTransferModule"); | ||
59 | |||
60 | m_scene = new SceneHelpers().SetupScene(); | ||
61 | SceneHelpers.SetupSceneModules(m_scene, config, new InventoryTransferModule()); | ||
62 | } | ||
63 | |||
64 | [Test] | ||
65 | public void TestAcceptGivenItem() | ||
66 | { | ||
67 | // TestHelpers.EnableLogging(); | ||
68 | |||
69 | UUID initialSessionId = TestHelpers.ParseTail(0x10); | ||
70 | UUID itemId = TestHelpers.ParseTail(0x100); | ||
71 | UUID assetId = TestHelpers.ParseTail(0x200); | ||
72 | |||
73 | UserAccount ua1 | ||
74 | = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); | ||
75 | UserAccount ua2 | ||
76 | = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); | ||
77 | |||
78 | ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); | ||
79 | TestClient giverClient = (TestClient)giverSp.ControllingClient; | ||
80 | |||
81 | ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); | ||
82 | TestClient receiverClient = (TestClient)receiverSp.ControllingClient; | ||
83 | |||
84 | // Create the object to test give | ||
85 | InventoryItemBase originalItem | ||
86 | = UserInventoryHelpers.CreateInventoryItem( | ||
87 | m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object); | ||
88 | |||
89 | byte[] giveImBinaryBucket = new byte[17]; | ||
90 | byte[] itemIdBytes = itemId.GetBytes(); | ||
91 | Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); | ||
92 | |||
93 | GridInstantMessage giveIm | ||
94 | = new GridInstantMessage( | ||
95 | m_scene, | ||
96 | giverSp.UUID, | ||
97 | giverSp.Name, | ||
98 | receiverSp.UUID, | ||
99 | (byte)InstantMessageDialog.InventoryOffered, | ||
100 | false, | ||
101 | "inventory offered msg", | ||
102 | initialSessionId, | ||
103 | false, | ||
104 | Vector3.Zero, | ||
105 | giveImBinaryBucket, | ||
106 | true); | ||
107 | |||
108 | giverClient.HandleImprovedInstantMessage(giveIm); | ||
109 | |||
110 | // These details might not all be correct. | ||
111 | GridInstantMessage acceptIm | ||
112 | = new GridInstantMessage( | ||
113 | m_scene, | ||
114 | receiverSp.UUID, | ||
115 | receiverSp.Name, | ||
116 | giverSp.UUID, | ||
117 | (byte)InstantMessageDialog.InventoryAccepted, | ||
118 | false, | ||
119 | "inventory accepted msg", | ||
120 | initialSessionId, | ||
121 | false, | ||
122 | Vector3.Zero, | ||
123 | null, | ||
124 | true); | ||
125 | |||
126 | receiverClient.HandleImprovedInstantMessage(acceptIm); | ||
127 | |||
128 | // Test for item remaining in the giver's inventory (here we assume a copy item) | ||
129 | // TODO: Test no-copy items. | ||
130 | InventoryItemBase originalItemAfterGive | ||
131 | = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); | ||
132 | |||
133 | Assert.That(originalItemAfterGive, Is.Not.Null); | ||
134 | Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID)); | ||
135 | |||
136 | // Test for item successfully making it into the receiver's inventory | ||
137 | InventoryItemBase receivedItem | ||
138 | = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Objects/givenObj"); | ||
139 | |||
140 | Assert.That(receivedItem, Is.Not.Null); | ||
141 | Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID)); | ||
142 | |||
143 | // Test that on a delete, item still exists and is accessible for the giver. | ||
144 | m_scene.InventoryService.DeleteItems(receiverSp.UUID, new List<UUID>() { receivedItem.ID }); | ||
145 | |||
146 | InventoryItemBase originalItemAfterDelete | ||
147 | = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); | ||
148 | |||
149 | Assert.That(originalItemAfterDelete, Is.Not.Null); | ||
150 | |||
151 | // TODO: Test scenario where giver deletes their item first. | ||
152 | } | ||
153 | |||
154 | /// <summary> | ||
155 | /// Test user rejection of a given item. | ||
156 | /// </summary> | ||
157 | /// <remarks> | ||
158 | /// A rejected item still ends up in the user's trash folder. | ||
159 | /// </remarks> | ||
160 | [Test] | ||
161 | public void TestRejectGivenItem() | ||
162 | { | ||
163 | // TestHelpers.EnableLogging(); | ||
164 | |||
165 | UUID initialSessionId = TestHelpers.ParseTail(0x10); | ||
166 | UUID itemId = TestHelpers.ParseTail(0x100); | ||
167 | UUID assetId = TestHelpers.ParseTail(0x200); | ||
168 | |||
169 | UserAccount ua1 | ||
170 | = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); | ||
171 | UserAccount ua2 | ||
172 | = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); | ||
173 | |||
174 | ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); | ||
175 | TestClient giverClient = (TestClient)giverSp.ControllingClient; | ||
176 | |||
177 | ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); | ||
178 | TestClient receiverClient = (TestClient)receiverSp.ControllingClient; | ||
179 | |||
180 | // Create the object to test give | ||
181 | InventoryItemBase originalItem | ||
182 | = UserInventoryHelpers.CreateInventoryItem( | ||
183 | m_scene, "givenObj", itemId, assetId, giverSp.UUID, InventoryType.Object); | ||
184 | |||
185 | GridInstantMessage receivedIm = null; | ||
186 | receiverClient.OnReceivedInstantMessage += im => receivedIm = im; | ||
187 | |||
188 | byte[] giveImBinaryBucket = new byte[17]; | ||
189 | byte[] itemIdBytes = itemId.GetBytes(); | ||
190 | Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); | ||
191 | |||
192 | GridInstantMessage giveIm | ||
193 | = new GridInstantMessage( | ||
194 | m_scene, | ||
195 | giverSp.UUID, | ||
196 | giverSp.Name, | ||
197 | receiverSp.UUID, | ||
198 | (byte)InstantMessageDialog.InventoryOffered, | ||
199 | false, | ||
200 | "inventory offered msg", | ||
201 | initialSessionId, | ||
202 | false, | ||
203 | Vector3.Zero, | ||
204 | giveImBinaryBucket, | ||
205 | true); | ||
206 | |||
207 | giverClient.HandleImprovedInstantMessage(giveIm); | ||
208 | |||
209 | // These details might not all be correct. | ||
210 | // Session ID is now the created item ID (!) | ||
211 | GridInstantMessage rejectIm | ||
212 | = new GridInstantMessage( | ||
213 | m_scene, | ||
214 | receiverSp.UUID, | ||
215 | receiverSp.Name, | ||
216 | giverSp.UUID, | ||
217 | (byte)InstantMessageDialog.InventoryDeclined, | ||
218 | false, | ||
219 | "inventory declined msg", | ||
220 | new UUID(receivedIm.imSessionID), | ||
221 | false, | ||
222 | Vector3.Zero, | ||
223 | null, | ||
224 | true); | ||
225 | |||
226 | receiverClient.HandleImprovedInstantMessage(rejectIm); | ||
227 | |||
228 | // Test for item remaining in the giver's inventory (here we assume a copy item) | ||
229 | // TODO: Test no-copy items. | ||
230 | InventoryItemBase originalItemAfterGive | ||
231 | = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); | ||
232 | |||
233 | Assert.That(originalItemAfterGive, Is.Not.Null); | ||
234 | Assert.That(originalItemAfterGive.ID, Is.EqualTo(originalItem.ID)); | ||
235 | |||
236 | // Test for item successfully making it into the receiver's inventory | ||
237 | InventoryItemBase receivedItem | ||
238 | = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, receiverSp.UUID, "Trash/givenObj"); | ||
239 | |||
240 | InventoryFolderBase trashFolder | ||
241 | = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, AssetType.TrashFolder); | ||
242 | |||
243 | Assert.That(receivedItem, Is.Not.Null); | ||
244 | Assert.That(receivedItem.ID, Is.Not.EqualTo(originalItem.ID)); | ||
245 | Assert.That(receivedItem.Folder, Is.EqualTo(trashFolder.ID)); | ||
246 | |||
247 | // Test that on a delete, item still exists and is accessible for the giver. | ||
248 | m_scene.InventoryService.PurgeFolder(trashFolder); | ||
249 | |||
250 | InventoryItemBase originalItemAfterDelete | ||
251 | = UserInventoryHelpers.GetInventoryItem(m_scene.InventoryService, giverSp.UUID, "Objects/givenObj"); | ||
252 | |||
253 | Assert.That(originalItemAfterDelete, Is.Not.Null); | ||
254 | } | ||
255 | |||
256 | [Test] | ||
257 | public void TestAcceptGivenFolder() | ||
258 | { | ||
259 | TestHelpers.InMethod(); | ||
260 | // TestHelpers.EnableLogging(); | ||
261 | |||
262 | UUID initialSessionId = TestHelpers.ParseTail(0x10); | ||
263 | UUID folderId = TestHelpers.ParseTail(0x100); | ||
264 | |||
265 | UserAccount ua1 | ||
266 | = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); | ||
267 | UserAccount ua2 | ||
268 | = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); | ||
269 | |||
270 | ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); | ||
271 | TestClient giverClient = (TestClient)giverSp.ControllingClient; | ||
272 | |||
273 | ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); | ||
274 | TestClient receiverClient = (TestClient)receiverSp.ControllingClient; | ||
275 | |||
276 | InventoryFolderBase originalFolder | ||
277 | = UserInventoryHelpers.CreateInventoryFolder( | ||
278 | m_scene.InventoryService, giverSp.UUID, folderId, "f1", true); | ||
279 | |||
280 | byte[] giveImBinaryBucket = new byte[17]; | ||
281 | giveImBinaryBucket[0] = (byte)AssetType.Folder; | ||
282 | byte[] itemIdBytes = folderId.GetBytes(); | ||
283 | Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); | ||
284 | |||
285 | GridInstantMessage giveIm | ||
286 | = new GridInstantMessage( | ||
287 | m_scene, | ||
288 | giverSp.UUID, | ||
289 | giverSp.Name, | ||
290 | receiverSp.UUID, | ||
291 | (byte)InstantMessageDialog.InventoryOffered, | ||
292 | false, | ||
293 | "inventory offered msg", | ||
294 | initialSessionId, | ||
295 | false, | ||
296 | Vector3.Zero, | ||
297 | giveImBinaryBucket, | ||
298 | true); | ||
299 | |||
300 | giverClient.HandleImprovedInstantMessage(giveIm); | ||
301 | |||
302 | // These details might not all be correct. | ||
303 | GridInstantMessage acceptIm | ||
304 | = new GridInstantMessage( | ||
305 | m_scene, | ||
306 | receiverSp.UUID, | ||
307 | receiverSp.Name, | ||
308 | giverSp.UUID, | ||
309 | (byte)InstantMessageDialog.InventoryAccepted, | ||
310 | false, | ||
311 | "inventory accepted msg", | ||
312 | initialSessionId, | ||
313 | false, | ||
314 | Vector3.Zero, | ||
315 | null, | ||
316 | true); | ||
317 | |||
318 | receiverClient.HandleImprovedInstantMessage(acceptIm); | ||
319 | |||
320 | // Test for item remaining in the giver's inventory (here we assume a copy item) | ||
321 | // TODO: Test no-copy items. | ||
322 | InventoryFolderBase originalFolderAfterGive | ||
323 | = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); | ||
324 | |||
325 | Assert.That(originalFolderAfterGive, Is.Not.Null); | ||
326 | Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID)); | ||
327 | |||
328 | // Test for item successfully making it into the receiver's inventory | ||
329 | InventoryFolderBase receivedFolder | ||
330 | = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "f1"); | ||
331 | |||
332 | Assert.That(receivedFolder, Is.Not.Null); | ||
333 | Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID)); | ||
334 | |||
335 | // Test that on a delete, item still exists and is accessible for the giver. | ||
336 | m_scene.InventoryService.DeleteFolders(receiverSp.UUID, new List<UUID>() { receivedFolder.ID }); | ||
337 | |||
338 | InventoryFolderBase originalFolderAfterDelete | ||
339 | = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); | ||
340 | |||
341 | Assert.That(originalFolderAfterDelete, Is.Not.Null); | ||
342 | |||
343 | // TODO: Test scenario where giver deletes their item first. | ||
344 | } | ||
345 | |||
346 | /// <summary> | ||
347 | /// Test user rejection of a given item. | ||
348 | /// </summary> | ||
349 | /// <remarks> | ||
350 | /// A rejected item still ends up in the user's trash folder. | ||
351 | /// </remarks> | ||
352 | [Test] | ||
353 | public void TestRejectGivenFolder() | ||
354 | { | ||
355 | TestHelpers.InMethod(); | ||
356 | // TestHelpers.EnableLogging(); | ||
357 | |||
358 | UUID initialSessionId = TestHelpers.ParseTail(0x10); | ||
359 | UUID folderId = TestHelpers.ParseTail(0x100); | ||
360 | |||
361 | UserAccount ua1 | ||
362 | = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "One", TestHelpers.ParseTail(0x1), "pw"); | ||
363 | UserAccount ua2 | ||
364 | = UserAccountHelpers.CreateUserWithInventory(m_scene, "User", "Two", TestHelpers.ParseTail(0x2), "pw"); | ||
365 | |||
366 | ScenePresence giverSp = SceneHelpers.AddScenePresence(m_scene, ua1); | ||
367 | TestClient giverClient = (TestClient)giverSp.ControllingClient; | ||
368 | |||
369 | ScenePresence receiverSp = SceneHelpers.AddScenePresence(m_scene, ua2); | ||
370 | TestClient receiverClient = (TestClient)receiverSp.ControllingClient; | ||
371 | |||
372 | // Create the folder to test give | ||
373 | InventoryFolderBase originalFolder | ||
374 | = UserInventoryHelpers.CreateInventoryFolder( | ||
375 | m_scene.InventoryService, giverSp.UUID, folderId, "f1", true); | ||
376 | |||
377 | GridInstantMessage receivedIm = null; | ||
378 | receiverClient.OnReceivedInstantMessage += im => receivedIm = im; | ||
379 | |||
380 | byte[] giveImBinaryBucket = new byte[17]; | ||
381 | giveImBinaryBucket[0] = (byte)AssetType.Folder; | ||
382 | byte[] itemIdBytes = folderId.GetBytes(); | ||
383 | Array.Copy(itemIdBytes, 0, giveImBinaryBucket, 1, itemIdBytes.Length); | ||
384 | |||
385 | GridInstantMessage giveIm | ||
386 | = new GridInstantMessage( | ||
387 | m_scene, | ||
388 | giverSp.UUID, | ||
389 | giverSp.Name, | ||
390 | receiverSp.UUID, | ||
391 | (byte)InstantMessageDialog.InventoryOffered, | ||
392 | false, | ||
393 | "inventory offered msg", | ||
394 | initialSessionId, | ||
395 | false, | ||
396 | Vector3.Zero, | ||
397 | giveImBinaryBucket, | ||
398 | true); | ||
399 | |||
400 | giverClient.HandleImprovedInstantMessage(giveIm); | ||
401 | |||
402 | // These details might not all be correct. | ||
403 | // Session ID is now the created item ID (!) | ||
404 | GridInstantMessage rejectIm | ||
405 | = new GridInstantMessage( | ||
406 | m_scene, | ||
407 | receiverSp.UUID, | ||
408 | receiverSp.Name, | ||
409 | giverSp.UUID, | ||
410 | (byte)InstantMessageDialog.InventoryDeclined, | ||
411 | false, | ||
412 | "inventory declined msg", | ||
413 | new UUID(receivedIm.imSessionID), | ||
414 | false, | ||
415 | Vector3.Zero, | ||
416 | null, | ||
417 | true); | ||
418 | |||
419 | receiverClient.HandleImprovedInstantMessage(rejectIm); | ||
420 | |||
421 | // Test for item remaining in the giver's inventory (here we assume a copy item) | ||
422 | // TODO: Test no-copy items. | ||
423 | InventoryFolderBase originalFolderAfterGive | ||
424 | = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); | ||
425 | |||
426 | Assert.That(originalFolderAfterGive, Is.Not.Null); | ||
427 | Assert.That(originalFolderAfterGive.ID, Is.EqualTo(originalFolder.ID)); | ||
428 | |||
429 | // Test for folder successfully making it into the receiver's inventory | ||
430 | InventoryFolderBase receivedFolder | ||
431 | = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, receiverSp.UUID, "Trash/f1"); | ||
432 | |||
433 | InventoryFolderBase trashFolder | ||
434 | = m_scene.InventoryService.GetFolderForType(receiverSp.UUID, AssetType.TrashFolder); | ||
435 | |||
436 | Assert.That(receivedFolder, Is.Not.Null); | ||
437 | Assert.That(receivedFolder.ID, Is.Not.EqualTo(originalFolder.ID)); | ||
438 | Assert.That(receivedFolder.ParentID, Is.EqualTo(trashFolder.ID)); | ||
439 | |||
440 | // Test that on a delete, item still exists and is accessible for the giver. | ||
441 | m_scene.InventoryService.PurgeFolder(trashFolder); | ||
442 | |||
443 | InventoryFolderBase originalFolderAfterDelete | ||
444 | = UserInventoryHelpers.GetInventoryFolder(m_scene.InventoryService, giverSp.UUID, "f1"); | ||
445 | |||
446 | Assert.That(originalFolderAfterDelete, Is.Not.Null); | ||
447 | } | ||
448 | } | ||
449 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs index bf24030..2bb24ae 100644 --- a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs | |||
@@ -57,6 +57,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile | |||
57 | 57 | ||
58 | public void Initialise(IConfigSource config) | 58 | public void Initialise(IConfigSource config) |
59 | { | 59 | { |
60 | if(config.Configs["UserProfiles"] != null) | ||
61 | return; | ||
62 | |||
60 | m_log.DebugFormat("[PROFILE MODULE]: Basic Profile Module enabled"); | 63 | m_log.DebugFormat("[PROFILE MODULE]: Basic Profile Module enabled"); |
61 | m_Enabled = true; | 64 | m_Enabled = true; |
62 | } | 65 | } |
diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs new file mode 100644 index 0000000..161f160 --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs | |||
@@ -0,0 +1,1342 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Text; | ||
31 | using System.Collections; | ||
32 | using System.Collections.Generic; | ||
33 | using System.Globalization; | ||
34 | using System.Net; | ||
35 | using System.Net.Sockets; | ||
36 | using System.Reflection; | ||
37 | using System.Xml; | ||
38 | using OpenMetaverse; | ||
39 | using OpenMetaverse.StructuredData; | ||
40 | using log4net; | ||
41 | using Nini.Config; | ||
42 | using Nwc.XmlRpc; | ||
43 | using OpenSim.Framework; | ||
44 | using OpenSim.Region.Framework.Interfaces; | ||
45 | using OpenSim.Region.Framework.Scenes; | ||
46 | using OpenSim.Services.Interfaces; | ||
47 | using Mono.Addins; | ||
48 | using OpenSim.Services.Connectors.Hypergrid; | ||
49 | |||
50 | namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles | ||
51 | { | ||
52 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserProfilesModule")] | ||
53 | public class UserProfileModule : IProfileModule, INonSharedRegionModule | ||
54 | { | ||
55 | /// <summary> | ||
56 | /// Logging | ||
57 | /// </summary> | ||
58 | static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | |||
60 | // The pair of Dictionaries are used to handle the switching of classified ads | ||
61 | // by maintaining a cache of classified id to creator id mappings and an interest | ||
62 | // count. The entries are removed when the interest count reaches 0. | ||
63 | Dictionary<UUID, UUID> m_classifiedCache = new Dictionary<UUID, UUID>(); | ||
64 | Dictionary<UUID, int> m_classifiedInterest = new Dictionary<UUID, int>(); | ||
65 | |||
66 | public Scene Scene | ||
67 | { | ||
68 | get; private set; | ||
69 | } | ||
70 | |||
71 | /// <summary> | ||
72 | /// Gets or sets the ConfigSource. | ||
73 | /// </summary> | ||
74 | /// <value> | ||
75 | /// The configuration | ||
76 | /// </value> | ||
77 | public IConfigSource Config { | ||
78 | get; | ||
79 | set; | ||
80 | } | ||
81 | |||
82 | /// <summary> | ||
83 | /// Gets or sets the URI to the profile server. | ||
84 | /// </summary> | ||
85 | /// <value> | ||
86 | /// The profile server URI. | ||
87 | /// </value> | ||
88 | public string ProfileServerUri { | ||
89 | get; | ||
90 | set; | ||
91 | } | ||
92 | |||
93 | IProfileModule ProfileModule | ||
94 | { | ||
95 | get; set; | ||
96 | } | ||
97 | |||
98 | IUserManagement UserManagementModule | ||
99 | { | ||
100 | get; set; | ||
101 | } | ||
102 | |||
103 | /// <summary> | ||
104 | /// Gets or sets a value indicating whether this | ||
105 | /// <see cref="OpenSim.Region.Coremodules.UserProfiles.UserProfileModule"/> is enabled. | ||
106 | /// </summary> | ||
107 | /// <value> | ||
108 | /// <c>true</c> if enabled; otherwise, <c>false</c>. | ||
109 | /// </value> | ||
110 | public bool Enabled { | ||
111 | get; | ||
112 | set; | ||
113 | } | ||
114 | |||
115 | #region IRegionModuleBase implementation | ||
116 | /// <summary> | ||
117 | /// This is called to initialize the region module. For shared modules, this is called exactly once, after | ||
118 | /// creating the single (shared) instance. For non-shared modules, this is called once on each instance, after | ||
119 | /// the instace for the region has been created. | ||
120 | /// </summary> | ||
121 | /// <param name='source'> | ||
122 | /// Source. | ||
123 | /// </param> | ||
124 | public void Initialise(IConfigSource source) | ||
125 | { | ||
126 | Config = source; | ||
127 | ReplaceableInterface = typeof(IProfileModule); | ||
128 | |||
129 | IConfig profileConfig = Config.Configs["UserProfiles"]; | ||
130 | |||
131 | if (profileConfig == null) | ||
132 | { | ||
133 | m_log.Debug("[PROFILES]: UserProfiles disabled, no configuration"); | ||
134 | Enabled = false; | ||
135 | return; | ||
136 | } | ||
137 | |||
138 | // If we find ProfileURL then we configure for FULL support | ||
139 | // else we setup for BASIC support | ||
140 | ProfileServerUri = profileConfig.GetString("ProfileServiceURL", ""); | ||
141 | if (ProfileServerUri == "") | ||
142 | { | ||
143 | Enabled = false; | ||
144 | return; | ||
145 | } | ||
146 | |||
147 | m_log.Debug("[PROFILES]: Full Profiles Enabled"); | ||
148 | ReplaceableInterface = null; | ||
149 | Enabled = true; | ||
150 | } | ||
151 | |||
152 | /// <summary> | ||
153 | /// Adds the region. | ||
154 | /// </summary> | ||
155 | /// <param name='scene'> | ||
156 | /// Scene. | ||
157 | /// </param> | ||
158 | public void AddRegion(Scene scene) | ||
159 | { | ||
160 | if(!Enabled) | ||
161 | return; | ||
162 | |||
163 | Scene = scene; | ||
164 | Scene.RegisterModuleInterface<IProfileModule>(this); | ||
165 | Scene.EventManager.OnNewClient += OnNewClient; | ||
166 | Scene.EventManager.OnMakeRootAgent += HandleOnMakeRootAgent; | ||
167 | |||
168 | UserManagementModule = Scene.RequestModuleInterface<IUserManagement>(); | ||
169 | } | ||
170 | |||
171 | void HandleOnMakeRootAgent (ScenePresence obj) | ||
172 | { | ||
173 | if(obj.PresenceType == PresenceType.Npc) | ||
174 | return; | ||
175 | |||
176 | GetImageAssets(((IScenePresence)obj).UUID); | ||
177 | } | ||
178 | |||
179 | /// <summary> | ||
180 | /// Removes the region. | ||
181 | /// </summary> | ||
182 | /// <param name='scene'> | ||
183 | /// Scene. | ||
184 | /// </param> | ||
185 | public void RemoveRegion(Scene scene) | ||
186 | { | ||
187 | if(!Enabled) | ||
188 | return; | ||
189 | } | ||
190 | |||
191 | /// <summary> | ||
192 | /// This will be called once for every scene loaded. In a shared module this will be multiple times in one | ||
193 | /// instance, while a nonshared module instance will only be called once. This method is called after AddRegion | ||
194 | /// has been called in all modules for that scene, providing an opportunity to request another module's | ||
195 | /// interface, or hook an event from another module. | ||
196 | /// </summary> | ||
197 | /// <param name='scene'> | ||
198 | /// Scene. | ||
199 | /// </param> | ||
200 | public void RegionLoaded(Scene scene) | ||
201 | { | ||
202 | if(!Enabled) | ||
203 | return; | ||
204 | } | ||
205 | |||
206 | /// <summary> | ||
207 | /// If this returns non-null, it is the type of an interface that this module intends to register. This will | ||
208 | /// cause the loader to defer loading of this module until all other modules have been loaded. If no other | ||
209 | /// module has registered the interface by then, this module will be activated, else it will remain inactive, | ||
210 | /// letting the other module take over. This should return non-null ONLY in modules that are intended to be | ||
211 | /// easily replaceable, e.g. stub implementations that the developer expects to be replaced by third party | ||
212 | /// provided modules. | ||
213 | /// </summary> | ||
214 | /// <value> | ||
215 | /// The replaceable interface. | ||
216 | /// </value> | ||
217 | public Type ReplaceableInterface | ||
218 | { | ||
219 | get; private set; | ||
220 | } | ||
221 | |||
222 | /// <summary> | ||
223 | /// Called as the instance is closed. | ||
224 | /// </summary> | ||
225 | public void Close() | ||
226 | { | ||
227 | } | ||
228 | |||
229 | /// <value> | ||
230 | /// The name of the module | ||
231 | /// </value> | ||
232 | /// <summary> | ||
233 | /// Gets the module name. | ||
234 | /// </summary> | ||
235 | public string Name | ||
236 | { | ||
237 | get { return "UserProfileModule"; } | ||
238 | } | ||
239 | #endregion IRegionModuleBase implementation | ||
240 | |||
241 | #region Region Event Handlers | ||
242 | /// <summary> | ||
243 | /// Raises the new client event. | ||
244 | /// </summary> | ||
245 | /// <param name='client'> | ||
246 | /// Client. | ||
247 | /// </param> | ||
248 | void OnNewClient(IClientAPI client) | ||
249 | { | ||
250 | //Profile | ||
251 | client.OnRequestAvatarProperties += RequestAvatarProperties; | ||
252 | client.OnUpdateAvatarProperties += AvatarPropertiesUpdate; | ||
253 | client.OnAvatarInterestUpdate += AvatarInterestsUpdate; | ||
254 | |||
255 | // Classifieds | ||
256 | client.AddGenericPacketHandler("avatarclassifiedsrequest", ClassifiedsRequest); | ||
257 | client.OnClassifiedInfoUpdate += ClassifiedInfoUpdate; | ||
258 | client.OnClassifiedInfoRequest += ClassifiedInfoRequest; | ||
259 | client.OnClassifiedDelete += ClassifiedDelete; | ||
260 | |||
261 | // Picks | ||
262 | client.AddGenericPacketHandler("avatarpicksrequest", PicksRequest); | ||
263 | client.AddGenericPacketHandler("pickinforequest", PickInfoRequest); | ||
264 | client.OnPickInfoUpdate += PickInfoUpdate; | ||
265 | client.OnPickDelete += PickDelete; | ||
266 | |||
267 | // Notes | ||
268 | client.AddGenericPacketHandler("avatarnotesrequest", NotesRequest); | ||
269 | client.OnAvatarNotesUpdate += NotesUpdate; | ||
270 | } | ||
271 | #endregion Region Event Handlers | ||
272 | |||
273 | #region Classified | ||
274 | /// | ||
275 | /// <summary> | ||
276 | /// Handles the avatar classifieds request. | ||
277 | /// </summary> | ||
278 | /// <param name='sender'> | ||
279 | /// Sender. | ||
280 | /// </param> | ||
281 | /// <param name='method'> | ||
282 | /// Method. | ||
283 | /// </param> | ||
284 | /// <param name='args'> | ||
285 | /// Arguments. | ||
286 | /// </param> | ||
287 | public void ClassifiedsRequest(Object sender, string method, List<String> args) | ||
288 | { | ||
289 | if (!(sender is IClientAPI)) | ||
290 | return; | ||
291 | |||
292 | IClientAPI remoteClient = (IClientAPI)sender; | ||
293 | |||
294 | UUID targetID; | ||
295 | UUID.TryParse(args[0], out targetID); | ||
296 | |||
297 | // Can't handle NPC yet... | ||
298 | ScenePresence p = FindPresence(targetID); | ||
299 | |||
300 | if (null != p) | ||
301 | { | ||
302 | if (p.PresenceType == PresenceType.Npc) | ||
303 | return; | ||
304 | } | ||
305 | |||
306 | string serverURI = string.Empty; | ||
307 | bool foreign = GetUserProfileServerURI(targetID, out serverURI); | ||
308 | UUID creatorId = UUID.Zero; | ||
309 | |||
310 | OSDMap parameters= new OSDMap(); | ||
311 | UUID.TryParse(args[0], out creatorId); | ||
312 | parameters.Add("creatorId", OSD.FromUUID(creatorId)); | ||
313 | OSD Params = (OSD)parameters; | ||
314 | if(!JsonRpcRequest(ref Params, "avatarclassifiedsrequest", serverURI, UUID.Random().ToString())) | ||
315 | { | ||
316 | // Error Handling here! | ||
317 | // if(parameters.ContainsKey("message") | ||
318 | } | ||
319 | |||
320 | parameters = (OSDMap)Params; | ||
321 | |||
322 | OSDArray list = (OSDArray)parameters["result"]; | ||
323 | |||
324 | Dictionary<UUID, string> classifieds = new Dictionary<UUID, string>(); | ||
325 | |||
326 | foreach(OSD map in list) | ||
327 | { | ||
328 | OSDMap m = (OSDMap)map; | ||
329 | UUID cid = m["classifieduuid"].AsUUID(); | ||
330 | string name = m["name"].AsString(); | ||
331 | |||
332 | classifieds[cid] = name; | ||
333 | |||
334 | lock (m_classifiedCache) | ||
335 | { | ||
336 | if (!m_classifiedCache.ContainsKey(cid)) | ||
337 | { | ||
338 | m_classifiedCache.Add(cid,creatorId); | ||
339 | m_classifiedInterest.Add(cid, 0); | ||
340 | } | ||
341 | |||
342 | m_classifiedInterest[cid]++; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | remoteClient.SendAvatarClassifiedReply(new UUID(args[0]), classifieds); | ||
347 | } | ||
348 | |||
349 | public void ClassifiedInfoRequest(UUID queryClassifiedID, IClientAPI remoteClient) | ||
350 | { | ||
351 | UUID target = remoteClient.AgentId; | ||
352 | UserClassifiedAdd ad = new UserClassifiedAdd(); | ||
353 | ad.ClassifiedId = queryClassifiedID; | ||
354 | |||
355 | lock (m_classifiedCache) | ||
356 | { | ||
357 | if (m_classifiedCache.ContainsKey(queryClassifiedID)) | ||
358 | { | ||
359 | target = m_classifiedCache[queryClassifiedID]; | ||
360 | |||
361 | m_classifiedInterest[queryClassifiedID] --; | ||
362 | |||
363 | if (m_classifiedInterest[queryClassifiedID] == 0) | ||
364 | { | ||
365 | m_classifiedInterest.Remove(queryClassifiedID); | ||
366 | m_classifiedCache.Remove(queryClassifiedID); | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | |||
371 | string serverURI = string.Empty; | ||
372 | bool foreign = GetUserProfileServerURI(target, out serverURI); | ||
373 | |||
374 | object Ad = (object)ad; | ||
375 | if(!JsonRpcRequest(ref Ad, "classifieds_info_query", serverURI, UUID.Random().ToString())) | ||
376 | { | ||
377 | remoteClient.SendAgentAlertMessage( | ||
378 | "Error getting classified info", false); | ||
379 | return; | ||
380 | } | ||
381 | ad = (UserClassifiedAdd) Ad; | ||
382 | |||
383 | if(ad.CreatorId == UUID.Zero) | ||
384 | return; | ||
385 | |||
386 | Vector3 globalPos = new Vector3(); | ||
387 | Vector3.TryParse(ad.GlobalPos, out globalPos); | ||
388 | |||
389 | remoteClient.SendClassifiedInfoReply(ad.ClassifiedId, ad.CreatorId, (uint)ad.CreationDate, (uint)ad.ExpirationDate, | ||
390 | (uint)ad.Category, ad.Name, ad.Description, ad.ParcelId, (uint)ad.ParentEstate, | ||
391 | ad.SnapshotId, ad.SimName, globalPos, ad.ParcelName, ad.Flags, ad.Price); | ||
392 | |||
393 | } | ||
394 | |||
395 | /// <summary> | ||
396 | /// Classifieds info update. | ||
397 | /// </summary> | ||
398 | /// <param name='queryclassifiedID'> | ||
399 | /// Queryclassified I. | ||
400 | /// </param> | ||
401 | /// <param name='queryCategory'> | ||
402 | /// Query category. | ||
403 | /// </param> | ||
404 | /// <param name='queryName'> | ||
405 | /// Query name. | ||
406 | /// </param> | ||
407 | /// <param name='queryDescription'> | ||
408 | /// Query description. | ||
409 | /// </param> | ||
410 | /// <param name='queryParcelID'> | ||
411 | /// Query parcel I. | ||
412 | /// </param> | ||
413 | /// <param name='queryParentEstate'> | ||
414 | /// Query parent estate. | ||
415 | /// </param> | ||
416 | /// <param name='querySnapshotID'> | ||
417 | /// Query snapshot I. | ||
418 | /// </param> | ||
419 | /// <param name='queryGlobalPos'> | ||
420 | /// Query global position. | ||
421 | /// </param> | ||
422 | /// <param name='queryclassifiedFlags'> | ||
423 | /// Queryclassified flags. | ||
424 | /// </param> | ||
425 | /// <param name='queryclassifiedPrice'> | ||
426 | /// Queryclassified price. | ||
427 | /// </param> | ||
428 | /// <param name='remoteClient'> | ||
429 | /// Remote client. | ||
430 | /// </param> | ||
431 | public void ClassifiedInfoUpdate(UUID queryclassifiedID, uint queryCategory, string queryName, string queryDescription, UUID queryParcelID, | ||
432 | uint queryParentEstate, UUID querySnapshotID, Vector3 queryGlobalPos, byte queryclassifiedFlags, | ||
433 | int queryclassifiedPrice, IClientAPI remoteClient) | ||
434 | { | ||
435 | UserClassifiedAdd ad = new UserClassifiedAdd(); | ||
436 | |||
437 | Scene s = (Scene) remoteClient.Scene; | ||
438 | Vector3 pos = remoteClient.SceneAgent.AbsolutePosition; | ||
439 | ILandObject land = s.LandChannel.GetLandObject(pos.X, pos.Y); | ||
440 | ScenePresence p = FindPresence(remoteClient.AgentId); | ||
441 | Vector3 avaPos = p.AbsolutePosition; | ||
442 | |||
443 | string serverURI = string.Empty; | ||
444 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
445 | |||
446 | if (land == null) | ||
447 | { | ||
448 | ad.ParcelName = string.Empty; | ||
449 | } | ||
450 | else | ||
451 | { | ||
452 | ad.ParcelName = land.LandData.Name; | ||
453 | } | ||
454 | |||
455 | ad.CreatorId = remoteClient.AgentId; | ||
456 | ad.ClassifiedId = queryclassifiedID; | ||
457 | ad.Category = Convert.ToInt32(queryCategory); | ||
458 | ad.Name = queryName; | ||
459 | ad.Description = queryDescription; | ||
460 | ad.ParentEstate = Convert.ToInt32(queryParentEstate); | ||
461 | ad.SnapshotId = querySnapshotID; | ||
462 | ad.SimName = remoteClient.Scene.RegionInfo.RegionName; | ||
463 | ad.GlobalPos = queryGlobalPos.ToString (); | ||
464 | ad.Flags = queryclassifiedFlags; | ||
465 | ad.Price = queryclassifiedPrice; | ||
466 | ad.ParcelId = p.currentParcelUUID; | ||
467 | |||
468 | object Ad = ad; | ||
469 | |||
470 | OSD X = OSD.SerializeMembers(Ad); | ||
471 | |||
472 | if(!JsonRpcRequest(ref Ad, "classified_update", serverURI, UUID.Random().ToString())) | ||
473 | { | ||
474 | remoteClient.SendAgentAlertMessage( | ||
475 | "Error updating classified", false); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | /// <summary> | ||
480 | /// Classifieds delete. | ||
481 | /// </summary> | ||
482 | /// <param name='queryClassifiedID'> | ||
483 | /// Query classified I. | ||
484 | /// </param> | ||
485 | /// <param name='remoteClient'> | ||
486 | /// Remote client. | ||
487 | /// </param> | ||
488 | public void ClassifiedDelete(UUID queryClassifiedID, IClientAPI remoteClient) | ||
489 | { | ||
490 | string serverURI = string.Empty; | ||
491 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
492 | |||
493 | UUID classifiedId; | ||
494 | OSDMap parameters= new OSDMap(); | ||
495 | UUID.TryParse(queryClassifiedID.ToString(), out classifiedId); | ||
496 | parameters.Add("classifiedId", OSD.FromUUID(classifiedId)); | ||
497 | OSD Params = (OSD)parameters; | ||
498 | if(!JsonRpcRequest(ref Params, "classified_delete", serverURI, UUID.Random().ToString())) | ||
499 | { | ||
500 | remoteClient.SendAgentAlertMessage( | ||
501 | "Error classified delete", false); | ||
502 | } | ||
503 | |||
504 | parameters = (OSDMap)Params; | ||
505 | } | ||
506 | #endregion Classified | ||
507 | |||
508 | #region Picks | ||
509 | /// <summary> | ||
510 | /// Handles the avatar picks request. | ||
511 | /// </summary> | ||
512 | /// <param name='sender'> | ||
513 | /// Sender. | ||
514 | /// </param> | ||
515 | /// <param name='method'> | ||
516 | /// Method. | ||
517 | /// </param> | ||
518 | /// <param name='args'> | ||
519 | /// Arguments. | ||
520 | /// </param> | ||
521 | public void PicksRequest(Object sender, string method, List<String> args) | ||
522 | { | ||
523 | if (!(sender is IClientAPI)) | ||
524 | return; | ||
525 | |||
526 | IClientAPI remoteClient = (IClientAPI)sender; | ||
527 | |||
528 | UUID targetId; | ||
529 | UUID.TryParse(args[0], out targetId); | ||
530 | |||
531 | // Can't handle NPC yet... | ||
532 | ScenePresence p = FindPresence(targetId); | ||
533 | |||
534 | if (null != p) | ||
535 | { | ||
536 | if (p.PresenceType == PresenceType.Npc) | ||
537 | return; | ||
538 | } | ||
539 | |||
540 | string serverURI = string.Empty; | ||
541 | bool foreign = GetUserProfileServerURI(targetId, out serverURI); | ||
542 | |||
543 | OSDMap parameters= new OSDMap(); | ||
544 | parameters.Add("creatorId", OSD.FromUUID(targetId)); | ||
545 | OSD Params = (OSD)parameters; | ||
546 | if(!JsonRpcRequest(ref Params, "avatarpicksrequest", serverURI, UUID.Random().ToString())) | ||
547 | { | ||
548 | remoteClient.SendAgentAlertMessage( | ||
549 | "Error requesting picks", false); | ||
550 | return; | ||
551 | } | ||
552 | |||
553 | parameters = (OSDMap)Params; | ||
554 | |||
555 | OSDArray list = (OSDArray)parameters["result"]; | ||
556 | |||
557 | Dictionary<UUID, string> picks = new Dictionary<UUID, string>(); | ||
558 | |||
559 | foreach(OSD map in list) | ||
560 | { | ||
561 | OSDMap m = (OSDMap)map; | ||
562 | UUID cid = m["pickuuid"].AsUUID(); | ||
563 | string name = m["name"].AsString(); | ||
564 | |||
565 | m_log.DebugFormat("[PROFILES]: PicksRequest {0}", name); | ||
566 | |||
567 | picks[cid] = name; | ||
568 | } | ||
569 | remoteClient.SendAvatarPicksReply(new UUID(args[0]), picks); | ||
570 | } | ||
571 | |||
572 | /// <summary> | ||
573 | /// Handles the pick info request. | ||
574 | /// </summary> | ||
575 | /// <param name='sender'> | ||
576 | /// Sender. | ||
577 | /// </param> | ||
578 | /// <param name='method'> | ||
579 | /// Method. | ||
580 | /// </param> | ||
581 | /// <param name='args'> | ||
582 | /// Arguments. | ||
583 | /// </param> | ||
584 | public void PickInfoRequest(Object sender, string method, List<String> args) | ||
585 | { | ||
586 | if (!(sender is IClientAPI)) | ||
587 | return; | ||
588 | |||
589 | UUID targetID; | ||
590 | UUID.TryParse(args[0], out targetID); | ||
591 | string serverURI = string.Empty; | ||
592 | bool foreign = GetUserProfileServerURI(targetID, out serverURI); | ||
593 | IClientAPI remoteClient = (IClientAPI)sender; | ||
594 | |||
595 | UserProfilePick pick = new UserProfilePick(); | ||
596 | UUID.TryParse(args[0], out pick.CreatorId); | ||
597 | UUID.TryParse(args[1], out pick.PickId); | ||
598 | |||
599 | |||
600 | object Pick = (object)pick; | ||
601 | if(!JsonRpcRequest(ref Pick, "pickinforequest", serverURI, UUID.Random().ToString())) | ||
602 | { | ||
603 | remoteClient.SendAgentAlertMessage( | ||
604 | "Error selecting pick", false); | ||
605 | } | ||
606 | pick = (UserProfilePick) Pick; | ||
607 | if(pick.SnapshotId == UUID.Zero) | ||
608 | { | ||
609 | // In case of a new UserPick, the data may not be ready and we would send wrong data, skip it... | ||
610 | m_log.DebugFormat("[PROFILES]: PickInfoRequest: SnapshotID is {0}", UUID.Zero.ToString()); | ||
611 | return; | ||
612 | } | ||
613 | |||
614 | Vector3 globalPos; | ||
615 | Vector3.TryParse(pick.GlobalPos,out globalPos); | ||
616 | |||
617 | m_log.DebugFormat("[PROFILES]: PickInfoRequest: {0} : {1}", pick.Name.ToString(), pick.SnapshotId.ToString()); | ||
618 | |||
619 | remoteClient.SendPickInfoReply(pick.PickId,pick.CreatorId,pick.TopPick,pick.ParcelId,pick.Name, | ||
620 | pick.Desc,pick.SnapshotId,pick.User,pick.OriginalName,pick.SimName, | ||
621 | globalPos,pick.SortOrder,pick.Enabled); | ||
622 | } | ||
623 | |||
624 | /// <summary> | ||
625 | /// Updates the userpicks | ||
626 | /// </summary> | ||
627 | /// <param name='remoteClient'> | ||
628 | /// Remote client. | ||
629 | /// </param> | ||
630 | /// <param name='pickID'> | ||
631 | /// Pick I. | ||
632 | /// </param> | ||
633 | /// <param name='creatorID'> | ||
634 | /// the creator of the pick | ||
635 | /// </param> | ||
636 | /// <param name='topPick'> | ||
637 | /// Top pick. | ||
638 | /// </param> | ||
639 | /// <param name='name'> | ||
640 | /// Name. | ||
641 | /// </param> | ||
642 | /// <param name='desc'> | ||
643 | /// Desc. | ||
644 | /// </param> | ||
645 | /// <param name='snapshotID'> | ||
646 | /// Snapshot I. | ||
647 | /// </param> | ||
648 | /// <param name='sortOrder'> | ||
649 | /// Sort order. | ||
650 | /// </param> | ||
651 | /// <param name='enabled'> | ||
652 | /// Enabled. | ||
653 | /// </param> | ||
654 | public void PickInfoUpdate(IClientAPI remoteClient, UUID pickID, UUID creatorID, bool topPick, string name, string desc, UUID snapshotID, int sortOrder, bool enabled) | ||
655 | { | ||
656 | |||
657 | m_log.DebugFormat("[PROFILES]: Start PickInfoUpdate Name: {0} PickId: {1} SnapshotId: {2}", name, pickID.ToString(), snapshotID.ToString()); | ||
658 | UserProfilePick pick = new UserProfilePick(); | ||
659 | string serverURI = string.Empty; | ||
660 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
661 | ScenePresence p = FindPresence(remoteClient.AgentId); | ||
662 | |||
663 | Vector3 avaPos = p.AbsolutePosition; | ||
664 | // Getting the global position for the Avatar | ||
665 | Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.RegionLocX*Constants.RegionSize + avaPos.X, | ||
666 | remoteClient.Scene.RegionInfo.RegionLocY*Constants.RegionSize + avaPos.Y, | ||
667 | avaPos.Z); | ||
668 | |||
669 | string landOwnerName = string.Empty; | ||
670 | ILandObject land = p.Scene.LandChannel.GetLandObject(avaPos.X, avaPos.Y); | ||
671 | if(land.LandData.IsGroupOwned) | ||
672 | { | ||
673 | IGroupsModule groupMod = p.Scene.RequestModuleInterface<IGroupsModule>(); | ||
674 | UUID groupId = land.LandData.GroupID; | ||
675 | GroupRecord groupRecord = groupMod.GetGroupRecord(groupId); | ||
676 | landOwnerName = groupRecord.GroupName; | ||
677 | } | ||
678 | else | ||
679 | { | ||
680 | IUserAccountService accounts = p.Scene.RequestModuleInterface<IUserAccountService>(); | ||
681 | UserAccount user = accounts.GetUserAccount(p.Scene.RegionInfo.ScopeID, land.LandData.OwnerID); | ||
682 | landOwnerName = user.Name; | ||
683 | } | ||
684 | |||
685 | pick.PickId = pickID; | ||
686 | pick.CreatorId = creatorID; | ||
687 | pick.TopPick = topPick; | ||
688 | pick.Name = name; | ||
689 | pick.Desc = desc; | ||
690 | pick.ParcelId = p.currentParcelUUID; | ||
691 | pick.SnapshotId = snapshotID; | ||
692 | pick.User = landOwnerName; | ||
693 | pick.SimName = remoteClient.Scene.RegionInfo.RegionName; | ||
694 | pick.GlobalPos = posGlobal.ToString(); | ||
695 | pick.SortOrder = sortOrder; | ||
696 | pick.Enabled = enabled; | ||
697 | |||
698 | object Pick = (object)pick; | ||
699 | if(!JsonRpcRequest(ref Pick, "picks_update", serverURI, UUID.Random().ToString())) | ||
700 | { | ||
701 | remoteClient.SendAgentAlertMessage( | ||
702 | "Error updating pick", false); | ||
703 | } | ||
704 | |||
705 | m_log.DebugFormat("[PROFILES]: Finish PickInfoUpdate {0} {1}", pick.Name, pick.PickId.ToString()); | ||
706 | } | ||
707 | |||
708 | /// <summary> | ||
709 | /// Delete a Pick | ||
710 | /// </summary> | ||
711 | /// <param name='remoteClient'> | ||
712 | /// Remote client. | ||
713 | /// </param> | ||
714 | /// <param name='queryPickID'> | ||
715 | /// Query pick I. | ||
716 | /// </param> | ||
717 | public void PickDelete(IClientAPI remoteClient, UUID queryPickID) | ||
718 | { | ||
719 | string serverURI = string.Empty; | ||
720 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
721 | |||
722 | OSDMap parameters= new OSDMap(); | ||
723 | parameters.Add("pickId", OSD.FromUUID(queryPickID)); | ||
724 | OSD Params = (OSD)parameters; | ||
725 | if(!JsonRpcRequest(ref Params, "picks_delete", serverURI, UUID.Random().ToString())) | ||
726 | { | ||
727 | remoteClient.SendAgentAlertMessage( | ||
728 | "Error picks delete", false); | ||
729 | } | ||
730 | } | ||
731 | #endregion Picks | ||
732 | |||
733 | #region Notes | ||
734 | /// <summary> | ||
735 | /// Handles the avatar notes request. | ||
736 | /// </summary> | ||
737 | /// <param name='sender'> | ||
738 | /// Sender. | ||
739 | /// </param> | ||
740 | /// <param name='method'> | ||
741 | /// Method. | ||
742 | /// </param> | ||
743 | /// <param name='args'> | ||
744 | /// Arguments. | ||
745 | /// </param> | ||
746 | public void NotesRequest(Object sender, string method, List<String> args) | ||
747 | { | ||
748 | UserProfileNotes note = new UserProfileNotes(); | ||
749 | |||
750 | if (!(sender is IClientAPI)) | ||
751 | return; | ||
752 | |||
753 | IClientAPI remoteClient = (IClientAPI)sender; | ||
754 | string serverURI = string.Empty; | ||
755 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
756 | note.TargetId = remoteClient.AgentId; | ||
757 | UUID.TryParse(args[0], out note.UserId); | ||
758 | |||
759 | object Note = (object)note; | ||
760 | if(!JsonRpcRequest(ref Note, "avatarnotesrequest", serverURI, UUID.Random().ToString())) | ||
761 | { | ||
762 | remoteClient.SendAgentAlertMessage( | ||
763 | "Error requesting note", false); | ||
764 | } | ||
765 | note = (UserProfileNotes) Note; | ||
766 | |||
767 | remoteClient.SendAvatarNotesReply(note.TargetId, note.Notes); | ||
768 | } | ||
769 | |||
770 | /// <summary> | ||
771 | /// Avatars the notes update. | ||
772 | /// </summary> | ||
773 | /// <param name='remoteClient'> | ||
774 | /// Remote client. | ||
775 | /// </param> | ||
776 | /// <param name='queryTargetID'> | ||
777 | /// Query target I. | ||
778 | /// </param> | ||
779 | /// <param name='queryNotes'> | ||
780 | /// Query notes. | ||
781 | /// </param> | ||
782 | public void NotesUpdate(IClientAPI remoteClient, UUID queryTargetID, string queryNotes) | ||
783 | { | ||
784 | UserProfileNotes note = new UserProfileNotes(); | ||
785 | |||
786 | note.UserId = remoteClient.AgentId; | ||
787 | note.TargetId = queryTargetID; | ||
788 | note.Notes = queryNotes; | ||
789 | |||
790 | string serverURI = string.Empty; | ||
791 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
792 | |||
793 | object Note = note; | ||
794 | if(!JsonRpcRequest(ref Note, "avatar_notes_update", serverURI, UUID.Random().ToString())) | ||
795 | { | ||
796 | remoteClient.SendAgentAlertMessage( | ||
797 | "Error updating note", false); | ||
798 | } | ||
799 | } | ||
800 | #endregion Notes | ||
801 | |||
802 | #region Avatar Properties | ||
803 | /// <summary> | ||
804 | /// Update the avatars interests . | ||
805 | /// </summary> | ||
806 | /// <param name='remoteClient'> | ||
807 | /// Remote client. | ||
808 | /// </param> | ||
809 | /// <param name='wantmask'> | ||
810 | /// Wantmask. | ||
811 | /// </param> | ||
812 | /// <param name='wanttext'> | ||
813 | /// Wanttext. | ||
814 | /// </param> | ||
815 | /// <param name='skillsmask'> | ||
816 | /// Skillsmask. | ||
817 | /// </param> | ||
818 | /// <param name='skillstext'> | ||
819 | /// Skillstext. | ||
820 | /// </param> | ||
821 | /// <param name='languages'> | ||
822 | /// Languages. | ||
823 | /// </param> | ||
824 | public void AvatarInterestsUpdate(IClientAPI remoteClient, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages) | ||
825 | { | ||
826 | UserProfileProperties prop = new UserProfileProperties(); | ||
827 | |||
828 | prop.UserId = remoteClient.AgentId; | ||
829 | prop.WantToMask = (int)wantmask; | ||
830 | prop.WantToText = wanttext; | ||
831 | prop.SkillsMask = (int)skillsmask; | ||
832 | prop.SkillsText = skillstext; | ||
833 | prop.Language = languages; | ||
834 | |||
835 | string serverURI = string.Empty; | ||
836 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
837 | |||
838 | object Param = prop; | ||
839 | if(!JsonRpcRequest(ref Param, "avatar_interests_update", serverURI, UUID.Random().ToString())) | ||
840 | { | ||
841 | remoteClient.SendAgentAlertMessage( | ||
842 | "Error updating interests", false); | ||
843 | } | ||
844 | } | ||
845 | |||
846 | public void RequestAvatarProperties(IClientAPI remoteClient, UUID avatarID) | ||
847 | { | ||
848 | if ( String.IsNullOrEmpty(avatarID.ToString()) || String.IsNullOrEmpty(remoteClient.AgentId.ToString())) | ||
849 | { | ||
850 | // Looking for a reason that some viewers are sending null Id's | ||
851 | m_log.DebugFormat("[PROFILES]: This should not happen remoteClient.AgentId {0} - avatarID {1}", remoteClient.AgentId, avatarID); | ||
852 | return; | ||
853 | } | ||
854 | |||
855 | // Can't handle NPC yet... | ||
856 | ScenePresence p = FindPresence(avatarID); | ||
857 | |||
858 | if (null != p) | ||
859 | { | ||
860 | if (p.PresenceType == PresenceType.Npc) | ||
861 | return; | ||
862 | } | ||
863 | |||
864 | string serverURI = string.Empty; | ||
865 | bool foreign = GetUserProfileServerURI(avatarID, out serverURI); | ||
866 | |||
867 | UserAccount account = null; | ||
868 | Dictionary<string,object> userInfo; | ||
869 | |||
870 | if (!foreign) | ||
871 | { | ||
872 | account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, avatarID); | ||
873 | } | ||
874 | else | ||
875 | { | ||
876 | userInfo = new Dictionary<string, object>(); | ||
877 | } | ||
878 | |||
879 | Byte[] charterMember = new Byte[1]; | ||
880 | string born = String.Empty; | ||
881 | uint flags = 0x00; | ||
882 | |||
883 | if (null != account) | ||
884 | { | ||
885 | if (account.UserTitle == "") | ||
886 | { | ||
887 | charterMember[0] = (Byte)((account.UserFlags & 0xf00) >> 8); | ||
888 | } | ||
889 | else | ||
890 | { | ||
891 | charterMember = Utils.StringToBytes(account.UserTitle); | ||
892 | } | ||
893 | |||
894 | born = Util.ToDateTime(account.Created).ToString( | ||
895 | "M/d/yyyy", CultureInfo.InvariantCulture); | ||
896 | flags = (uint)(account.UserFlags & 0xff); | ||
897 | } | ||
898 | else | ||
899 | { | ||
900 | if (GetUserAccountData(avatarID, out userInfo) == true) | ||
901 | { | ||
902 | if ((string)userInfo["user_title"] == "") | ||
903 | { | ||
904 | charterMember[0] = (Byte)(((Byte)userInfo["user_flags"] & 0xf00) >> 8); | ||
905 | } | ||
906 | else | ||
907 | { | ||
908 | charterMember = Utils.StringToBytes((string)userInfo["user_title"]); | ||
909 | } | ||
910 | |||
911 | int val_born = (int)userInfo["user_created"]; | ||
912 | born = Util.ToDateTime(val_born).ToString( | ||
913 | "M/d/yyyy", CultureInfo.InvariantCulture); | ||
914 | |||
915 | // picky, picky | ||
916 | int val_flags = (int)userInfo["user_flags"]; | ||
917 | flags = (uint)(val_flags & 0xff); | ||
918 | } | ||
919 | } | ||
920 | |||
921 | UserProfileProperties props = new UserProfileProperties(); | ||
922 | string result = string.Empty; | ||
923 | |||
924 | props.UserId = avatarID; | ||
925 | GetProfileData(ref props, out result); | ||
926 | |||
927 | remoteClient.SendAvatarProperties(props.UserId, props.AboutText, born, charterMember , props.FirstLifeText, flags, | ||
928 | props.FirstLifeImageId, props.ImageId, props.WebUrl, props.PartnerId); | ||
929 | |||
930 | |||
931 | remoteClient.SendAvatarInterestsReply(props.UserId, (uint)props.WantToMask, props.WantToText, (uint)props.SkillsMask, | ||
932 | props.SkillsText, props.Language); | ||
933 | } | ||
934 | |||
935 | /// <summary> | ||
936 | /// Updates the avatar properties. | ||
937 | /// </summary> | ||
938 | /// <param name='remoteClient'> | ||
939 | /// Remote client. | ||
940 | /// </param> | ||
941 | /// <param name='newProfile'> | ||
942 | /// New profile. | ||
943 | /// </param> | ||
944 | public void AvatarPropertiesUpdate(IClientAPI remoteClient, UserProfileData newProfile) | ||
945 | { | ||
946 | if (remoteClient.AgentId == newProfile.ID) | ||
947 | { | ||
948 | UserProfileProperties prop = new UserProfileProperties(); | ||
949 | |||
950 | prop.UserId = remoteClient.AgentId; | ||
951 | prop.WebUrl = newProfile.ProfileUrl; | ||
952 | prop.ImageId = newProfile.Image; | ||
953 | prop.AboutText = newProfile.AboutText; | ||
954 | prop.FirstLifeImageId = newProfile.FirstLifeImage; | ||
955 | prop.FirstLifeText = newProfile.FirstLifeAboutText; | ||
956 | |||
957 | string serverURI = string.Empty; | ||
958 | bool foreign = GetUserProfileServerURI(remoteClient.AgentId, out serverURI); | ||
959 | |||
960 | object Prop = prop; | ||
961 | |||
962 | if(!JsonRpcRequest(ref Prop, "avatar_properties_update", serverURI, UUID.Random().ToString())) | ||
963 | { | ||
964 | remoteClient.SendAgentAlertMessage( | ||
965 | "Error updating properties", false); | ||
966 | } | ||
967 | |||
968 | RequestAvatarProperties(remoteClient, newProfile.ID); | ||
969 | } | ||
970 | } | ||
971 | |||
972 | |||
973 | /// <summary> | ||
974 | /// Gets the profile data. | ||
975 | /// </summary> | ||
976 | /// <returns> | ||
977 | /// The profile data. | ||
978 | /// </returns> | ||
979 | /// <param name='userID'> | ||
980 | /// User I. | ||
981 | /// </param> | ||
982 | bool GetProfileData(ref UserProfileProperties properties, out string message) | ||
983 | { | ||
984 | // Can't handle NPC yet... | ||
985 | ScenePresence p = FindPresence(properties.UserId); | ||
986 | |||
987 | if (null != p) | ||
988 | { | ||
989 | if (p.PresenceType == PresenceType.Npc) | ||
990 | { | ||
991 | message = "Id points to NPC"; | ||
992 | return false; | ||
993 | } | ||
994 | } | ||
995 | |||
996 | string serverURI = string.Empty; | ||
997 | bool foreign = GetUserProfileServerURI(properties.UserId, out serverURI); | ||
998 | |||
999 | // This is checking a friend on the home grid | ||
1000 | // Not HG friend | ||
1001 | if ( String.IsNullOrEmpty(serverURI)) | ||
1002 | { | ||
1003 | message = "No Presence - foreign friend"; | ||
1004 | return false; | ||
1005 | } | ||
1006 | |||
1007 | object Prop = (object)properties; | ||
1008 | JsonRpcRequest(ref Prop, "avatar_properties_request", serverURI, UUID.Random().ToString()); | ||
1009 | properties = (UserProfileProperties)Prop; | ||
1010 | |||
1011 | message = "Success"; | ||
1012 | return true; | ||
1013 | } | ||
1014 | #endregion Avatar Properties | ||
1015 | |||
1016 | #region Utils | ||
1017 | bool GetImageAssets(UUID avatarId) | ||
1018 | { | ||
1019 | string profileServerURI = string.Empty; | ||
1020 | string assetServerURI = string.Empty; | ||
1021 | |||
1022 | bool foreign = GetUserProfileServerURI(avatarId, out profileServerURI); | ||
1023 | |||
1024 | if(!foreign) | ||
1025 | return true; | ||
1026 | |||
1027 | assetServerURI = UserManagementModule.GetUserServerURL(avatarId, "AssetServerURI"); | ||
1028 | |||
1029 | OSDMap parameters= new OSDMap(); | ||
1030 | parameters.Add("avatarId", OSD.FromUUID(avatarId)); | ||
1031 | OSD Params = (OSD)parameters; | ||
1032 | if(!JsonRpcRequest(ref Params, "image_assets_request", profileServerURI, UUID.Random().ToString())) | ||
1033 | { | ||
1034 | // Error Handling here! | ||
1035 | // if(parameters.ContainsKey("message") | ||
1036 | return false; | ||
1037 | } | ||
1038 | |||
1039 | parameters = (OSDMap)Params; | ||
1040 | |||
1041 | OSDArray list = (OSDArray)parameters["result"]; | ||
1042 | |||
1043 | foreach(OSD asset in list) | ||
1044 | { | ||
1045 | OSDString assetId = (OSDString)asset; | ||
1046 | |||
1047 | Scene.AssetService.Get(string.Format("{0}/{1}",assetServerURI, assetId.AsString()), this, | ||
1048 | delegate (string assetID, Object s, AssetBase a) | ||
1049 | { | ||
1050 | // m_log.DebugFormat("[PROFILES]: Getting Image Assets {0}", assetID); | ||
1051 | return; | ||
1052 | }); | ||
1053 | } | ||
1054 | return true; | ||
1055 | } | ||
1056 | |||
1057 | /// <summary> | ||
1058 | /// Gets the user account data. | ||
1059 | /// </summary> | ||
1060 | /// <returns> | ||
1061 | /// The user profile data. | ||
1062 | /// </returns> | ||
1063 | /// <param name='userID'> | ||
1064 | /// If set to <c>true</c> user I. | ||
1065 | /// </param> | ||
1066 | /// <param name='userInfo'> | ||
1067 | /// If set to <c>true</c> user info. | ||
1068 | /// </param> | ||
1069 | bool GetUserAccountData(UUID userID, out Dictionary<string, object> userInfo) | ||
1070 | { | ||
1071 | Dictionary<string,object> info = new Dictionary<string, object>(); | ||
1072 | |||
1073 | if (UserManagementModule.IsLocalGridUser(userID)) | ||
1074 | { | ||
1075 | // Is local | ||
1076 | IUserAccountService uas = Scene.UserAccountService; | ||
1077 | UserAccount account = uas.GetUserAccount(Scene.RegionInfo.ScopeID, userID); | ||
1078 | |||
1079 | info["user_flags"] = account.UserFlags; | ||
1080 | info["user_created"] = account.Created; | ||
1081 | |||
1082 | if (!String.IsNullOrEmpty(account.UserTitle)) | ||
1083 | info["user_title"] = account.UserTitle; | ||
1084 | else | ||
1085 | info["user_title"] = ""; | ||
1086 | |||
1087 | userInfo = info; | ||
1088 | |||
1089 | return false; | ||
1090 | } | ||
1091 | else | ||
1092 | { | ||
1093 | // Is Foreign | ||
1094 | string home_url = UserManagementModule.GetUserServerURL(userID, "HomeURI"); | ||
1095 | |||
1096 | if (String.IsNullOrEmpty(home_url)) | ||
1097 | { | ||
1098 | info["user_flags"] = 0; | ||
1099 | info["user_created"] = 0; | ||
1100 | info["user_title"] = "Unavailable"; | ||
1101 | |||
1102 | userInfo = info; | ||
1103 | return true; | ||
1104 | } | ||
1105 | |||
1106 | UserAgentServiceConnector uConn = new UserAgentServiceConnector(home_url); | ||
1107 | |||
1108 | Dictionary<string, object> account = uConn.GetUserInfo(userID); | ||
1109 | |||
1110 | if (account.Count > 0) | ||
1111 | { | ||
1112 | if (account.ContainsKey("user_flags")) | ||
1113 | info["user_flags"] = account["user_flags"]; | ||
1114 | else | ||
1115 | info["user_flags"] = ""; | ||
1116 | |||
1117 | if (account.ContainsKey("user_created")) | ||
1118 | info["user_created"] = account["user_created"]; | ||
1119 | else | ||
1120 | info["user_created"] = ""; | ||
1121 | |||
1122 | info["user_title"] = "HG Visitor"; | ||
1123 | } | ||
1124 | else | ||
1125 | { | ||
1126 | info["user_flags"] = 0; | ||
1127 | info["user_created"] = 0; | ||
1128 | info["user_title"] = "HG Visitor"; | ||
1129 | } | ||
1130 | userInfo = info; | ||
1131 | return true; | ||
1132 | } | ||
1133 | } | ||
1134 | |||
1135 | /// <summary> | ||
1136 | /// Gets the user profile server UR. | ||
1137 | /// </summary> | ||
1138 | /// <returns> | ||
1139 | /// The user profile server UR. | ||
1140 | /// </returns> | ||
1141 | /// <param name='userID'> | ||
1142 | /// If set to <c>true</c> user I. | ||
1143 | /// </param> | ||
1144 | /// <param name='serverURI'> | ||
1145 | /// If set to <c>true</c> server UR. | ||
1146 | /// </param> | ||
1147 | bool GetUserProfileServerURI(UUID userID, out string serverURI) | ||
1148 | { | ||
1149 | bool local; | ||
1150 | local = UserManagementModule.IsLocalGridUser(userID); | ||
1151 | |||
1152 | if (!local) | ||
1153 | { | ||
1154 | serverURI = UserManagementModule.GetUserServerURL(userID, "ProfileServerURI"); | ||
1155 | // Is Foreign | ||
1156 | return true; | ||
1157 | } | ||
1158 | else | ||
1159 | { | ||
1160 | serverURI = ProfileServerUri; | ||
1161 | // Is local | ||
1162 | return false; | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | /// <summary> | ||
1167 | /// Finds the presence. | ||
1168 | /// </summary> | ||
1169 | /// <returns> | ||
1170 | /// The presence. | ||
1171 | /// </returns> | ||
1172 | /// <param name='clientID'> | ||
1173 | /// Client I. | ||
1174 | /// </param> | ||
1175 | ScenePresence FindPresence(UUID clientID) | ||
1176 | { | ||
1177 | ScenePresence p; | ||
1178 | |||
1179 | p = Scene.GetScenePresence(clientID); | ||
1180 | if (p != null && !p.IsChildAgent) | ||
1181 | return p; | ||
1182 | |||
1183 | return null; | ||
1184 | } | ||
1185 | #endregion Util | ||
1186 | |||
1187 | #region Web Util | ||
1188 | /// <summary> | ||
1189 | /// Sends json-rpc request with a serializable type. | ||
1190 | /// </summary> | ||
1191 | /// <returns> | ||
1192 | /// OSD Map. | ||
1193 | /// </returns> | ||
1194 | /// <param name='parameters'> | ||
1195 | /// Serializable type . | ||
1196 | /// </param> | ||
1197 | /// <param name='method'> | ||
1198 | /// Json-rpc method to call. | ||
1199 | /// </param> | ||
1200 | /// <param name='uri'> | ||
1201 | /// URI of json-rpc service. | ||
1202 | /// </param> | ||
1203 | /// <param name='jsonId'> | ||
1204 | /// Id for our call. | ||
1205 | /// </param> | ||
1206 | bool JsonRpcRequest(ref object parameters, string method, string uri, string jsonId) | ||
1207 | { | ||
1208 | if (jsonId == null) | ||
1209 | throw new ArgumentNullException ("jsonId"); | ||
1210 | if (uri == null) | ||
1211 | throw new ArgumentNullException ("uri"); | ||
1212 | if (method == null) | ||
1213 | throw new ArgumentNullException ("method"); | ||
1214 | if (parameters == null) | ||
1215 | throw new ArgumentNullException ("parameters"); | ||
1216 | |||
1217 | // Prep our payload | ||
1218 | OSDMap json = new OSDMap(); | ||
1219 | |||
1220 | json.Add("jsonrpc", OSD.FromString("2.0")); | ||
1221 | json.Add("id", OSD.FromString(jsonId)); | ||
1222 | json.Add("method", OSD.FromString(method)); | ||
1223 | // Experiment | ||
1224 | json.Add("params", OSD.SerializeMembers(parameters)); | ||
1225 | |||
1226 | string jsonRequestData = OSDParser.SerializeJsonString(json); | ||
1227 | byte[] content = Encoding.UTF8.GetBytes(jsonRequestData); | ||
1228 | |||
1229 | HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); | ||
1230 | // webRequest.Credentials = new NetworkCredential(rpcUser, rpcPass); | ||
1231 | webRequest.ContentType = "application/json-rpc"; | ||
1232 | webRequest.Method = "POST"; | ||
1233 | |||
1234 | Stream dataStream = webRequest.GetRequestStream(); | ||
1235 | dataStream.Write(content, 0, content.Length); | ||
1236 | dataStream.Close(); | ||
1237 | |||
1238 | WebResponse webResponse = null; | ||
1239 | try | ||
1240 | { | ||
1241 | webResponse = webRequest.GetResponse(); | ||
1242 | } | ||
1243 | catch (WebException e) | ||
1244 | { | ||
1245 | Console.WriteLine("Web Error" + e.Message); | ||
1246 | Console.WriteLine ("Please check input"); | ||
1247 | return false; | ||
1248 | } | ||
1249 | |||
1250 | byte[] buf = new byte[8192]; | ||
1251 | Stream rstream = webResponse.GetResponseStream(); | ||
1252 | OSDMap mret = (OSDMap)OSDParser.DeserializeJson(rstream); | ||
1253 | |||
1254 | if(mret.ContainsKey("error")) | ||
1255 | return false; | ||
1256 | |||
1257 | // get params... | ||
1258 | OSD.DeserializeMembers(ref parameters, (OSDMap) mret["result"]); | ||
1259 | return true; | ||
1260 | } | ||
1261 | |||
1262 | /// <summary> | ||
1263 | /// Sends json-rpc request with OSD parameter. | ||
1264 | /// </summary> | ||
1265 | /// <returns> | ||
1266 | /// The rpc request. | ||
1267 | /// </returns> | ||
1268 | /// <param name='data'> | ||
1269 | /// data - incoming as parameters, outgong as result/error | ||
1270 | /// </param> | ||
1271 | /// <param name='method'> | ||
1272 | /// Json-rpc method to call. | ||
1273 | /// </param> | ||
1274 | /// <param name='uri'> | ||
1275 | /// URI of json-rpc service. | ||
1276 | /// </param> | ||
1277 | /// <param name='jsonId'> | ||
1278 | /// If set to <c>true</c> json identifier. | ||
1279 | /// </param> | ||
1280 | bool JsonRpcRequest(ref OSD data, string method, string uri, string jsonId) | ||
1281 | { | ||
1282 | OSDMap map = new OSDMap(); | ||
1283 | |||
1284 | map["jsonrpc"] = "2.0"; | ||
1285 | if(string.IsNullOrEmpty(jsonId)) | ||
1286 | map["id"] = UUID.Random().ToString(); | ||
1287 | else | ||
1288 | map["id"] = jsonId; | ||
1289 | |||
1290 | map["method"] = method; | ||
1291 | map["params"] = data; | ||
1292 | |||
1293 | string jsonRequestData = OSDParser.SerializeJsonString(map); | ||
1294 | byte[] content = Encoding.UTF8.GetBytes(jsonRequestData); | ||
1295 | |||
1296 | HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri); | ||
1297 | webRequest.ContentType = "application/json-rpc"; | ||
1298 | webRequest.Method = "POST"; | ||
1299 | |||
1300 | Stream dataStream = webRequest.GetRequestStream(); | ||
1301 | dataStream.Write(content, 0, content.Length); | ||
1302 | dataStream.Close(); | ||
1303 | |||
1304 | WebResponse webResponse = null; | ||
1305 | try | ||
1306 | { | ||
1307 | webResponse = webRequest.GetResponse(); | ||
1308 | } | ||
1309 | catch (WebException e) | ||
1310 | { | ||
1311 | Console.WriteLine("Web Error" + e.Message); | ||
1312 | Console.WriteLine ("Please check input"); | ||
1313 | return false; | ||
1314 | } | ||
1315 | |||
1316 | byte[] buf = new byte[8192]; | ||
1317 | Stream rstream = webResponse.GetResponseStream(); | ||
1318 | |||
1319 | OSDMap response = new OSDMap(); | ||
1320 | try | ||
1321 | { | ||
1322 | response = (OSDMap)OSDParser.DeserializeJson(rstream); | ||
1323 | } | ||
1324 | catch (Exception e) | ||
1325 | { | ||
1326 | m_log.DebugFormat("[PROFILES]: JsonRpcRequest Error {0} - remote user with legacy profiles?", e.Message); | ||
1327 | return false; | ||
1328 | } | ||
1329 | |||
1330 | if(response.ContainsKey("error")) | ||
1331 | { | ||
1332 | data = response["error"]; | ||
1333 | return false; | ||
1334 | } | ||
1335 | |||
1336 | data = response; | ||
1337 | |||
1338 | return true; | ||
1339 | } | ||
1340 | #endregion Web Util | ||
1341 | } | ||
1342 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index ed867b8..b9c88d4 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |||
@@ -280,10 +280,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
280 | 280 | ||
281 | private void OnConnectionClosed(IClientAPI client) | 281 | private void OnConnectionClosed(IClientAPI client) |
282 | { | 282 | { |
283 | if (client.IsLoggingOut) | 283 | if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting)) |
284 | { | 284 | { |
285 | m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting); | ||
286 | |||
287 | m_log.DebugFormat( | 285 | m_log.DebugFormat( |
288 | "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", | 286 | "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", |
289 | client.Name, Scene.Name); | 287 | client.Name, Scene.Name); |
@@ -944,6 +942,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
944 | EnableChildAgents(sp); | 942 | EnableChildAgents(sp); |
945 | 943 | ||
946 | // Finally, kill the agent we just created at the destination. | 944 | // Finally, kill the agent we just created at the destination. |
945 | // XXX: Possibly this should be done asynchronously. | ||
947 | Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); | 946 | Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); |
948 | } | 947 | } |
949 | 948 | ||
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index d09ea3e..aa00145 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs | |||
@@ -358,7 +358,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
358 | bool asAttachment) | 358 | bool asAttachment) |
359 | { | 359 | { |
360 | CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); | 360 | CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); |
361 | Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); | 361 | // Dictionary<UUID, Vector3> originalPositions = new Dictionary<UUID, Vector3>(); |
362 | 362 | ||
363 | foreach (SceneObjectGroup objectGroup in objlist) | 363 | foreach (SceneObjectGroup objectGroup in objlist) |
364 | { | 364 | { |
@@ -379,7 +379,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
379 | objectGroup.AbsolutePosition.Z); | 379 | objectGroup.AbsolutePosition.Z); |
380 | 380 | ||
381 | Quaternion inventoryStoredRotation = objectGroup.GroupRotation; | 381 | Quaternion inventoryStoredRotation = objectGroup.GroupRotation; |
382 | originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; | 382 | //originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; |
383 | 383 | ||
384 | // Restore attachment data after trip through the sim | 384 | // Restore attachment data after trip through the sim |
385 | if (objectGroup.RootPart.AttachPoint > 0) | 385 | if (objectGroup.RootPart.AttachPoint > 0) |
@@ -423,9 +423,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
423 | else | 423 | else |
424 | itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); | 424 | itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); |
425 | 425 | ||
426 | // Restore the position of each group now that it has been stored to inventory. | 426 | // // Restore the position of each group now that it has been stored to inventory. |
427 | foreach (SceneObjectGroup objectGroup in objlist) | 427 | // foreach (SceneObjectGroup objectGroup in objlist) |
428 | objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; | 428 | // objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; |
429 | 429 | ||
430 | InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); | 430 | InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); |
431 | 431 | ||
@@ -707,6 +707,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
707 | InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); | 707 | InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); |
708 | if (f != null) | 708 | if (f != null) |
709 | folder = m_Scene.InventoryService.GetFolder(f); | 709 | folder = m_Scene.InventoryService.GetFolder(f); |
710 | |||
711 | if(folder.Type == 14 || folder.Type == 16) | ||
712 | { | ||
713 | // folder.Type = 6; | ||
714 | folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.Object); | ||
715 | } | ||
710 | } | 716 | } |
711 | } | 717 | } |
712 | 718 | ||
@@ -880,7 +886,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
880 | return null; | 886 | return null; |
881 | } | 887 | } |
882 | 888 | ||
883 | if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, rez_pos, attachment)) | 889 | if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, rez_pos, veclist, attachment)) |
884 | return null; | 890 | return null; |
885 | 891 | ||
886 | for (int i = 0; i < objlist.Count; i++) | 892 | for (int i = 0; i < objlist.Count; i++) |
@@ -979,10 +985,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
979 | /// <param name="item"></param> | 985 | /// <param name="item"></param> |
980 | /// <param name="objlist"></param> | 986 | /// <param name="objlist"></param> |
981 | /// <param name="pos"></param> | 987 | /// <param name="pos"></param> |
988 | /// <param name="veclist"> | ||
989 | /// List of vector position adjustments for a coalesced objects. For ordinary objects | ||
990 | /// this list will contain just Vector3.Zero. The order of adjustments must match the order of objlist | ||
991 | /// </param> | ||
982 | /// <param name="isAttachment"></param> | 992 | /// <param name="isAttachment"></param> |
983 | /// <returns>true if we can processed with rezzing, false if we need to abort</returns> | 993 | /// <returns>true if we can processed with rezzing, false if we need to abort</returns> |
984 | private bool DoPreRezWhenFromItem( | 994 | private bool DoPreRezWhenFromItem( |
985 | IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, Vector3 pos, bool isAttachment) | 995 | IClientAPI remoteClient, InventoryItemBase item, List<SceneObjectGroup> objlist, |
996 | Vector3 pos, List<Vector3> veclist, bool isAttachment) | ||
986 | { | 997 | { |
987 | UUID fromUserInventoryItemId = UUID.Zero; | 998 | UUID fromUserInventoryItemId = UUID.Zero; |
988 | 999 | ||
@@ -1005,28 +1016,29 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess | |||
1005 | } | 1016 | } |
1006 | } | 1017 | } |
1007 | 1018 | ||
1008 | int primcount = 0; | 1019 | for (int i = 0; i < objlist.Count; i++) |
1009 | foreach (SceneObjectGroup g in objlist) | ||
1010 | primcount += g.PrimCount; | ||
1011 | |||
1012 | if (!m_Scene.Permissions.CanRezObject( | ||
1013 | primcount, remoteClient.AgentId, pos) | ||
1014 | && !isAttachment) | ||
1015 | { | 1020 | { |
1016 | // The client operates in no fail mode. It will | 1021 | SceneObjectGroup g = objlist[i]; |
1017 | // have already removed the item from the folder | ||
1018 | // if it's no copy. | ||
1019 | // Put it back if it's not an attachment | ||
1020 | // | ||
1021 | if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment)) | ||
1022 | remoteClient.SendBulkUpdateInventory(item); | ||
1023 | 1022 | ||
1024 | ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); | 1023 | if (!m_Scene.Permissions.CanRezObject( |
1025 | remoteClient.SendAlertMessage(string.Format( | 1024 | g.PrimCount, remoteClient.AgentId, pos + veclist[i]) |
1026 | "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", | 1025 | && !isAttachment) |
1027 | item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.RegionInfo.RegionName)); | 1026 | { |
1027 | // The client operates in no fail mode. It will | ||
1028 | // have already removed the item from the folder | ||
1029 | // if it's no copy. | ||
1030 | // Put it back if it's not an attachment | ||
1031 | // | ||
1032 | if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!isAttachment)) | ||
1033 | remoteClient.SendBulkUpdateInventory(item); | ||
1028 | 1034 | ||
1029 | return false; | 1035 | ILandObject land = m_Scene.LandChannel.GetLandObject(pos.X, pos.Y); |
1036 | remoteClient.SendAlertMessage(string.Format( | ||
1037 | "Can't rez object '{0}' at <{1:F3}, {2:F3}, {3:F3}> on parcel '{4}' in region {5}.", | ||
1038 | item.Name, pos.X, pos.Y, pos.Z, land != null ? land.LandData.Name : "Unknown", m_Scene.Name)); | ||
1039 | |||
1040 | return false; | ||
1041 | } | ||
1030 | } | 1042 | } |
1031 | 1043 | ||
1032 | for (int i = 0; i < objlist.Count; i++) | 1044 | for (int i = 0; i < objlist.Count; i++) |
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs index 4ef57fe..ad3cf15 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs | |||
@@ -50,12 +50,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
50 | { | 50 | { |
51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
52 | 52 | ||
53 | |||
54 | #region ISharedRegionModule | 53 | #region ISharedRegionModule |
55 | 54 | ||
56 | public new void Initialise(IConfigSource config) | 55 | public new void Initialise(IConfigSource config) |
57 | { | 56 | { |
58 | string umanmod = config.Configs["Modules"].GetString("UserManagementModule", base.Name); | 57 | string umanmod = config.Configs["Modules"].GetString("UserManagementModule", null); |
59 | if (umanmod == Name) | 58 | if (umanmod == Name) |
60 | { | 59 | { |
61 | m_Enabled = true; | 60 | m_Enabled = true; |
@@ -71,7 +70,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
71 | 70 | ||
72 | #endregion ISharedRegionModule | 71 | #endregion ISharedRegionModule |
73 | 72 | ||
74 | protected override void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users) | 73 | protected override void AddAdditionalUsers(string query, List<UserData> users) |
75 | { | 74 | { |
76 | if (query.Contains("@")) // First.Last@foo.com, maybe? | 75 | if (query.Contains("@")) // First.Last@foo.com, maybe? |
77 | { | 76 | { |
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs new file mode 100644 index 0000000..9d36aa5 --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs | |||
@@ -0,0 +1,76 @@ | |||
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 | |||
28 | using System; | ||
29 | using Nini.Config; | ||
30 | using NUnit.Framework; | ||
31 | using OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.CoreModules.Framework.UserManagement; | ||
34 | using OpenSim.Tests.Common; | ||
35 | using OpenSim.Tests.Common.Mock; | ||
36 | |||
37 | namespace OpenSim.Region.CoreModules.Framework.UserManagement.Tests | ||
38 | { | ||
39 | [TestFixture] | ||
40 | public class HGUserManagementModuleTests : OpenSimTestCase | ||
41 | { | ||
42 | /// <summary> | ||
43 | /// Test that a new HG agent (i.e. one without a user account) has their name cached in the UMM upon creation. | ||
44 | /// </summary> | ||
45 | [Test] | ||
46 | public void TestCachedUserNameForNewAgent() | ||
47 | { | ||
48 | TestHelpers.InMethod(); | ||
49 | // TestHelpers.EnableLogging(); | ||
50 | |||
51 | HGUserManagementModule hgumm = new HGUserManagementModule(); | ||
52 | UUID userId = TestHelpers.ParseStem("11"); | ||
53 | string firstName = "Fred"; | ||
54 | string lastName = "Astaire"; | ||
55 | string homeUri = "example.com"; | ||
56 | |||
57 | IConfigSource config = new IniConfigSource(); | ||
58 | config.AddConfig("Modules"); | ||
59 | config.Configs["Modules"].Set("UserManagementModule", hgumm.Name); | ||
60 | |||
61 | SceneHelpers sceneHelpers = new SceneHelpers(); | ||
62 | TestScene scene = sceneHelpers.SetupScene(); | ||
63 | SceneHelpers.SetupSceneModules(scene, config, hgumm); | ||
64 | |||
65 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); | ||
66 | acd.firstname = firstName; | ||
67 | acd.lastname = lastName; | ||
68 | acd.ServiceURLs["HomeURI"] = "http://" + homeUri; | ||
69 | |||
70 | SceneHelpers.AddScenePresence(scene, acd); | ||
71 | |||
72 | string name = hgumm.GetUserName(userId); | ||
73 | Assert.That(name, Is.EqualTo(string.Format("{0}.{1} @{2}", firstName, lastName, homeUri))); | ||
74 | } | ||
75 | } | ||
76 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 77e8b00..864e181 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs | |||
@@ -46,17 +46,8 @@ using Mono.Addins; | |||
46 | 46 | ||
47 | namespace OpenSim.Region.CoreModules.Framework.UserManagement | 47 | namespace OpenSim.Region.CoreModules.Framework.UserManagement |
48 | { | 48 | { |
49 | public class UserData | ||
50 | { | ||
51 | public UUID Id { get; set; } | ||
52 | public string FirstName { get; set; } | ||
53 | public string LastName { get; set; } | ||
54 | public string HomeURL { get; set; } | ||
55 | public Dictionary<string, object> ServerURLs { get; set; } | ||
56 | } | ||
57 | |||
58 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")] | 49 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserManagementModule")] |
59 | public class UserManagementModule : ISharedRegionModule, IUserManagement | 50 | public class UserManagementModule : ISharedRegionModule, IUserManagement, IPeople |
60 | { | 51 | { |
61 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
62 | 53 | ||
@@ -101,6 +92,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
101 | m_Scenes.Add(scene); | 92 | m_Scenes.Add(scene); |
102 | 93 | ||
103 | scene.RegisterModuleInterface<IUserManagement>(this); | 94 | scene.RegisterModuleInterface<IUserManagement>(this); |
95 | scene.RegisterModuleInterface<IPeople>(this); | ||
104 | scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); | 96 | scene.EventManager.OnNewClient += new EventManager.OnNewClientDelegate(EventManager_OnNewClient); |
105 | scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); | 97 | scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); |
106 | } | 98 | } |
@@ -165,13 +157,16 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
165 | } | 157 | } |
166 | else | 158 | else |
167 | { | 159 | { |
168 | string[] names = GetUserNames(uuid); | 160 | string[] names; |
161 | bool foundRealName = TryGetUserNames(uuid, out names); | ||
162 | |||
169 | if (names.Length == 2) | 163 | if (names.Length == 2) |
170 | { | 164 | { |
171 | //m_log.DebugFormat("[XXX] HandleUUIDNameRequest {0} is {1} {2}", uuid, names[0], names[1]); | 165 | if (!foundRealName) |
166 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: Sending {0} {1} for {2} to {3} since no bound name found", names[0], names[1], uuid, remote_client.Name); | ||
167 | |||
172 | remote_client.SendNameReply(uuid, names[0], names[1]); | 168 | remote_client.SendNameReply(uuid, names[0], names[1]); |
173 | } | 169 | } |
174 | |||
175 | } | 170 | } |
176 | } | 171 | } |
177 | 172 | ||
@@ -181,29 +176,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
181 | 176 | ||
182 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); | 177 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: HandleAvatarPickerRequest for {0}", query); |
183 | 178 | ||
184 | // searhc the user accounts service | 179 | List<UserData> users = GetUserData(query, 500, 1); |
185 | List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); | ||
186 | |||
187 | List<UserData> users = new List<UserData>(); | ||
188 | if (accs != null) | ||
189 | { | ||
190 | foreach (UserAccount acc in accs) | ||
191 | { | ||
192 | UserData ud = new UserData(); | ||
193 | ud.FirstName = acc.FirstName; | ||
194 | ud.LastName = acc.LastName; | ||
195 | ud.Id = acc.PrincipalID; | ||
196 | users.Add(ud); | ||
197 | } | ||
198 | } | ||
199 | |||
200 | // search the local cache | ||
201 | foreach (UserData data in m_UserCache.Values) | ||
202 | if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && | ||
203 | (data.FirstName.StartsWith(query) || data.LastName.StartsWith(query))) | ||
204 | users.Add(data); | ||
205 | |||
206 | AddAdditionalUsers(avatarID, query, users); | ||
207 | 180 | ||
208 | AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); | 181 | AvatarPickerReplyPacket replyPacket = (AvatarPickerReplyPacket)PacketPool.Instance.GetPacket(PacketType.AvatarPickerReply); |
209 | // TODO: don't create new blocks if recycling an old packet | 182 | // TODO: don't create new blocks if recycling an old packet |
@@ -249,12 +222,51 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
249 | client.SendAvatarPickerReply(agent_data, data_args); | 222 | client.SendAvatarPickerReply(agent_data, data_args); |
250 | } | 223 | } |
251 | 224 | ||
252 | protected virtual void AddAdditionalUsers(UUID avatarID, string query, List<UserData> users) | 225 | protected virtual void AddAdditionalUsers(string query, List<UserData> users) |
253 | { | 226 | { |
254 | } | 227 | } |
255 | 228 | ||
256 | #endregion Event Handlers | 229 | #endregion Event Handlers |
257 | 230 | ||
231 | #region IPeople | ||
232 | |||
233 | public List<UserData> GetUserData(string query, int page_size, int page_number) | ||
234 | { | ||
235 | // search the user accounts service | ||
236 | List<UserAccount> accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); | ||
237 | |||
238 | List<UserData> users = new List<UserData>(); | ||
239 | if (accs != null) | ||
240 | { | ||
241 | foreach (UserAccount acc in accs) | ||
242 | { | ||
243 | UserData ud = new UserData(); | ||
244 | ud.FirstName = acc.FirstName; | ||
245 | ud.LastName = acc.LastName; | ||
246 | ud.Id = acc.PrincipalID; | ||
247 | users.Add(ud); | ||
248 | } | ||
249 | } | ||
250 | |||
251 | // search the local cache | ||
252 | lock (m_UserCache) | ||
253 | { | ||
254 | foreach (UserData data in m_UserCache.Values) | ||
255 | { | ||
256 | if (users.Find(delegate(UserData d) { return d.Id == data.Id; }) == null && | ||
257 | (data.FirstName.ToLower().StartsWith(query.ToLower()) || data.LastName.ToLower().StartsWith(query.ToLower()))) | ||
258 | users.Add(data); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | AddAdditionalUsers(query, users); | ||
263 | |||
264 | return users; | ||
265 | |||
266 | } | ||
267 | |||
268 | #endregion IPeople | ||
269 | |||
258 | private void CacheCreators(SceneObjectGroup sog) | 270 | private void CacheCreators(SceneObjectGroup sog) |
259 | { | 271 | { |
260 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification); | 272 | //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification); |
@@ -268,17 +280,24 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
268 | } | 280 | } |
269 | } | 281 | } |
270 | 282 | ||
271 | private string[] GetUserNames(UUID uuid) | 283 | /// <summary> |
284 | /// Try to get the names bound to the given uuid. | ||
285 | /// </summary> | ||
286 | /// <returns>True if the name was found, false if not.</returns> | ||
287 | /// <param name='uuid'></param> | ||
288 | /// <param name='names'>The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User"</param> | ||
289 | private bool TryGetUserNames(UUID uuid, out string[] names) | ||
272 | { | 290 | { |
273 | string[] returnstring = new string[2]; | 291 | names = new string[2]; |
274 | 292 | ||
275 | lock (m_UserCache) | 293 | lock (m_UserCache) |
276 | { | 294 | { |
277 | if (m_UserCache.ContainsKey(uuid)) | 295 | if (m_UserCache.ContainsKey(uuid)) |
278 | { | 296 | { |
279 | returnstring[0] = m_UserCache[uuid].FirstName; | 297 | names[0] = m_UserCache[uuid].FirstName; |
280 | returnstring[1] = m_UserCache[uuid].LastName; | 298 | names[1] = m_UserCache[uuid].LastName; |
281 | return returnstring; | 299 | |
300 | return true; | ||
282 | } | 301 | } |
283 | } | 302 | } |
284 | 303 | ||
@@ -286,8 +305,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
286 | 305 | ||
287 | if (account != null) | 306 | if (account != null) |
288 | { | 307 | { |
289 | returnstring[0] = account.FirstName; | 308 | names[0] = account.FirstName; |
290 | returnstring[1] = account.LastName; | 309 | names[1] = account.LastName; |
291 | 310 | ||
292 | UserData user = new UserData(); | 311 | UserData user = new UserData(); |
293 | user.FirstName = account.FirstName; | 312 | user.FirstName = account.FirstName; |
@@ -295,14 +314,16 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
295 | 314 | ||
296 | lock (m_UserCache) | 315 | lock (m_UserCache) |
297 | m_UserCache[uuid] = user; | 316 | m_UserCache[uuid] = user; |
317 | |||
318 | return true; | ||
298 | } | 319 | } |
299 | else | 320 | else |
300 | { | 321 | { |
301 | returnstring[0] = "Unknown"; | 322 | names[0] = "Unknown"; |
302 | returnstring[1] = "User"; | 323 | names[1] = "UserUMMTGUN2"; |
303 | } | ||
304 | 324 | ||
305 | return returnstring; | 325 | return false; |
326 | } | ||
306 | } | 327 | } |
307 | 328 | ||
308 | #region IUserManagement | 329 | #region IUserManagement |
@@ -338,15 +359,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
338 | 359 | ||
339 | public string GetUserName(UUID uuid) | 360 | public string GetUserName(UUID uuid) |
340 | { | 361 | { |
341 | string[] names = GetUserNames(uuid); | 362 | string[] names; |
363 | TryGetUserNames(uuid, out names); | ||
364 | |||
342 | if (names.Length == 2) | 365 | if (names.Length == 2) |
343 | { | 366 | { |
344 | string firstname = names[0]; | 367 | string firstname = names[0]; |
345 | string lastname = names[1]; | 368 | string lastname = names[1]; |
346 | 369 | ||
347 | return firstname + " " + lastname; | 370 | return firstname + " " + lastname; |
348 | |||
349 | } | 371 | } |
372 | |||
350 | return "(hippos)"; | 373 | return "(hippos)"; |
351 | } | 374 | } |
352 | 375 | ||
@@ -453,70 +476,71 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
453 | UserData oldUser; | 476 | UserData oldUser; |
454 | //lock the whole block - prevent concurrent update | 477 | //lock the whole block - prevent concurrent update |
455 | lock (m_UserCache) | 478 | lock (m_UserCache) |
479 | m_UserCache.TryGetValue(id, out oldUser); | ||
480 | |||
481 | if (oldUser != null) | ||
456 | { | 482 | { |
457 | m_UserCache.TryGetValue (id, out oldUser); | 483 | if (creatorData == null || creatorData == String.Empty) |
458 | if (oldUser != null) | ||
459 | { | 484 | { |
460 | if (creatorData == null || creatorData == String.Empty) | 485 | //ignore updates without creator data |
461 | { | 486 | return; |
462 | //ignore updates without creator data | ||
463 | return; | ||
464 | } | ||
465 | //try update unknown users | ||
466 | //and creator's home URL's | ||
467 | if ((oldUser.FirstName == "Unknown" && !creatorData.Contains ("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith (oldUser.HomeURL))) | ||
468 | { | ||
469 | m_UserCache.Remove (id); | ||
470 | // m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData,oldUser.HomeURL); | ||
471 | } | ||
472 | else | ||
473 | { | ||
474 | //we have already a valid user within the cache | ||
475 | return; | ||
476 | } | ||
477 | } | 487 | } |
478 | 488 | ||
479 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount (m_Scenes [0].RegionInfo.ScopeID, id); | 489 | //try update unknown users |
480 | 490 | //and creator's home URL's | |
481 | if (account != null) | 491 | if ((oldUser.FirstName == "Unknown" && !creatorData.Contains("Unknown")) || (oldUser.HomeURL != null && !creatorData.StartsWith(oldUser.HomeURL))) |
482 | { | 492 | { |
483 | AddUser (id, account.FirstName, account.LastName); | 493 | lock (m_UserCache) |
494 | m_UserCache.Remove(id); | ||
495 | m_log.DebugFormat("[USER MANAGEMENT MODULE]: Re-adding user with id {0}, creatorData [{1}] and old HomeURL {2}", id, creatorData, oldUser.HomeURL); | ||
484 | } | 496 | } |
485 | else | 497 | else |
486 | { | 498 | { |
487 | UserData user = new UserData (); | 499 | //we have already a valid user within the cache |
488 | user.Id = id; | 500 | return; |
501 | } | ||
502 | } | ||
489 | 503 | ||
490 | if (creatorData != null && creatorData != string.Empty) | 504 | UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, id); |
491 | { | 505 | |
492 | //creatorData = <endpoint>;<name> | 506 | if (account != null) |
507 | { | ||
508 | AddUser(id, account.FirstName, account.LastName); | ||
509 | } | ||
510 | else | ||
511 | { | ||
512 | UserData user = new UserData(); | ||
513 | user.Id = id; | ||
514 | |||
515 | if (creatorData != null && creatorData != string.Empty) | ||
516 | { | ||
517 | //creatorData = <endpoint>;<name> | ||
493 | 518 | ||
494 | string[] parts = creatorData.Split (';'); | 519 | string[] parts = creatorData.Split(';'); |
495 | if (parts.Length >= 1) | 520 | if (parts.Length >= 1) |
521 | { | ||
522 | user.HomeURL = parts[0]; | ||
523 | try | ||
496 | { | 524 | { |
497 | user.HomeURL = parts [0]; | 525 | Uri uri = new Uri(parts[0]); |
498 | try | 526 | user.LastName = "@" + uri.Authority; |
499 | { | 527 | } |
500 | Uri uri = new Uri (parts [0]); | 528 | catch (UriFormatException) |
501 | user.LastName = "@" + uri.Authority; | 529 | { |
502 | } | 530 | m_log.DebugFormat("[SCENE]: Unable to parse Uri {0}", parts[0]); |
503 | catch (UriFormatException) | 531 | user.LastName = "@unknown"; |
504 | { | ||
505 | m_log.DebugFormat ("[SCENE]: Unable to parse Uri {0}", parts [0]); | ||
506 | user.LastName = "@unknown"; | ||
507 | } | ||
508 | } | 532 | } |
509 | if (parts.Length >= 2) | ||
510 | user.FirstName = parts [1].Replace (' ', '.'); | ||
511 | } | ||
512 | else | ||
513 | { | ||
514 | user.FirstName = "Unknown"; | ||
515 | user.LastName = "User"; | ||
516 | } | 533 | } |
517 | 534 | if (parts.Length >= 2) | |
518 | AddUserInternal (user); | 535 | user.FirstName = parts[1].Replace(' ', '.'); |
536 | } | ||
537 | else | ||
538 | { | ||
539 | user.FirstName = "Unknown"; | ||
540 | user.LastName = "UserUMMAU"; | ||
519 | } | 541 | } |
542 | |||
543 | AddUserInternal(user); | ||
520 | } | 544 | } |
521 | } | 545 | } |
522 | 546 | ||
@@ -544,6 +568,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
544 | protected void RegisterConsoleCmds() | 568 | protected void RegisterConsoleCmds() |
545 | { | 569 | { |
546 | MainConsole.Instance.Commands.AddCommand("Users", true, | 570 | MainConsole.Instance.Commands.AddCommand("Users", true, |
571 | "show name", | ||
572 | "show name <uuid>", | ||
573 | "Show the bindings between a single user UUID and a user name", | ||
574 | String.Empty, | ||
575 | HandleShowUser); | ||
576 | |||
577 | MainConsole.Instance.Commands.AddCommand("Users", true, | ||
547 | "show names", | 578 | "show names", |
548 | "show names", | 579 | "show names", |
549 | "Show the bindings between user UUIDs and user names", | 580 | "Show the bindings between user UUIDs and user names", |
@@ -551,26 +582,54 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement | |||
551 | HandleShowUsers); | 582 | HandleShowUsers); |
552 | } | 583 | } |
553 | 584 | ||
554 | private void HandleShowUsers(string module, string[] cmd) | 585 | private void HandleShowUser(string module, string[] cmd) |
555 | { | 586 | { |
587 | if (cmd.Length < 3) | ||
588 | { | ||
589 | MainConsole.Instance.OutputFormat("Usage: show name <uuid>"); | ||
590 | return; | ||
591 | } | ||
592 | |||
593 | UUID userId; | ||
594 | if (!ConsoleUtil.TryParseConsoleUuid(MainConsole.Instance, cmd[2], out userId)) | ||
595 | return; | ||
596 | |||
597 | string[] names; | ||
598 | |||
599 | UserData ud; | ||
600 | |||
556 | lock (m_UserCache) | 601 | lock (m_UserCache) |
557 | { | 602 | { |
558 | if (m_UserCache.Count == 0) | 603 | if (!m_UserCache.TryGetValue(userId, out ud)) |
559 | { | 604 | { |
560 | MainConsole.Instance.Output("No users found"); | 605 | MainConsole.Instance.OutputFormat("No name known for user with id {0}", userId); |
561 | return; | 606 | return; |
562 | } | 607 | } |
563 | 608 | } | |
564 | MainConsole.Instance.Output("UUID User Name"); | 609 | |
565 | MainConsole.Instance.Output("-----------------------------------------------------------------------------"); | 610 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); |
611 | cdt.AddColumn("UUID", 36); | ||
612 | cdt.AddColumn("Name", 30); | ||
613 | cdt.AddColumn("HomeURL", 40); | ||
614 | cdt.AddRow(userId, string.Format("{0} {1}", ud.FirstName, ud.LastName), ud.HomeURL); | ||
615 | |||
616 | MainConsole.Instance.Output(cdt.ToString()); | ||
617 | } | ||
618 | |||
619 | private void HandleShowUsers(string module, string[] cmd) | ||
620 | { | ||
621 | ConsoleDisplayTable cdt = new ConsoleDisplayTable(); | ||
622 | cdt.AddColumn("UUID", 36); | ||
623 | cdt.AddColumn("Name", 30); | ||
624 | cdt.AddColumn("HomeURL", 40); | ||
625 | |||
626 | lock (m_UserCache) | ||
627 | { | ||
566 | foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache) | 628 | foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache) |
567 | { | 629 | cdt.AddRow(kvp.Key, string.Format("{0} {1}", kvp.Value.FirstName, kvp.Value.LastName), kvp.Value.HomeURL); |
568 | MainConsole.Instance.Output(String.Format("{0} {1} {2} ({3})", | ||
569 | kvp.Key, kvp.Value.FirstName, kvp.Value.LastName, kvp.Value.HomeURL)); | ||
570 | } | ||
571 | |||
572 | return; | ||
573 | } | 630 | } |
631 | |||
632 | MainConsole.Instance.Output(cdt.ToString()); | ||
574 | } | 633 | } |
575 | } | 634 | } |
576 | } \ No newline at end of file | 635 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index 2b13a8b..6eb25ef 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | |||
@@ -412,7 +412,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
412 | //public bool HttpVerboseThrottle = true; // not implemented | 412 | //public bool HttpVerboseThrottle = true; // not implemented |
413 | public List<string> HttpCustomHeaders = null; | 413 | public List<string> HttpCustomHeaders = null; |
414 | public bool HttpPragmaNoCache = true; | 414 | public bool HttpPragmaNoCache = true; |
415 | private Thread httpThread; | ||
416 | 415 | ||
417 | // Request info | 416 | // Request info |
418 | private UUID _itemID; | 417 | private UUID _itemID; |
@@ -622,7 +621,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
622 | { | 621 | { |
623 | if (!WorkItem.Cancel()) | 622 | if (!WorkItem.Cancel()) |
624 | { | 623 | { |
625 | WorkItem.Abort(); | 624 | WorkItem.Cancel(true); |
626 | } | 625 | } |
627 | } | 626 | } |
628 | catch (Exception) | 627 | catch (Exception) |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs new file mode 100644 index 0000000..323535a --- /dev/null +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/UserProfiles/LocalUserProfilesServiceConnector.cs | |||
@@ -0,0 +1,226 @@ | |||
1 | |||
2 | /* | ||
3 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
4 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of the OpenSimulator Project nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
20 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
26 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
27 | */ | ||
28 | |||
29 | using log4net; | ||
30 | using Mono.Addins; | ||
31 | using Nini.Config; | ||
32 | using System; | ||
33 | using System.Collections.Generic; | ||
34 | using System.Reflection; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Framework.Console; | ||
37 | using OpenSim.Server.Base; | ||
38 | using OpenSim.Server.Handlers; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Framework.Servers.HttpServer; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Region.Framework.Scenes; | ||
43 | using OpenSim.Services.Interfaces; | ||
44 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
45 | using OpenMetaverse; | ||
46 | |||
47 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Profile | ||
48 | { | ||
49 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalUserProfilesServicesConnector")] | ||
50 | public class LocalUserProfilesServicesConnector : ISharedRegionModule | ||
51 | { | ||
52 | private static readonly ILog m_log = | ||
53 | LogManager.GetLogger( | ||
54 | MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private Dictionary<UUID, Scene> regions = new Dictionary<UUID, Scene>(); | ||
57 | |||
58 | public IUserProfilesService ServiceModule | ||
59 | { | ||
60 | get; private set; | ||
61 | } | ||
62 | |||
63 | public bool Enabled | ||
64 | { | ||
65 | get; private set; | ||
66 | } | ||
67 | |||
68 | public string Name | ||
69 | { | ||
70 | get | ||
71 | { | ||
72 | return "LocalUserProfilesServicesConnector"; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | public string ConfigName | ||
77 | { | ||
78 | get; private set; | ||
79 | } | ||
80 | |||
81 | public Type ReplaceableInterface | ||
82 | { | ||
83 | get { return null; } | ||
84 | } | ||
85 | |||
86 | public LocalUserProfilesServicesConnector() | ||
87 | { | ||
88 | m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector no params"); | ||
89 | } | ||
90 | |||
91 | public LocalUserProfilesServicesConnector(IConfigSource source) | ||
92 | { | ||
93 | m_log.Debug("[LOCAL USERPROFILES SERVICE CONNECTOR]: LocalUserProfileServicesConnector instantiated directly."); | ||
94 | InitialiseService(source); | ||
95 | } | ||
96 | |||
97 | public void InitialiseService(IConfigSource source) | ||
98 | { | ||
99 | ConfigName = "UserProfilesService"; | ||
100 | |||
101 | // Instantiate the request handler | ||
102 | IHttpServer Server = MainServer.Instance; | ||
103 | |||
104 | IConfig config = source.Configs[ConfigName]; | ||
105 | if (config == null) | ||
106 | { | ||
107 | m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: UserProfilesService missing from OpenSim.ini"); | ||
108 | return; | ||
109 | } | ||
110 | |||
111 | if(!config.GetBoolean("Enabled",false)) | ||
112 | { | ||
113 | Enabled = false; | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | Enabled = true; | ||
118 | |||
119 | string serviceDll = config.GetString("LocalServiceModule", | ||
120 | String.Empty); | ||
121 | |||
122 | if (serviceDll == String.Empty) | ||
123 | { | ||
124 | m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: No LocalServiceModule named in section UserProfilesService"); | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | Object[] args = new Object[] { source, ConfigName }; | ||
129 | ServiceModule = | ||
130 | ServerUtils.LoadPlugin<IUserProfilesService>(serviceDll, | ||
131 | args); | ||
132 | |||
133 | if (ServiceModule == null) | ||
134 | { | ||
135 | m_log.Error("[LOCAL USERPROFILES SERVICE CONNECTOR]: Can't load user profiles service"); | ||
136 | return; | ||
137 | } | ||
138 | |||
139 | Enabled = true; | ||
140 | |||
141 | JsonRpcProfileHandlers handler = new JsonRpcProfileHandlers(ServiceModule); | ||
142 | |||
143 | Server.AddJsonRPCHandler("avatarclassifiedsrequest", handler.AvatarClassifiedsRequest); | ||
144 | Server.AddJsonRPCHandler("classified_update", handler.ClassifiedUpdate); | ||
145 | Server.AddJsonRPCHandler("classifieds_info_query", handler.ClassifiedInfoRequest); | ||
146 | Server.AddJsonRPCHandler("classified_delete", handler.ClassifiedDelete); | ||
147 | Server.AddJsonRPCHandler("avatarpicksrequest", handler.AvatarPicksRequest); | ||
148 | Server.AddJsonRPCHandler("pickinforequest", handler.PickInfoRequest); | ||
149 | Server.AddJsonRPCHandler("picks_update", handler.PicksUpdate); | ||
150 | Server.AddJsonRPCHandler("picks_delete", handler.PicksDelete); | ||
151 | Server.AddJsonRPCHandler("avatarnotesrequest", handler.AvatarNotesRequest); | ||
152 | Server.AddJsonRPCHandler("avatar_notes_update", handler.NotesUpdate); | ||
153 | Server.AddJsonRPCHandler("avatar_properties_request", handler.AvatarPropertiesRequest); | ||
154 | Server.AddJsonRPCHandler("avatar_properties_update", handler.AvatarPropertiesUpdate); | ||
155 | Server.AddJsonRPCHandler("avatar_interests_update", handler.AvatarInterestsUpdate); | ||
156 | Server.AddJsonRPCHandler("image_assets_request", handler.AvatarImageAssetsRequest); | ||
157 | Server.AddJsonRPCHandler("user_data_request", handler.RequestUserAppData); | ||
158 | Server.AddJsonRPCHandler("user_data_update", handler.UpdateUserAppData); | ||
159 | |||
160 | } | ||
161 | |||
162 | #region ISharedRegionModule implementation | ||
163 | |||
164 | void ISharedRegionModule.PostInitialise() | ||
165 | { | ||
166 | if(!Enabled) | ||
167 | return; | ||
168 | } | ||
169 | |||
170 | #endregion | ||
171 | |||
172 | #region IRegionModuleBase implementation | ||
173 | |||
174 | void IRegionModuleBase.Initialise(IConfigSource source) | ||
175 | { | ||
176 | IConfig moduleConfig = source.Configs["Modules"]; | ||
177 | if (moduleConfig != null) | ||
178 | { | ||
179 | string name = moduleConfig.GetString("UserProfilesServices", ""); | ||
180 | if (name == Name) | ||
181 | { | ||
182 | InitialiseService(source); | ||
183 | m_log.Info("[LOCAL USERPROFILES SERVICE CONNECTOR]: Local user profiles connector enabled"); | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | |||
188 | void IRegionModuleBase.Close() | ||
189 | { | ||
190 | return; | ||
191 | } | ||
192 | |||
193 | void IRegionModuleBase.AddRegion(Scene scene) | ||
194 | { | ||
195 | if (!Enabled) | ||
196 | return; | ||
197 | |||
198 | lock (regions) | ||
199 | { | ||
200 | if (regions.ContainsKey(scene.RegionInfo.RegionID)) | ||
201 | m_log.ErrorFormat("[LOCAL USERPROFILES SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); | ||
202 | else | ||
203 | regions.Add(scene.RegionInfo.RegionID, scene); | ||
204 | } | ||
205 | } | ||
206 | |||
207 | void IRegionModuleBase.RemoveRegion(Scene scene) | ||
208 | { | ||
209 | if (!Enabled) | ||
210 | return; | ||
211 | |||
212 | lock (regions) | ||
213 | { | ||
214 | if (regions.ContainsKey(scene.RegionInfo.RegionID)) | ||
215 | regions.Remove(scene.RegionInfo.RegionID); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | void IRegionModuleBase.RegionLoaded(Scene scene) | ||
220 | { | ||
221 | if (!Enabled) | ||
222 | return; | ||
223 | } | ||
224 | #endregion | ||
225 | } | ||
226 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs index d221d68..9f58175 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs | |||
@@ -322,7 +322,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset | |||
322 | // a copy of the local asset. | 322 | // a copy of the local asset. |
323 | m_Cache.Cache(asset); | 323 | m_Cache.Cache(asset); |
324 | 324 | ||
325 | if (asset.Temporary || asset.Local) | 325 | if (asset.Local) |
326 | { | 326 | { |
327 | if (m_Cache != null) | 327 | if (m_Cache != null) |
328 | m_Cache.Cache(asset); | 328 | m_Cache.Cache(asset); |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs index 480cd69..52b1039 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs | |||
@@ -258,7 +258,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset | |||
258 | if (m_Cache != null) | 258 | if (m_Cache != null) |
259 | m_Cache.Cache(asset); | 259 | m_Cache.Cache(asset); |
260 | 260 | ||
261 | if (asset.Temporary || asset.Local) | 261 | if (asset.Local) |
262 | { | 262 | { |
263 | // m_log.DebugFormat( | 263 | // m_log.DebugFormat( |
264 | // "[LOCAL ASSET SERVICE CONNECTOR]: Returning asset {0} {1} without querying database since status Temporary = {2}, Local = {3}", | 264 | // "[LOCAL ASSET SERVICE CONNECTOR]: Returning asset {0} {1} without querying database since status Temporary = {2}, Local = {3}", |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs index 1982473..4f75191 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/Tests/AssetConnectorTests.cs | |||
@@ -42,7 +42,7 @@ using OpenSim.Tests.Common; | |||
42 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests | 42 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests |
43 | { | 43 | { |
44 | [TestFixture] | 44 | [TestFixture] |
45 | public class AssetConnectorsTests : OpenSimTestCase | 45 | public class AssetConnectorTests : OpenSimTestCase |
46 | { | 46 | { |
47 | [Test] | 47 | [Test] |
48 | public void TestAddAsset() | 48 | public void TestAddAsset() |
@@ -77,7 +77,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests | |||
77 | // TODO: Add cache and check that this does receive a copy of the asset | 77 | // TODO: Add cache and check that this does receive a copy of the asset |
78 | } | 78 | } |
79 | 79 | ||
80 | [Test] | ||
81 | public void TestAddTemporaryAsset() | 80 | public void TestAddTemporaryAsset() |
82 | { | 81 | { |
83 | TestHelpers.InMethod(); | 82 | TestHelpers.InMethod(); |
@@ -93,8 +92,45 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests | |||
93 | LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); | 92 | LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); |
94 | lasc.Initialise(config); | 93 | lasc.Initialise(config); |
95 | 94 | ||
95 | // If it is remote, it should be stored | ||
96 | AssetBase a2 = AssetHelpers.CreateNotecardAsset(); | ||
97 | a2.Local = false; | ||
98 | a2.Temporary = true; | ||
99 | |||
100 | lasc.Store(a2); | ||
101 | |||
102 | AssetBase retreivedA2 = lasc.Get(a2.ID); | ||
103 | Assert.That(retreivedA2.ID, Is.EqualTo(a2.ID)); | ||
104 | Assert.That(retreivedA2.Metadata.ID, Is.EqualTo(a2.Metadata.ID)); | ||
105 | Assert.That(retreivedA2.Data.Length, Is.EqualTo(a2.Data.Length)); | ||
106 | |||
107 | AssetMetadata retrievedA2Metadata = lasc.GetMetadata(a2.ID); | ||
108 | Assert.That(retrievedA2Metadata.ID, Is.EqualTo(a2.ID)); | ||
109 | |||
110 | byte[] retrievedA2Data = lasc.GetData(a2.ID); | ||
111 | Assert.That(retrievedA2Data.Length, Is.EqualTo(a2.Data.Length)); | ||
112 | |||
113 | // TODO: Add cache and check that this does receive a copy of the asset | ||
114 | } | ||
115 | |||
116 | [Test] | ||
117 | public void TestAddLocalAsset() | ||
118 | { | ||
119 | TestHelpers.InMethod(); | ||
120 | // TestHelpers.EnableLogging(); | ||
121 | |||
122 | IConfigSource config = new IniConfigSource(); | ||
123 | config.AddConfig("Modules"); | ||
124 | config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector"); | ||
125 | config.AddConfig("AssetService"); | ||
126 | config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService"); | ||
127 | config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); | ||
128 | |||
129 | LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); | ||
130 | lasc.Initialise(config); | ||
131 | |||
96 | AssetBase a1 = AssetHelpers.CreateNotecardAsset(); | 132 | AssetBase a1 = AssetHelpers.CreateNotecardAsset(); |
97 | a1.Temporary = true; | 133 | a1.Local = true; |
98 | 134 | ||
99 | lasc.Store(a1); | 135 | lasc.Store(a1); |
100 | 136 | ||
@@ -106,7 +142,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests | |||
106 | } | 142 | } |
107 | 143 | ||
108 | [Test] | 144 | [Test] |
109 | public void TestAddLocalAsset() | 145 | public void TestAddTemporaryLocalAsset() |
110 | { | 146 | { |
111 | TestHelpers.InMethod(); | 147 | TestHelpers.InMethod(); |
112 | // TestHelpers.EnableLogging(); | 148 | // TestHelpers.EnableLogging(); |
@@ -121,8 +157,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests | |||
121 | LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); | 157 | LocalAssetServicesConnector lasc = new LocalAssetServicesConnector(); |
122 | lasc.Initialise(config); | 158 | lasc.Initialise(config); |
123 | 159 | ||
160 | // If it is local, it should not be stored | ||
124 | AssetBase a1 = AssetHelpers.CreateNotecardAsset(); | 161 | AssetBase a1 = AssetHelpers.CreateNotecardAsset(); |
125 | a1.Local = true; | 162 | a1.Local = true; |
163 | a1.Temporary = true; | ||
126 | 164 | ||
127 | lasc.Store(a1); | 165 | lasc.Store(a1); |
128 | 166 | ||
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs index c0c2ca7..3849a3f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs | |||
@@ -56,6 +56,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
56 | 56 | ||
57 | public LocalGridServicesConnector() | 57 | public LocalGridServicesConnector() |
58 | { | 58 | { |
59 | m_log.Debug("[LOCAL GRID SERVICE CONNECTOR]: LocalGridServicesConnector no parms."); | ||
59 | } | 60 | } |
60 | 61 | ||
61 | public LocalGridServicesConnector(IConfigSource source) | 62 | public LocalGridServicesConnector(IConfigSource source) |
@@ -142,10 +143,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
142 | 143 | ||
143 | scene.RegisterModuleInterface<IGridService>(this); | 144 | scene.RegisterModuleInterface<IGridService>(this); |
144 | 145 | ||
145 | if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID)) | 146 | lock (m_LocalCache) |
146 | m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); | 147 | { |
147 | else | 148 | if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID)) |
148 | m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene)); | 149 | m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); |
150 | else | ||
151 | m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene)); | ||
152 | } | ||
149 | } | 153 | } |
150 | 154 | ||
151 | public void RemoveRegion(Scene scene) | 155 | public void RemoveRegion(Scene scene) |
@@ -153,8 +157,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
153 | if (!m_Enabled) | 157 | if (!m_Enabled) |
154 | return; | 158 | return; |
155 | 159 | ||
156 | m_LocalCache[scene.RegionInfo.RegionID].Clear(); | 160 | lock (m_LocalCache) |
157 | m_LocalCache.Remove(scene.RegionInfo.RegionID); | 161 | { |
162 | m_LocalCache[scene.RegionInfo.RegionID].Clear(); | ||
163 | m_LocalCache.Remove(scene.RegionInfo.RegionID); | ||
164 | } | ||
158 | } | 165 | } |
159 | 166 | ||
160 | public void RegionLoaded(Scene scene) | 167 | public void RegionLoaded(Scene scene) |
@@ -191,12 +198,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
191 | 198 | ||
192 | // First see if it's a neighbour, even if it isn't on this sim. | 199 | // First see if it's a neighbour, even if it isn't on this sim. |
193 | // Neighbour data is cached in memory, so this is fast | 200 | // Neighbour data is cached in memory, so this is fast |
194 | foreach (RegionCache rcache in m_LocalCache.Values) | 201 | |
202 | lock (m_LocalCache) | ||
195 | { | 203 | { |
196 | region = rcache.GetRegionByPosition(x, y); | 204 | foreach (RegionCache rcache in m_LocalCache.Values) |
197 | if (region != null) | ||
198 | { | 205 | { |
199 | return region; | 206 | region = rcache.GetRegionByPosition(x, y); |
207 | if (region != null) | ||
208 | { | ||
209 | return region; | ||
210 | } | ||
200 | } | 211 | } |
201 | } | 212 | } |
202 | 213 | ||
@@ -245,12 +256,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid | |||
245 | { | 256 | { |
246 | System.Text.StringBuilder caps = new System.Text.StringBuilder(); | 257 | System.Text.StringBuilder caps = new System.Text.StringBuilder(); |
247 | 258 | ||
248 | foreach (KeyValuePair<UUID, RegionCache> kvp in m_LocalCache) | 259 | lock (m_LocalCache) |
249 | { | 260 | { |
250 | caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); | 261 | foreach (KeyValuePair<UUID, RegionCache> kvp in m_LocalCache) |
251 | List<GridRegion> regions = kvp.Value.GetNeighbours(); | 262 | { |
252 | foreach (GridRegion r in regions) | 263 | caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); |
253 | caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize); | 264 | List<GridRegion> regions = kvp.Value.GetNeighbours(); |
265 | foreach (GridRegion r in regions) | ||
266 | caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize); | ||
267 | } | ||
254 | } | 268 | } |
255 | 269 | ||
256 | MainConsole.Instance.Output(caps.ToString()); | 270 | MainConsole.Instance.Output(caps.ToString()); |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index e474ef6..58576d1 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs | |||
@@ -233,6 +233,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
233 | if (sp != null) | 233 | if (sp != null) |
234 | { | 234 | { |
235 | AgentCircuitData aCircuit = scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); | 235 | AgentCircuitData aCircuit = scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); |
236 | if (aCircuit == null) | ||
237 | return; | ||
238 | if (aCircuit.ServiceURLs == null) | ||
239 | return; | ||
240 | |||
236 | if (aCircuit.ServiceURLs.ContainsKey("InventoryServerURI")) | 241 | if (aCircuit.ServiceURLs.ContainsKey("InventoryServerURI")) |
237 | { | 242 | { |
238 | inventoryURL = aCircuit.ServiceURLs["InventoryServerURI"].ToString(); | 243 | inventoryURL = aCircuit.ServiceURLs["InventoryServerURI"].ToString(); |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs index 1e434b9..2fc8ee3 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/InventoryCache.cs | |||
@@ -1,11 +1,41 @@ | |||
1 | using System; | 1 | /* |
2 | using System.Collections.Generic; | 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 | */ | ||
3 | 27 | ||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Threading; | ||
4 | using OpenSim.Framework; | 31 | using OpenSim.Framework; |
5 | using OpenMetaverse; | 32 | using OpenMetaverse; |
6 | 33 | ||
7 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | 34 | namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory |
8 | { | 35 | { |
36 | /// <summary> | ||
37 | /// Cache root and system inventory folders to reduce number of potentially remote inventory calls and associated holdups. | ||
38 | /// </summary> | ||
9 | public class InventoryCache | 39 | public class InventoryCache |
10 | { | 40 | { |
11 | private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour | 41 | private const double CACHE_EXPIRATION_SECONDS = 3600.0; // 1 hour |
@@ -16,8 +46,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
16 | 46 | ||
17 | public void Cache(UUID userID, InventoryFolderBase root) | 47 | public void Cache(UUID userID, InventoryFolderBase root) |
18 | { | 48 | { |
19 | lock (m_RootFolders) | 49 | m_RootFolders.AddOrUpdate(userID, root, CACHE_EXPIRATION_SECONDS); |
20 | m_RootFolders.AddOrUpdate(userID, root, CACHE_EXPIRATION_SECONDS); | ||
21 | } | 50 | } |
22 | 51 | ||
23 | public InventoryFolderBase GetRootFolder(UUID userID) | 52 | public InventoryFolderBase GetRootFolder(UUID userID) |
@@ -31,14 +60,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
31 | 60 | ||
32 | public void Cache(UUID userID, AssetType type, InventoryFolderBase folder) | 61 | public void Cache(UUID userID, AssetType type, InventoryFolderBase folder) |
33 | { | 62 | { |
34 | lock (m_FolderTypes) | 63 | Dictionary<AssetType, InventoryFolderBase> ff = null; |
64 | if (!m_FolderTypes.TryGetValue(userID, out ff)) | ||
65 | { | ||
66 | ff = new Dictionary<AssetType, InventoryFolderBase>(); | ||
67 | m_FolderTypes.Add(userID, ff, CACHE_EXPIRATION_SECONDS); | ||
68 | } | ||
69 | |||
70 | // We need to lock here since two threads could potentially retrieve the same dictionary | ||
71 | // and try to add a folder for that type simultaneously. Dictionary<>.Add() is not described as thread-safe in the SDK | ||
72 | // even if the folders are identical. | ||
73 | lock (ff) | ||
35 | { | 74 | { |
36 | Dictionary<AssetType, InventoryFolderBase> ff = null; | ||
37 | if (!m_FolderTypes.TryGetValue(userID, out ff)) | ||
38 | { | ||
39 | ff = new Dictionary<AssetType, InventoryFolderBase>(); | ||
40 | m_FolderTypes.Add(userID, ff, CACHE_EXPIRATION_SECONDS); | ||
41 | } | ||
42 | if (!ff.ContainsKey(type)) | 75 | if (!ff.ContainsKey(type)) |
43 | ff.Add(type, folder); | 76 | ff.Add(type, folder); |
44 | } | 77 | } |
@@ -50,8 +83,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
50 | if (m_FolderTypes.TryGetValue(userID, out ff)) | 83 | if (m_FolderTypes.TryGetValue(userID, out ff)) |
51 | { | 84 | { |
52 | InventoryFolderBase f = null; | 85 | InventoryFolderBase f = null; |
53 | if (ff.TryGetValue(type, out f)) | 86 | |
54 | return f; | 87 | lock (ff) |
88 | { | ||
89 | if (ff.TryGetValue(type, out f)) | ||
90 | return f; | ||
91 | } | ||
55 | } | 92 | } |
56 | 93 | ||
57 | return null; | 94 | return null; |
@@ -59,8 +96,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory | |||
59 | 96 | ||
60 | public void Cache(UUID userID, InventoryCollection inv) | 97 | public void Cache(UUID userID, InventoryCollection inv) |
61 | { | 98 | { |
62 | lock (m_Inventories) | 99 | m_Inventories.AddOrUpdate(userID, inv, 120); |
63 | m_Inventories.AddOrUpdate(userID, inv, 120); | ||
64 | } | 100 | } |
65 | 101 | ||
66 | public InventoryCollection GetUserInventory(UUID userID) | 102 | public InventoryCollection GetUserInventory(UUID userID) |
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 8b8bb37..e4aa7bc 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs | |||
@@ -322,7 +322,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation | |||
322 | // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", | 322 | // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", |
323 | // s.RegionInfo.RegionName, destination.RegionHandle); | 323 | // s.RegionInfo.RegionName, destination.RegionHandle); |
324 | 324 | ||
325 | Util.FireAndForget(delegate { m_scenes[destination.RegionID].IncomingCloseAgent(id, false); }); | 325 | m_scenes[destination.RegionID].IncomingCloseAgent(id, false); |
326 | return true; | 326 | return true; |
327 | } | 327 | } |
328 | //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent"); | 328 | //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent"); |
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs new file mode 100644 index 0000000..73e706c --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateConnector.cs | |||
@@ -0,0 +1,218 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | |||
32 | using OpenSim.Services.Interfaces; | ||
33 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
34 | using OpenSim.Server.Base; | ||
35 | using OpenSim.Framework.Servers.HttpServer; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | |||
39 | using OpenMetaverse; | ||
40 | using log4net; | ||
41 | |||
42 | namespace OpenSim.Region.CoreModules.World.Estate | ||
43 | { | ||
44 | public class EstateConnector | ||
45 | { | ||
46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | protected XEstateModule m_EstateModule; | ||
49 | |||
50 | public EstateConnector(XEstateModule module) | ||
51 | { | ||
52 | m_EstateModule = module; | ||
53 | } | ||
54 | |||
55 | public void SendTeleportHomeOneUser(uint EstateID, UUID PreyID) | ||
56 | { | ||
57 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
58 | sendData["METHOD"] = "teleport_home_one_user"; | ||
59 | |||
60 | sendData["EstateID"] = EstateID.ToString(); | ||
61 | sendData["PreyID"] = PreyID.ToString(); | ||
62 | |||
63 | SendToEstate(EstateID, sendData); | ||
64 | } | ||
65 | |||
66 | public void SendTeleportHomeAllUsers(uint EstateID) | ||
67 | { | ||
68 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
69 | sendData["METHOD"] = "teleport_home_all_users"; | ||
70 | |||
71 | sendData["EstateID"] = EstateID.ToString(); | ||
72 | |||
73 | SendToEstate(EstateID, sendData); | ||
74 | } | ||
75 | |||
76 | public bool SendUpdateCovenant(uint EstateID, UUID CovenantID) | ||
77 | { | ||
78 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
79 | sendData["METHOD"] = "update_covenant"; | ||
80 | |||
81 | sendData["CovenantID"] = CovenantID.ToString(); | ||
82 | sendData["EstateID"] = EstateID.ToString(); | ||
83 | |||
84 | // Handle local regions locally | ||
85 | // | ||
86 | foreach (Scene s in m_EstateModule.Scenes) | ||
87 | { | ||
88 | if (s.RegionInfo.EstateSettings.EstateID == EstateID) | ||
89 | s.RegionInfo.RegionSettings.Covenant = CovenantID; | ||
90 | // s.ReloadEstateData(); | ||
91 | } | ||
92 | |||
93 | SendToEstate(EstateID, sendData); | ||
94 | |||
95 | return true; | ||
96 | } | ||
97 | |||
98 | public bool SendUpdateEstate(uint EstateID) | ||
99 | { | ||
100 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
101 | sendData["METHOD"] = "update_estate"; | ||
102 | |||
103 | sendData["EstateID"] = EstateID.ToString(); | ||
104 | |||
105 | // Handle local regions locally | ||
106 | // | ||
107 | foreach (Scene s in m_EstateModule.Scenes) | ||
108 | { | ||
109 | if (s.RegionInfo.EstateSettings.EstateID == EstateID) | ||
110 | s.ReloadEstateData(); | ||
111 | } | ||
112 | |||
113 | SendToEstate(EstateID, sendData); | ||
114 | |||
115 | return true; | ||
116 | } | ||
117 | |||
118 | public void SendEstateMessage(uint EstateID, UUID FromID, string FromName, string Message) | ||
119 | { | ||
120 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
121 | sendData["METHOD"] = "estate_message"; | ||
122 | |||
123 | sendData["EstateID"] = EstateID.ToString(); | ||
124 | sendData["FromID"] = FromID.ToString(); | ||
125 | sendData["FromName"] = FromName; | ||
126 | sendData["Message"] = Message; | ||
127 | |||
128 | SendToEstate(EstateID, sendData); | ||
129 | } | ||
130 | |||
131 | private void SendToEstate(uint EstateID, Dictionary<string, object> sendData) | ||
132 | { | ||
133 | List<UUID> regions = m_EstateModule.Scenes[0].GetEstateRegions((int)EstateID); | ||
134 | |||
135 | UUID ScopeID = UUID.Zero; | ||
136 | |||
137 | // Handle local regions locally | ||
138 | // | ||
139 | lock (m_EstateModule.Scenes) | ||
140 | { | ||
141 | foreach (Scene s in m_EstateModule.Scenes) | ||
142 | { | ||
143 | if (regions.Contains(s.RegionInfo.RegionID)) | ||
144 | { | ||
145 | // All regions in one estate are in the same scope. | ||
146 | // Use that scope. | ||
147 | // | ||
148 | ScopeID = s.RegionInfo.ScopeID; | ||
149 | regions.Remove(s.RegionInfo.RegionID); | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | |||
154 | // Our own region should always be in the above list. | ||
155 | // In a standalone this would not be true. But then, | ||
156 | // Scope ID is not relevat there. Use first scope. | ||
157 | // | ||
158 | if (ScopeID == UUID.Zero) | ||
159 | ScopeID = m_EstateModule.Scenes[0].RegionInfo.ScopeID; | ||
160 | |||
161 | // Don't send to the same instance twice | ||
162 | // | ||
163 | List<string> done = new List<string>(); | ||
164 | |||
165 | // Send to remote regions | ||
166 | // | ||
167 | foreach (UUID regionID in regions) | ||
168 | { | ||
169 | GridRegion region = m_EstateModule.Scenes[0].GridService.GetRegionByUUID(ScopeID, regionID); | ||
170 | if (region != null) | ||
171 | { | ||
172 | string url = "http://" + region.ExternalHostName + ":" + region.HttpPort; | ||
173 | if (done.Contains(url)) | ||
174 | continue; | ||
175 | |||
176 | Call(region, sendData); | ||
177 | done.Add(url); | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | private bool Call(GridRegion region, Dictionary<string, object> sendData) | ||
183 | { | ||
184 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
185 | // m_log.DebugFormat("[XESTATE CONNECTOR]: queryString = {0}", reqString); | ||
186 | try | ||
187 | { | ||
188 | string url = "http://" + region.ExternalHostName + ":" + region.HttpPort; | ||
189 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
190 | url + "/estate", | ||
191 | reqString); | ||
192 | if (reply != string.Empty) | ||
193 | { | ||
194 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
195 | |||
196 | if (replyData.ContainsKey("RESULT")) | ||
197 | { | ||
198 | if (replyData["RESULT"].ToString().ToLower() == "true") | ||
199 | return true; | ||
200 | else | ||
201 | return false; | ||
202 | } | ||
203 | else | ||
204 | m_log.DebugFormat("[XESTATE CONNECTOR]: reply data does not contain result field"); | ||
205 | |||
206 | } | ||
207 | else | ||
208 | m_log.DebugFormat("[XESTATE CONNECTOR]: received empty reply"); | ||
209 | } | ||
210 | catch (Exception e) | ||
211 | { | ||
212 | m_log.DebugFormat("[XESTATE CONNECTOR]: Exception when contacting remote sim: {0}", e.Message); | ||
213 | } | ||
214 | |||
215 | return false; | ||
216 | } | ||
217 | } | ||
218 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs new file mode 100644 index 0000000..f54ab2c --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateModule.cs | |||
@@ -0,0 +1,256 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | using Nini.Config; | ||
34 | using Nwc.XmlRpc; | ||
35 | using OpenMetaverse; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Communications; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using OpenSim.Server.Base; | ||
42 | using OpenSim.Framework.Servers; | ||
43 | using OpenSim.Framework.Servers.HttpServer; | ||
44 | using Mono.Addins; | ||
45 | |||
46 | namespace OpenSim.Region.CoreModules.World.Estate | ||
47 | { | ||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XEstate")] | ||
49 | public class XEstateModule : ISharedRegionModule | ||
50 | { | ||
51 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
52 | |||
53 | protected List<Scene> m_Scenes = new List<Scene>(); | ||
54 | protected bool m_InInfoUpdate = false; | ||
55 | |||
56 | public bool InInfoUpdate | ||
57 | { | ||
58 | get { return m_InInfoUpdate; } | ||
59 | set { m_InInfoUpdate = value; } | ||
60 | } | ||
61 | |||
62 | public List<Scene> Scenes | ||
63 | { | ||
64 | get { return m_Scenes; } | ||
65 | } | ||
66 | |||
67 | protected EstateConnector m_EstateConnector; | ||
68 | |||
69 | public void Initialise(IConfigSource config) | ||
70 | { | ||
71 | int port = 0; | ||
72 | |||
73 | IConfig estateConfig = config.Configs["Estate"]; | ||
74 | if (estateConfig != null) | ||
75 | { | ||
76 | port = estateConfig.GetInt("Port", 0); | ||
77 | } | ||
78 | |||
79 | m_EstateConnector = new EstateConnector(this); | ||
80 | |||
81 | // Instantiate the request handler | ||
82 | IHttpServer server = MainServer.GetHttpServer((uint)port); | ||
83 | server.AddStreamHandler(new EstateRequestHandler(this)); | ||
84 | } | ||
85 | |||
86 | public void PostInitialise() | ||
87 | { | ||
88 | } | ||
89 | |||
90 | public void Close() | ||
91 | { | ||
92 | } | ||
93 | |||
94 | public void AddRegion(Scene scene) | ||
95 | { | ||
96 | lock (m_Scenes) | ||
97 | m_Scenes.Add(scene); | ||
98 | |||
99 | scene.EventManager.OnNewClient += OnNewClient; | ||
100 | } | ||
101 | |||
102 | public void RegionLoaded(Scene scene) | ||
103 | { | ||
104 | IEstateModule em = scene.RequestModuleInterface<IEstateModule>(); | ||
105 | |||
106 | em.OnRegionInfoChange += OnRegionInfoChange; | ||
107 | em.OnEstateInfoChange += OnEstateInfoChange; | ||
108 | em.OnEstateMessage += OnEstateMessage; | ||
109 | } | ||
110 | |||
111 | public void RemoveRegion(Scene scene) | ||
112 | { | ||
113 | scene.EventManager.OnNewClient -= OnNewClient; | ||
114 | |||
115 | lock (m_Scenes) | ||
116 | m_Scenes.Remove(scene); | ||
117 | } | ||
118 | |||
119 | public string Name | ||
120 | { | ||
121 | get { return "EstateModule"; } | ||
122 | } | ||
123 | |||
124 | public Type ReplaceableInterface | ||
125 | { | ||
126 | get { return null; } | ||
127 | } | ||
128 | |||
129 | private Scene FindScene(UUID RegionID) | ||
130 | { | ||
131 | foreach (Scene s in Scenes) | ||
132 | { | ||
133 | if (s.RegionInfo.RegionID == RegionID) | ||
134 | return s; | ||
135 | } | ||
136 | |||
137 | return null; | ||
138 | } | ||
139 | |||
140 | private void OnRegionInfoChange(UUID RegionID) | ||
141 | { | ||
142 | Scene s = FindScene(RegionID); | ||
143 | if (s == null) | ||
144 | return; | ||
145 | |||
146 | if (!m_InInfoUpdate) | ||
147 | m_EstateConnector.SendUpdateCovenant(s.RegionInfo.EstateSettings.EstateID, s.RegionInfo.RegionSettings.Covenant); | ||
148 | } | ||
149 | |||
150 | private void OnEstateInfoChange(UUID RegionID) | ||
151 | { | ||
152 | Scene s = FindScene(RegionID); | ||
153 | if (s == null) | ||
154 | return; | ||
155 | |||
156 | if (!m_InInfoUpdate) | ||
157 | m_EstateConnector.SendUpdateEstate(s.RegionInfo.EstateSettings.EstateID); | ||
158 | } | ||
159 | |||
160 | private void OnEstateMessage(UUID RegionID, UUID FromID, string FromName, string Message) | ||
161 | { | ||
162 | Scene senderScenes = FindScene(RegionID); | ||
163 | if (senderScenes == null) | ||
164 | return; | ||
165 | |||
166 | uint estateID = senderScenes.RegionInfo.EstateSettings.EstateID; | ||
167 | |||
168 | foreach (Scene s in Scenes) | ||
169 | { | ||
170 | if (s.RegionInfo.EstateSettings.EstateID == estateID) | ||
171 | { | ||
172 | IDialogModule dm = s.RequestModuleInterface<IDialogModule>(); | ||
173 | |||
174 | if (dm != null) | ||
175 | { | ||
176 | dm.SendNotificationToUsersInRegion(FromID, FromName, | ||
177 | Message); | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | if (!m_InInfoUpdate) | ||
182 | m_EstateConnector.SendEstateMessage(estateID, FromID, FromName, Message); | ||
183 | } | ||
184 | |||
185 | private void OnNewClient(IClientAPI client) | ||
186 | { | ||
187 | client.OnEstateTeleportOneUserHomeRequest += OnEstateTeleportOneUserHomeRequest; | ||
188 | client.OnEstateTeleportAllUsersHomeRequest += OnEstateTeleportAllUsersHomeRequest; | ||
189 | |||
190 | } | ||
191 | |||
192 | private void OnEstateTeleportOneUserHomeRequest(IClientAPI client, UUID invoice, UUID senderID, UUID prey) | ||
193 | { | ||
194 | if (prey == UUID.Zero) | ||
195 | return; | ||
196 | |||
197 | if (!(client.Scene is Scene)) | ||
198 | return; | ||
199 | |||
200 | Scene scene = (Scene)client.Scene; | ||
201 | |||
202 | uint estateID = scene.RegionInfo.EstateSettings.EstateID; | ||
203 | |||
204 | if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false)) | ||
205 | return; | ||
206 | |||
207 | foreach (Scene s in Scenes) | ||
208 | { | ||
209 | if (s == scene) | ||
210 | continue; // Already handles by estate module | ||
211 | if (s.RegionInfo.EstateSettings.EstateID != estateID) | ||
212 | continue; | ||
213 | |||
214 | ScenePresence p = scene.GetScenePresence(prey); | ||
215 | if (p != null && !p.IsChildAgent) | ||
216 | { | ||
217 | p.ControllingClient.SendTeleportStart(16); | ||
218 | scene.TeleportClientHome(prey, p.ControllingClient); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | m_EstateConnector.SendTeleportHomeOneUser(estateID, prey); | ||
223 | } | ||
224 | |||
225 | private void OnEstateTeleportAllUsersHomeRequest(IClientAPI client, UUID invoice, UUID senderID) | ||
226 | { | ||
227 | if (!(client.Scene is Scene)) | ||
228 | return; | ||
229 | |||
230 | Scene scene = (Scene)client.Scene; | ||
231 | |||
232 | uint estateID = scene.RegionInfo.EstateSettings.EstateID; | ||
233 | |||
234 | if (!scene.Permissions.CanIssueEstateCommand(client.AgentId, false)) | ||
235 | return; | ||
236 | |||
237 | foreach (Scene s in Scenes) | ||
238 | { | ||
239 | if (s == scene) | ||
240 | continue; // Already handles by estate module | ||
241 | if (s.RegionInfo.EstateSettings.EstateID != estateID) | ||
242 | continue; | ||
243 | |||
244 | scene.ForEachScenePresence(delegate(ScenePresence p) { | ||
245 | if (p != null && !p.IsChildAgent) | ||
246 | { | ||
247 | p.ControllingClient.SendTeleportStart(16); | ||
248 | scene.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient); | ||
249 | } | ||
250 | }); | ||
251 | } | ||
252 | |||
253 | m_EstateConnector.SendTeleportHomeAllUsers(estateID); | ||
254 | } | ||
255 | } | ||
256 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs new file mode 100644 index 0000000..eb74cda --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Estate/XEstateRequestHandler.cs | |||
@@ -0,0 +1,298 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Xml; | ||
33 | |||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Server.Base; | ||
36 | using OpenSim.Framework.Servers.HttpServer; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | |||
40 | using OpenMetaverse; | ||
41 | using log4net; | ||
42 | |||
43 | namespace OpenSim.Region.CoreModules.World.Estate | ||
44 | { | ||
45 | public class EstateRequestHandler : BaseStreamHandler | ||
46 | { | ||
47 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | protected XEstateModule m_EstateModule; | ||
50 | protected Object m_RequestLock = new Object(); | ||
51 | |||
52 | public EstateRequestHandler(XEstateModule fmodule) | ||
53 | : base("POST", "/estate") | ||
54 | { | ||
55 | m_EstateModule = fmodule; | ||
56 | } | ||
57 | |||
58 | public override byte[] Handle(string path, Stream requestData, | ||
59 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
60 | { | ||
61 | StreamReader sr = new StreamReader(requestData); | ||
62 | string body = sr.ReadToEnd(); | ||
63 | sr.Close(); | ||
64 | body = body.Trim(); | ||
65 | |||
66 | m_log.DebugFormat("[XESTATE HANDLER]: query String: {0}", body); | ||
67 | |||
68 | try | ||
69 | { | ||
70 | lock (m_RequestLock) | ||
71 | { | ||
72 | Dictionary<string, object> request = | ||
73 | ServerUtils.ParseQueryString(body); | ||
74 | |||
75 | if (!request.ContainsKey("METHOD")) | ||
76 | return FailureResult(); | ||
77 | |||
78 | string method = request["METHOD"].ToString(); | ||
79 | request.Remove("METHOD"); | ||
80 | |||
81 | try | ||
82 | { | ||
83 | m_EstateModule.InInfoUpdate = false; | ||
84 | |||
85 | switch (method) | ||
86 | { | ||
87 | case "update_covenant": | ||
88 | return UpdateCovenant(request); | ||
89 | case "update_estate": | ||
90 | return UpdateEstate(request); | ||
91 | case "estate_message": | ||
92 | return EstateMessage(request); | ||
93 | case "teleport_home_one_user": | ||
94 | return TeleportHomeOneUser(request); | ||
95 | case "teleport_home_all_users": | ||
96 | return TeleportHomeAllUsers(request); | ||
97 | } | ||
98 | } | ||
99 | finally | ||
100 | { | ||
101 | m_EstateModule.InInfoUpdate = false; | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | catch (Exception e) | ||
106 | { | ||
107 | m_log.Debug("[XESTATE]: Exception {0}" + e.ToString()); | ||
108 | } | ||
109 | |||
110 | return FailureResult(); | ||
111 | } | ||
112 | |||
113 | byte[] TeleportHomeAllUsers(Dictionary<string, object> request) | ||
114 | { | ||
115 | UUID PreyID = UUID.Zero; | ||
116 | int EstateID = 0; | ||
117 | |||
118 | if (!request.ContainsKey("EstateID")) | ||
119 | return FailureResult(); | ||
120 | |||
121 | if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) | ||
122 | return FailureResult(); | ||
123 | |||
124 | foreach (Scene s in m_EstateModule.Scenes) | ||
125 | { | ||
126 | if (s.RegionInfo.EstateSettings.EstateID == EstateID) | ||
127 | { | ||
128 | s.ForEachScenePresence(delegate(ScenePresence p) { | ||
129 | if (p != null && !p.IsChildAgent) | ||
130 | { | ||
131 | p.ControllingClient.SendTeleportStart(16); | ||
132 | s.TeleportClientHome(p.ControllingClient.AgentId, p.ControllingClient); | ||
133 | } | ||
134 | }); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | return SuccessResult(); | ||
139 | } | ||
140 | |||
141 | byte[] TeleportHomeOneUser(Dictionary<string, object> request) | ||
142 | { | ||
143 | UUID PreyID = UUID.Zero; | ||
144 | int EstateID = 0; | ||
145 | |||
146 | if (!request.ContainsKey("PreyID") || | ||
147 | !request.ContainsKey("EstateID")) | ||
148 | { | ||
149 | return FailureResult(); | ||
150 | } | ||
151 | |||
152 | if (!UUID.TryParse(request["PreyID"].ToString(), out PreyID)) | ||
153 | return FailureResult(); | ||
154 | |||
155 | if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) | ||
156 | return FailureResult(); | ||
157 | |||
158 | foreach (Scene s in m_EstateModule.Scenes) | ||
159 | { | ||
160 | if (s.RegionInfo.EstateSettings.EstateID == EstateID) | ||
161 | { | ||
162 | ScenePresence p = s.GetScenePresence(PreyID); | ||
163 | if (p != null && !p.IsChildAgent) | ||
164 | { | ||
165 | p.ControllingClient.SendTeleportStart(16); | ||
166 | s.TeleportClientHome(PreyID, p.ControllingClient); | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | return SuccessResult(); | ||
172 | } | ||
173 | |||
174 | byte[] EstateMessage(Dictionary<string, object> request) | ||
175 | { | ||
176 | UUID FromID = UUID.Zero; | ||
177 | string FromName = String.Empty; | ||
178 | string Message = String.Empty; | ||
179 | int EstateID = 0; | ||
180 | |||
181 | if (!request.ContainsKey("FromID") || | ||
182 | !request.ContainsKey("FromName") || | ||
183 | !request.ContainsKey("Message") || | ||
184 | !request.ContainsKey("EstateID")) | ||
185 | { | ||
186 | return FailureResult(); | ||
187 | } | ||
188 | |||
189 | if (!UUID.TryParse(request["FromID"].ToString(), out FromID)) | ||
190 | return FailureResult(); | ||
191 | |||
192 | if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) | ||
193 | return FailureResult(); | ||
194 | |||
195 | FromName = request["FromName"].ToString(); | ||
196 | Message = request["Message"].ToString(); | ||
197 | |||
198 | foreach (Scene s in m_EstateModule.Scenes) | ||
199 | { | ||
200 | if (s.RegionInfo.EstateSettings.EstateID == EstateID) | ||
201 | { | ||
202 | IDialogModule dm = s.RequestModuleInterface<IDialogModule>(); | ||
203 | |||
204 | if (dm != null) | ||
205 | { | ||
206 | dm.SendNotificationToUsersInRegion(FromID, FromName, | ||
207 | Message); | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | |||
212 | return SuccessResult(); | ||
213 | } | ||
214 | |||
215 | byte[] UpdateCovenant(Dictionary<string, object> request) | ||
216 | { | ||
217 | UUID CovenantID = UUID.Zero; | ||
218 | int EstateID = 0; | ||
219 | |||
220 | if (!request.ContainsKey("CovenantID") || !request.ContainsKey("EstateID")) | ||
221 | return FailureResult(); | ||
222 | |||
223 | if (!UUID.TryParse(request["CovenantID"].ToString(), out CovenantID)) | ||
224 | return FailureResult(); | ||
225 | |||
226 | if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) | ||
227 | return FailureResult(); | ||
228 | |||
229 | foreach (Scene s in m_EstateModule.Scenes) | ||
230 | { | ||
231 | if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID) | ||
232 | s.RegionInfo.RegionSettings.Covenant = CovenantID; | ||
233 | } | ||
234 | |||
235 | return SuccessResult(); | ||
236 | } | ||
237 | |||
238 | byte[] UpdateEstate(Dictionary<string, object> request) | ||
239 | { | ||
240 | int EstateID = 0; | ||
241 | |||
242 | if (!request.ContainsKey("EstateID")) | ||
243 | return FailureResult(); | ||
244 | if (!Int32.TryParse(request["EstateID"].ToString(), out EstateID)) | ||
245 | return FailureResult(); | ||
246 | |||
247 | foreach (Scene s in m_EstateModule.Scenes) | ||
248 | { | ||
249 | if (s.RegionInfo.EstateSettings.EstateID == (uint)EstateID) | ||
250 | s.ReloadEstateData(); | ||
251 | } | ||
252 | return SuccessResult(); | ||
253 | } | ||
254 | |||
255 | private byte[] FailureResult() | ||
256 | { | ||
257 | return BoolResult(false); | ||
258 | } | ||
259 | |||
260 | private byte[] SuccessResult() | ||
261 | { | ||
262 | return BoolResult(true); | ||
263 | } | ||
264 | |||
265 | private byte[] BoolResult(bool value) | ||
266 | { | ||
267 | XmlDocument doc = new XmlDocument(); | ||
268 | |||
269 | XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, | ||
270 | "", ""); | ||
271 | |||
272 | doc.AppendChild(xmlnode); | ||
273 | |||
274 | XmlElement rootElement = doc.CreateElement("", "ServerResponse", | ||
275 | ""); | ||
276 | |||
277 | doc.AppendChild(rootElement); | ||
278 | |||
279 | XmlElement result = doc.CreateElement("", "RESULT", ""); | ||
280 | result.AppendChild(doc.CreateTextNode(value.ToString())); | ||
281 | |||
282 | rootElement.AppendChild(result); | ||
283 | |||
284 | return DocToBytes(doc); | ||
285 | } | ||
286 | |||
287 | private byte[] DocToBytes(XmlDocument doc) | ||
288 | { | ||
289 | MemoryStream ms = new MemoryStream(); | ||
290 | XmlTextWriter xw = new XmlTextWriter(ms, null); | ||
291 | xw.Formatting = Formatting.Indented; | ||
292 | doc.WriteTo(xw); | ||
293 | xw.Flush(); | ||
294 | |||
295 | return ms.ToArray(); | ||
296 | } | ||
297 | } | ||
298 | } | ||
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index c307998..dbc9296 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs | |||
@@ -74,6 +74,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
74 | 74 | ||
75 | protected IUserManagement m_userManager; | 75 | protected IUserManagement m_userManager; |
76 | protected IPrimCountModule m_primCountModule; | 76 | protected IPrimCountModule m_primCountModule; |
77 | protected IDialogModule m_Dialog; | ||
77 | 78 | ||
78 | // Minimum for parcels to work is 64m even if we don't actually use them. | 79 | // Minimum for parcels to work is 64m even if we don't actually use them. |
79 | #pragma warning disable 0429 | 80 | #pragma warning disable 0429 |
@@ -161,6 +162,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
161 | { | 162 | { |
162 | m_userManager = m_scene.RequestModuleInterface<IUserManagement>(); | 163 | m_userManager = m_scene.RequestModuleInterface<IUserManagement>(); |
163 | m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>(); | 164 | m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>(); |
165 | m_Dialog = m_scene.RequestModuleInterface<IDialogModule>(); | ||
164 | } | 166 | } |
165 | 167 | ||
166 | public void RemoveRegion(Scene scene) | 168 | public void RemoveRegion(Scene scene) |
@@ -213,6 +215,7 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
213 | client.OnPreAgentUpdate += ClientOnPreAgentUpdate; | 215 | client.OnPreAgentUpdate += ClientOnPreAgentUpdate; |
214 | client.OnParcelEjectUser += ClientOnParcelEjectUser; | 216 | client.OnParcelEjectUser += ClientOnParcelEjectUser; |
215 | client.OnParcelFreezeUser += ClientOnParcelFreezeUser; | 217 | client.OnParcelFreezeUser += ClientOnParcelFreezeUser; |
218 | client.OnSetStartLocationRequest += ClientOnSetHome; | ||
216 | 219 | ||
217 | EntityBase presenceEntity; | 220 | EntityBase presenceEntity; |
218 | if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) | 221 | if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) |
@@ -1896,7 +1899,53 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
1896 | land.LandData.ParcelAccessList.Add(entry); | 1899 | land.LandData.ParcelAccessList.Add(entry); |
1897 | } | 1900 | } |
1898 | } | 1901 | } |
1899 | 1902 | ||
1903 | /// <summary> | ||
1904 | /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in | ||
1905 | /// </summary> | ||
1906 | /// <param name="remoteClient"></param> | ||
1907 | /// <param name="regionHandle"></param> | ||
1908 | /// <param name="position"></param> | ||
1909 | /// <param name="lookAt"></param> | ||
1910 | /// <param name="flags"></param> | ||
1911 | public virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) | ||
1912 | { | ||
1913 | // Let's find the parcel in question | ||
1914 | ILandObject land = landChannel.GetLandObject(position); | ||
1915 | if (land == null || m_scene.GridUserService == null) | ||
1916 | { | ||
1917 | m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed."); | ||
1918 | return; | ||
1919 | } | ||
1920 | |||
1921 | // Gather some data | ||
1922 | ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID); | ||
1923 | SceneObjectGroup telehub = null; | ||
1924 | if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero) | ||
1925 | // Does the telehub exist in the scene? | ||
1926 | telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject); | ||
1927 | |||
1928 | // Can the user set home here? | ||
1929 | if (// (a) gods and land managers can set home | ||
1930 | m_scene.Permissions.IsAdministrator(remoteClient.AgentId) || | ||
1931 | m_scene.Permissions.IsGod(remoteClient.AgentId) || | ||
1932 | // (b) land owners can set home | ||
1933 | remoteClient.AgentId == land.LandData.OwnerID || | ||
1934 | // (c) members of the land-associated group in roles that can set home | ||
1935 | ((gpowers & (ulong)GroupPowers.AllowSetHome) == (ulong)GroupPowers.AllowSetHome) || | ||
1936 | // (d) parcels with telehubs can be the home of anyone | ||
1937 | (telehub != null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y))) | ||
1938 | { | ||
1939 | if (m_scene.GridUserService.SetHome(remoteClient.AgentId.ToString(), land.RegionUUID, position, lookAt)) | ||
1940 | // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. | ||
1941 | m_Dialog.SendAlertToUser(remoteClient, "Home position set."); | ||
1942 | else | ||
1943 | m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed."); | ||
1944 | } | ||
1945 | else | ||
1946 | m_Dialog.SendAlertToUser(remoteClient, "You are not allowed to set your home location in this parcel."); | ||
1947 | } | ||
1948 | |||
1900 | protected void InstallInterfaces() | 1949 | protected void InstallInterfaces() |
1901 | { | 1950 | { |
1902 | Command clearCommand | 1951 | Command clearCommand |
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 07d00c0..31f8a3f 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs | |||
@@ -249,13 +249,6 @@ namespace OpenSim.Region.CoreModules.World.Land | |||
249 | if (estateModule != null) | 249 | if (estateModule != null) |
250 | regionFlags = estateModule.GetRegionFlags(); | 250 | regionFlags = estateModule.GetRegionFlags(); |
251 | 251 | ||
252 | // In a perfect world, this would have worked. | ||
253 | // | ||
254 | // if ((landData.Flags & (uint)ParcelFlags.AllowLandmark) != 0) | ||
255 | // regionFlags |= (uint)RegionFlags.AllowLandmark; | ||
256 | // if (landData.OwnerID == remote_client.AgentId) | ||
257 | // regionFlags |= (uint)RegionFlags.AllowSetHome; | ||
258 | |||
259 | int seq_id; | 252 | int seq_id; |
260 | if (snap_selection && (sequence_id == 0)) | 253 | if (snap_selection && (sequence_id == 0)) |
261 | { | 254 | { |
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 79dd4a0..f8e93e1 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs | |||
@@ -1453,6 +1453,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions | |||
1453 | 1453 | ||
1454 | bool permission = false; | 1454 | bool permission = false; |
1455 | 1455 | ||
1456 | // m_log.DebugFormat("[PERMISSIONS MODULE]: Checking rez object at {0} in {1}", objectPosition, m_scene.Name); | ||
1457 | |||
1456 | ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); | 1458 | ILandObject land = m_scene.LandChannel.GetLandObject(objectPosition.X, objectPosition.Y); |
1457 | if (land == null) return false; | 1459 | if (land == null) return false; |
1458 | 1460 | ||
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs index 883045a..d093224 100644 --- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs +++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs | |||
@@ -369,6 +369,15 @@ namespace OpenSim.Region.CoreModules.World.Sound | |||
369 | }); | 369 | }); |
370 | } | 370 | } |
371 | 371 | ||
372 | public void SetSoundQueueing(UUID objectID, bool shouldQueue) | ||
373 | { | ||
374 | SceneObjectPart part; | ||
375 | if (!m_scene.TryGetSceneObjectPart(objectID, out part)) | ||
376 | return; | ||
377 | |||
378 | part.SoundQueueing = shouldQueue; | ||
379 | } | ||
380 | |||
372 | #endregion | 381 | #endregion |
373 | } | 382 | } |
374 | } | 383 | } |
diff --git a/OpenSim/Region/DataSnapshot/DataRequestHandler.cs b/OpenSim/Region/DataSnapshot/DataRequestHandler.cs index 32e93b4..50276ae 100644 --- a/OpenSim/Region/DataSnapshot/DataRequestHandler.cs +++ b/OpenSim/Region/DataSnapshot/DataRequestHandler.cs | |||
@@ -63,7 +63,7 @@ namespace OpenSim.Region.DataSnapshot | |||
63 | 63 | ||
64 | public Hashtable OnGetSnapshot(Hashtable keysvals) | 64 | public Hashtable OnGetSnapshot(Hashtable keysvals) |
65 | { | 65 | { |
66 | m_log.Info("[DATASNAPSHOT] Received collection request"); | 66 | m_log.Debug("[DATASNAPSHOT] Received collection request"); |
67 | Hashtable reply = new Hashtable(); | 67 | Hashtable reply = new Hashtable(); |
68 | int statuscode = 200; | 68 | int statuscode = 200; |
69 | 69 | ||
@@ -80,7 +80,7 @@ namespace OpenSim.Region.DataSnapshot | |||
80 | 80 | ||
81 | public Hashtable OnValidate(Hashtable keysvals) | 81 | public Hashtable OnValidate(Hashtable keysvals) |
82 | { | 82 | { |
83 | m_log.Info("[DATASNAPSHOT] Received validation request"); | 83 | m_log.Debug("[DATASNAPSHOT] Received validation request"); |
84 | Hashtable reply = new Hashtable(); | 84 | Hashtable reply = new Hashtable(); |
85 | int statuscode = 200; | 85 | int statuscode = 200; |
86 | 86 | ||
diff --git a/OpenSim/Region/DataSnapshot/SnapshotStore.cs b/OpenSim/Region/DataSnapshot/SnapshotStore.cs index aa3d2ff..480aaaf 100644 --- a/OpenSim/Region/DataSnapshot/SnapshotStore.cs +++ b/OpenSim/Region/DataSnapshot/SnapshotStore.cs | |||
@@ -120,7 +120,7 @@ namespace OpenSim.Region.DataSnapshot | |||
120 | provider.Stale = false; | 120 | provider.Stale = false; |
121 | m_scenes[provider.GetParentScene] = true; | 121 | m_scenes[provider.GetParentScene] = true; |
122 | 122 | ||
123 | m_log.Info("[DATASNAPSHOT]: Generated fragment response for provider type " + provider.Name); | 123 | m_log.Debug("[DATASNAPSHOT]: Generated fragment response for provider type " + provider.Name); |
124 | } | 124 | } |
125 | else | 125 | else |
126 | { | 126 | { |
@@ -134,7 +134,7 @@ namespace OpenSim.Region.DataSnapshot | |||
134 | data = factory.ImportNode(node, true); | 134 | data = factory.ImportNode(node, true); |
135 | } | 135 | } |
136 | 136 | ||
137 | m_log.Info("[DATASNAPSHOT]: Retrieved fragment response for provider type " + provider.Name); | 137 | m_log.Debug("[DATASNAPSHOT]: Retrieved fragment response for provider type " + provider.Name); |
138 | } | 138 | } |
139 | 139 | ||
140 | return data; | 140 | return data; |
@@ -154,7 +154,7 @@ namespace OpenSim.Region.DataSnapshot | |||
154 | 154 | ||
155 | if (!m_scenes[scene]) | 155 | if (!m_scenes[scene]) |
156 | { | 156 | { |
157 | m_log.Info("[DATASNAPSHOT]: Attempting to retrieve snapshot from cache."); | 157 | m_log.Debug("[DATASNAPSHOT]: Attempting to retrieve snapshot from cache."); |
158 | //get snapshot from cache | 158 | //get snapshot from cache |
159 | String path = DataFileNameScene(scene); | 159 | String path = DataFileNameScene(scene); |
160 | 160 | ||
@@ -168,11 +168,11 @@ namespace OpenSim.Region.DataSnapshot | |||
168 | regionElement = factory.ImportNode(node, true); | 168 | regionElement = factory.ImportNode(node, true); |
169 | } | 169 | } |
170 | 170 | ||
171 | m_log.Info("[DATASNAPSHOT]: Obtained snapshot from cache for " + scene.RegionInfo.RegionName); | 171 | m_log.Debug("[DATASNAPSHOT]: Obtained snapshot from cache for " + scene.RegionInfo.RegionName); |
172 | } | 172 | } |
173 | else | 173 | else |
174 | { | 174 | { |
175 | m_log.Info("[DATASNAPSHOT]: Attempting to generate snapshot."); | 175 | m_log.Debug("[DATASNAPSHOT]: Attempting to generate snapshot."); |
176 | //make snapshot | 176 | //make snapshot |
177 | regionElement = MakeRegionNode(scene, factory); | 177 | regionElement = MakeRegionNode(scene, factory); |
178 | 178 | ||
@@ -211,7 +211,7 @@ namespace OpenSim.Region.DataSnapshot | |||
211 | 211 | ||
212 | m_scenes[scene] = false; | 212 | m_scenes[scene] = false; |
213 | 213 | ||
214 | m_log.Info("[DATASNAPSHOT]: Generated new snapshot for " + scene.RegionInfo.RegionName); | 214 | m_log.Debug("[DATASNAPSHOT]: Generated new snapshot for " + scene.RegionInfo.RegionName); |
215 | } | 215 | } |
216 | 216 | ||
217 | return regionElement; | 217 | return regionElement; |
diff --git a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs index 292efa4..d49b24e 100644 --- a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs | |||
@@ -40,7 +40,7 @@ namespace OpenSim.Region.Framework.Interfaces | |||
40 | 40 | ||
41 | uint GetRegionFlags(); | 41 | uint GetRegionFlags(); |
42 | bool IsManager(UUID avatarID); | 42 | bool IsManager(UUID avatarID); |
43 | 43 | ||
44 | /// <summary> | 44 | /// <summary> |
45 | /// Tell all clients about the current state of the region (terrain textures, water height, etc.). | 45 | /// Tell all clients about the current state of the region (terrain textures, water height, etc.). |
46 | /// </summary> | 46 | /// </summary> |
diff --git a/OpenSim/Region/Framework/Interfaces/ISoundModule.cs b/OpenSim/Region/Framework/Interfaces/ISoundModule.cs index 68af492..8372ddd 100644 --- a/OpenSim/Region/Framework/Interfaces/ISoundModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ISoundModule.cs | |||
@@ -104,7 +104,6 @@ namespace OpenSim.Region.Framework.Interfaces | |||
104 | /// <param name="sound">Sound asset ID</param> | 104 | /// <param name="sound">Sound asset ID</param> |
105 | /// <param name="volume">Sound volume</param> | 105 | /// <param name="volume">Sound volume</param> |
106 | /// <param name="triggered">Triggered or not.</param> | 106 | /// <param name="triggered">Triggered or not.</param> |
107 | /// <param name="flags"></param> | ||
108 | /// <param name="radius">Sound radius</param> | 107 | /// <param name="radius">Sound radius</param> |
109 | /// <param name="useMaster">Play using sound master</param> | 108 | /// <param name="useMaster">Play using sound master</param> |
110 | /// <param name="isMaster">Play as sound master</param> | 109 | /// <param name="isMaster">Play as sound master</param> |
@@ -123,5 +122,12 @@ namespace OpenSim.Region.Framework.Interfaces | |||
123 | /// <param name="max">AABB top north-east corner</param> | 122 | /// <param name="max">AABB top north-east corner</param> |
124 | void TriggerSoundLimited(UUID objectID, UUID sound, double volume, | 123 | void TriggerSoundLimited(UUID objectID, UUID sound, double volume, |
125 | Vector3 min, Vector3 max); | 124 | Vector3 min, Vector3 max); |
125 | |||
126 | /// <summary> | ||
127 | /// Set whether sounds on the given prim should be queued. | ||
128 | /// </summary> | ||
129 | /// <param name='objectID'></param> | ||
130 | /// <param name='shouldQueue'></param> | ||
131 | void SetSoundQueueing(UUID objectID, bool shouldQueue); | ||
126 | } | 132 | } |
127 | } \ No newline at end of file | 133 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs index 66edfed..b7400ea 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/AnimationSet.cs | |||
@@ -28,8 +28,11 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using System.Text; | ||
31 | using log4net; | 32 | using log4net; |
32 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenMetaverse.StructuredData; | ||
35 | |||
33 | using OpenSim.Framework; | 36 | using OpenSim.Framework; |
34 | 37 | ||
35 | using Animation = OpenSim.Framework.Animation; | 38 | using Animation = OpenSim.Framework.Animation; |
@@ -60,6 +63,12 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
60 | ResetDefaultAnimation(); | 63 | ResetDefaultAnimation(); |
61 | } | 64 | } |
62 | 65 | ||
66 | public AnimationSet(OSDArray pArray) | ||
67 | { | ||
68 | ResetDefaultAnimation(); | ||
69 | FromOSDArray(pArray); | ||
70 | } | ||
71 | |||
63 | public bool HasAnimation(UUID animID) | 72 | public bool HasAnimation(UUID animID) |
64 | { | 73 | { |
65 | if (m_defaultAnimation.AnimID == animID) | 74 | if (m_defaultAnimation.AnimID == animID) |
@@ -218,5 +227,110 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
218 | foreach (OpenSim.Framework.Animation anim in theArray) | 227 | foreach (OpenSim.Framework.Animation anim in theArray) |
219 | m_animations.Add(anim); | 228 | m_animations.Add(anim); |
220 | } | 229 | } |
230 | |||
231 | // Create representation of this AnimationSet as an OSDArray. | ||
232 | // First two entries in the array are the default and implicitDefault animations | ||
233 | // followed by the other animations. | ||
234 | public OSDArray ToOSDArray() | ||
235 | { | ||
236 | OSDArray ret = new OSDArray(); | ||
237 | ret.Add(DefaultAnimation.PackUpdateMessage()); | ||
238 | ret.Add(ImplicitDefaultAnimation.PackUpdateMessage()); | ||
239 | |||
240 | foreach (OpenSim.Framework.Animation anim in m_animations) | ||
241 | ret.Add(anim.PackUpdateMessage()); | ||
242 | |||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | public void FromOSDArray(OSDArray pArray) | ||
247 | { | ||
248 | this.Clear(); | ||
249 | |||
250 | if (pArray.Count >= 1) | ||
251 | { | ||
252 | m_defaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[0]); | ||
253 | } | ||
254 | if (pArray.Count >= 2) | ||
255 | { | ||
256 | m_implicitDefaultAnimation = new OpenSim.Framework.Animation((OSDMap)pArray[1]); | ||
257 | } | ||
258 | for (int ii = 2; ii < pArray.Count; ii++) | ||
259 | { | ||
260 | m_animations.Add(new OpenSim.Framework.Animation((OSDMap)pArray[ii])); | ||
261 | } | ||
262 | } | ||
263 | |||
264 | // Compare two AnimationSets and return 'true' if the default animations are the same | ||
265 | // and all of the animations in the list are equal. | ||
266 | public override bool Equals(object obj) | ||
267 | { | ||
268 | AnimationSet other = obj as AnimationSet; | ||
269 | if (other != null) | ||
270 | { | ||
271 | if (this.DefaultAnimation.Equals(other.DefaultAnimation) | ||
272 | && this.ImplicitDefaultAnimation.Equals(other.ImplicitDefaultAnimation)) | ||
273 | { | ||
274 | // The defaults are the same. Is the list of animations the same? | ||
275 | OpenSim.Framework.Animation[] thisAnims = this.ToArray(); | ||
276 | OpenSim.Framework.Animation[] otherAnims = other.ToArray(); | ||
277 | if (thisAnims.Length == 0 && otherAnims.Length == 0) | ||
278 | return true; // the common case | ||
279 | if (thisAnims.Length == otherAnims.Length) | ||
280 | { | ||
281 | // Do this the hard way but since the list is usually short this won't take long. | ||
282 | foreach (OpenSim.Framework.Animation thisAnim in thisAnims) | ||
283 | { | ||
284 | bool found = false; | ||
285 | foreach (OpenSim.Framework.Animation otherAnim in otherAnims) | ||
286 | { | ||
287 | if (thisAnim.Equals(otherAnim)) | ||
288 | { | ||
289 | found = true; | ||
290 | break; | ||
291 | } | ||
292 | } | ||
293 | if (!found) | ||
294 | { | ||
295 | // If anything is not in the other list, these are not equal | ||
296 | return false; | ||
297 | } | ||
298 | } | ||
299 | // Found everything in the other list. Since lists are equal length, they must be equal. | ||
300 | return true; | ||
301 | } | ||
302 | } | ||
303 | return false; | ||
304 | } | ||
305 | // Don't know what was passed, but the base system will figure it out for me. | ||
306 | return base.Equals(obj); | ||
307 | } | ||
308 | |||
309 | public override string ToString() | ||
310 | { | ||
311 | StringBuilder buff = new StringBuilder(); | ||
312 | buff.Append("dflt="); | ||
313 | buff.Append(DefaultAnimation.ToString()); | ||
314 | buff.Append(",iDflt="); | ||
315 | if (DefaultAnimation.Equals(ImplicitDefaultAnimation)) | ||
316 | buff.Append("same"); | ||
317 | else | ||
318 | buff.Append(ImplicitDefaultAnimation.ToString()); | ||
319 | if (m_animations.Count > 0) | ||
320 | { | ||
321 | buff.Append(",anims="); | ||
322 | bool firstTime = true; | ||
323 | foreach (OpenSim.Framework.Animation anim in m_animations) | ||
324 | { | ||
325 | if (!firstTime) | ||
326 | buff.Append(","); | ||
327 | buff.Append("<"); | ||
328 | buff.Append(anim.ToString()); | ||
329 | buff.Append(">"); | ||
330 | firstTime = false; | ||
331 | } | ||
332 | } | ||
333 | return buff.ToString(); | ||
334 | } | ||
221 | } | 335 | } |
222 | } | 336 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs index c2b0468..b79dd8f 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/DefaultAvatarAnimations.cs | |||
@@ -104,5 +104,31 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
104 | 104 | ||
105 | return UUID.Zero; | 105 | return UUID.Zero; |
106 | } | 106 | } |
107 | |||
108 | /// <summary> | ||
109 | /// Get the name of the animation given a UUID. If there is no matching animation | ||
110 | /// return the UUID as a string. | ||
111 | /// </summary> | ||
112 | public static string GetDefaultAnimationName(UUID uuid) | ||
113 | { | ||
114 | string ret = "unknown"; | ||
115 | if (AnimsUUID.ContainsValue(uuid)) | ||
116 | { | ||
117 | foreach (KeyValuePair<string, UUID> kvp in AnimsUUID) | ||
118 | { | ||
119 | if (kvp.Value == uuid) | ||
120 | { | ||
121 | ret = kvp.Key; | ||
122 | break; | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | else | ||
127 | { | ||
128 | ret = uuid.ToString(); | ||
129 | } | ||
130 | |||
131 | return ret; | ||
132 | } | ||
107 | } | 133 | } |
108 | } \ No newline at end of file | 134 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index 65c279e..5529a25 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs | |||
@@ -93,7 +93,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
93 | GetAnimName(animID), animID, m_scenePresence.Name); | 93 | GetAnimName(animID), animID, m_scenePresence.Name); |
94 | 94 | ||
95 | if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) | 95 | if (m_animations.Add(animID, m_scenePresence.ControllingClient.NextAnimationSequenceNumber, objectID)) |
96 | { | ||
96 | SendAnimPack(); | 97 | SendAnimPack(); |
98 | m_scenePresence.TriggerScenePresenceUpdated(); | ||
99 | } | ||
97 | } | 100 | } |
98 | 101 | ||
99 | // Called from scripts | 102 | // Called from scripts |
@@ -132,7 +135,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
132 | GetAnimName(animID), animID, m_scenePresence.Name); | 135 | GetAnimName(animID), animID, m_scenePresence.Name); |
133 | 136 | ||
134 | if (m_animations.Remove(animID, allowNoDefault)) | 137 | if (m_animations.Remove(animID, allowNoDefault)) |
138 | { | ||
135 | SendAnimPack(); | 139 | SendAnimPack(); |
140 | m_scenePresence.TriggerScenePresenceUpdated(); | ||
141 | } | ||
136 | } | 142 | } |
137 | 143 | ||
138 | public void avnChangeAnim(UUID animID, bool addRemove, bool sendPack) | 144 | public void avnChangeAnim(UUID animID, bool addRemove, bool sendPack) |
@@ -180,8 +186,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
180 | /// The movement animation is reserved for "main" animations | 186 | /// The movement animation is reserved for "main" animations |
181 | /// that are mutually exclusive, e.g. flying and sitting. | 187 | /// that are mutually exclusive, e.g. flying and sitting. |
182 | /// </summary> | 188 | /// </summary> |
183 | public void TrySetMovementAnimation(string anim) | 189 | /// <returns>'true' if the animation was updated</returns> |
190 | public bool TrySetMovementAnimation(string anim) | ||
184 | { | 191 | { |
192 | bool ret = false; | ||
185 | if (!m_scenePresence.IsChildAgent) | 193 | if (!m_scenePresence.IsChildAgent) |
186 | { | 194 | { |
187 | // m_log.DebugFormat( | 195 | // m_log.DebugFormat( |
@@ -198,6 +206,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
198 | // 16384 is CHANGED_ANIMATION | 206 | // 16384 is CHANGED_ANIMATION |
199 | m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION}); | 207 | m_scenePresence.SendScriptEventToAttachments("changed", new Object[] { (int)Changed.ANIMATION}); |
200 | SendAnimPack(); | 208 | SendAnimPack(); |
209 | ret = true; | ||
201 | } | 210 | } |
202 | } | 211 | } |
203 | else | 212 | else |
@@ -206,6 +215,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
206 | "[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}", | 215 | "[SCENE PRESENCE ANIMATOR]: Tried to set movement animation {0} on child presence {1}", |
207 | anim, m_scenePresence.Name); | 216 | anim, m_scenePresence.Name); |
208 | } | 217 | } |
218 | return ret; | ||
209 | } | 219 | } |
210 | 220 | ||
211 | /// <summary> | 221 | /// <summary> |
@@ -439,8 +449,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
439 | /// <summary> | 449 | /// <summary> |
440 | /// Update the movement animation of this avatar according to its current state | 450 | /// Update the movement animation of this avatar according to its current state |
441 | /// </summary> | 451 | /// </summary> |
442 | public void UpdateMovementAnimations() | 452 | /// <returns>'true' if the animation was changed</returns> |
453 | public bool UpdateMovementAnimations() | ||
443 | { | 454 | { |
455 | bool ret = false; | ||
444 | lock (m_animations) | 456 | lock (m_animations) |
445 | { | 457 | { |
446 | string newMovementAnimation = DetermineMovementAnimation(); | 458 | string newMovementAnimation = DetermineMovementAnimation(); |
@@ -454,9 +466,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation | |||
454 | 466 | ||
455 | // Only set it if it's actually changed, give a script | 467 | // Only set it if it's actually changed, give a script |
456 | // a chance to stop a default animation | 468 | // a chance to stop a default animation |
457 | TrySetMovementAnimation(CurrentMovementAnimation); | 469 | ret = TrySetMovementAnimation(CurrentMovementAnimation); |
458 | } | 470 | } |
459 | } | 471 | } |
472 | return ret; | ||
460 | } | 473 | } |
461 | 474 | ||
462 | public UUID[] GetAnimationArray() | 475 | public UUID[] GetAnimationArray() |
diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs index f555b49..11a0146 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs | |||
@@ -104,14 +104,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
104 | // better than losing the object for now. | 104 | // better than losing the object for now. |
105 | if (permissionToDelete) | 105 | if (permissionToDelete) |
106 | { | 106 | { |
107 | List<uint> killIDs = new List<uint>(); | ||
108 | |||
109 | foreach (SceneObjectGroup g in objectGroups) | 107 | foreach (SceneObjectGroup g in objectGroups) |
110 | { killIDs.Add(g.LocalId); | 108 | g.DeleteGroupFromScene(false); |
111 | g.DeleteGroupFromScene(true); | ||
112 | } | ||
113 | |||
114 | m_scene.SendKillObject(killIDs); | ||
115 | } | 109 | } |
116 | } | 110 | } |
117 | 111 | ||
@@ -160,7 +154,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
160 | if (x.permissionToDelete) | 154 | if (x.permissionToDelete) |
161 | { | 155 | { |
162 | foreach (SceneObjectGroup g in x.objectGroups) | 156 | foreach (SceneObjectGroup g in x.objectGroups) |
163 | m_scene.DeleteSceneObject(g, false); | 157 | m_scene.DeleteSceneObject(g, true); |
164 | } | 158 | } |
165 | } | 159 | } |
166 | catch (Exception e) | 160 | catch (Exception e) |
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 4733547..4fec44f 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs | |||
@@ -974,6 +974,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
974 | public delegate void RegionStarted(Scene scene); | 974 | public delegate void RegionStarted(Scene scene); |
975 | public event RegionStarted OnRegionStarted; | 975 | public event RegionStarted OnRegionStarted; |
976 | 976 | ||
977 | public delegate void RegionHeartbeatStart(Scene scene); | ||
978 | public event RegionHeartbeatStart OnRegionHeartbeatStart; | ||
977 | public delegate void RegionHeartbeatEnd(Scene scene); | 979 | public delegate void RegionHeartbeatEnd(Scene scene); |
978 | public event RegionHeartbeatEnd OnRegionHeartbeatEnd; | 980 | public event RegionHeartbeatEnd OnRegionHeartbeatEnd; |
979 | 981 | ||
@@ -3096,6 +3098,27 @@ namespace OpenSim.Region.Framework.Scenes | |||
3096 | } | 3098 | } |
3097 | } | 3099 | } |
3098 | 3100 | ||
3101 | public void TriggerRegionHeartbeatStart(Scene scene) | ||
3102 | { | ||
3103 | RegionHeartbeatStart handler = OnRegionHeartbeatStart; | ||
3104 | |||
3105 | if (handler != null) | ||
3106 | { | ||
3107 | foreach (RegionHeartbeatStart d in handler.GetInvocationList()) | ||
3108 | { | ||
3109 | try | ||
3110 | { | ||
3111 | d(scene); | ||
3112 | } | ||
3113 | catch (Exception e) | ||
3114 | { | ||
3115 | m_log.ErrorFormat("[EVENT MANAGER]: Delegate for OnRegionHeartbeatStart failed - continuing {0} - {1}", | ||
3116 | e.Message, e.StackTrace); | ||
3117 | } | ||
3118 | } | ||
3119 | } | ||
3120 | } | ||
3121 | |||
3099 | public void TriggerRegionHeartbeatEnd(Scene scene) | 3122 | public void TriggerRegionHeartbeatEnd(Scene scene) |
3100 | { | 3123 | { |
3101 | RegionHeartbeatEnd handler = OnRegionHeartbeatEnd; | 3124 | RegionHeartbeatEnd handler = OnRegionHeartbeatEnd; |
diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs index d773ee7..8a40278 100644 --- a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | |||
@@ -1,6 +1,29 @@ | |||
1 | // Proprietary code of Avination Virtual Limited | 1 | /* |
2 | // (c) 2012 Melanie Thielker | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | // | 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 | */ | ||
4 | 27 | ||
5 | using System; | 28 | using System; |
6 | using System.Timers; | 29 | using System.Timers; |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index d2e41f8..70018c8 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs | |||
@@ -417,13 +417,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
417 | // is not allowed to change the export flag. | 417 | // is not allowed to change the export flag. |
418 | bool denyExportChange = false; | 418 | bool denyExportChange = false; |
419 | 419 | ||
420 | m_log.InfoFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions); | 420 | // m_log.DebugFormat("[XXX]: B: {0} O: {1} E: {2}", itemUpd.BasePermissions, itemUpd.CurrentPermissions, itemUpd.EveryOnePermissions); |
421 | 421 | ||
422 | // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export | 422 | // If the user is not the creator or doesn't have "E" in both "B" and "O", deny setting export |
423 | if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner) | 423 | if ((item.BasePermissions & (uint)(PermissionMask.All | PermissionMask.Export)) != (uint)(PermissionMask.All | PermissionMask.Export) || (item.CurrentPermissions & (uint)PermissionMask.Export) == 0 || item.CreatorIdAsUuid != item.Owner) |
424 | denyExportChange = true; | 424 | denyExportChange = true; |
425 | 425 | ||
426 | m_log.InfoFormat("[XXX]: Deny Export Update {0}", denyExportChange); | 426 | // m_log.DebugFormat("[XXX]: Deny Export Update {0}", denyExportChange); |
427 | 427 | ||
428 | // If it is already set, force it set and also force full perm | 428 | // If it is already set, force it set and also force full perm |
429 | // else prevent setting it. It can and should never be set unless | 429 | // else prevent setting it. It can and should never be set unless |
@@ -447,7 +447,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
447 | // If the new state is exportable, force full perm | 447 | // If the new state is exportable, force full perm |
448 | if ((itemUpd.EveryOnePermissions & (uint)PermissionMask.Export) != 0) | 448 | if ((itemUpd.EveryOnePermissions & (uint)PermissionMask.Export) != 0) |
449 | { | 449 | { |
450 | m_log.InfoFormat("[XXX]: Force full perm"); | 450 | // m_log.DebugFormat("[XXX]: Force full perm"); |
451 | itemUpd.NextPermissions = (uint)(PermissionMask.All); | 451 | itemUpd.NextPermissions = (uint)(PermissionMask.All); |
452 | } | 452 | } |
453 | } | 453 | } |
@@ -485,7 +485,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
485 | item.SaleType = itemUpd.SaleType; | 485 | item.SaleType = itemUpd.SaleType; |
486 | 486 | ||
487 | InventoryService.UpdateItem(item); | 487 | InventoryService.UpdateItem(item); |
488 | remoteClient.SendBulkUpdateInventory(item); | 488 | |
489 | // We cannot send out a bulk update here, since this will cause editing of clothing to start | ||
490 | // failing frequently. Possibly this is a race with a separate transaction that uploads the asset. | ||
491 | // remoteClient.SendBulkUpdateInventory(item); | ||
489 | } | 492 | } |
490 | 493 | ||
491 | if (UUID.Zero != transactionID) | 494 | if (UUID.Zero != transactionID) |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 2b58795..436a544 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -396,10 +396,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
396 | if (value) | 396 | if (value) |
397 | { | 397 | { |
398 | if (!m_active) | 398 | if (!m_active) |
399 | Start(); | 399 | Start(false); |
400 | } | 400 | } |
401 | else | 401 | else |
402 | { | 402 | { |
403 | // This appears assymetric with Start() above but is not - setting m_active = false stops the loops | ||
404 | // XXX: Possibly this should be in an explicit Stop() method for symmetry. | ||
403 | m_active = false; | 405 | m_active = false; |
404 | } | 406 | } |
405 | } | 407 | } |
@@ -1361,10 +1363,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
1361 | } | 1363 | } |
1362 | } | 1364 | } |
1363 | 1365 | ||
1366 | public override void Start() | ||
1367 | { | ||
1368 | Start(true); | ||
1369 | } | ||
1370 | |||
1364 | /// <summary> | 1371 | /// <summary> |
1365 | /// Start the scene | 1372 | /// Start the scene |
1366 | /// </summary> | 1373 | /// </summary> |
1367 | public void Start() | 1374 | /// <param name='startScripts'> |
1375 | /// Start the scripts within the scene. | ||
1376 | /// </param> | ||
1377 | public void Start(bool startScripts) | ||
1368 | { | 1378 | { |
1369 | m_active = true; | 1379 | m_active = true; |
1370 | 1380 | ||
@@ -1401,6 +1411,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1401 | m_heartbeatThread | 1411 | m_heartbeatThread |
1402 | = Watchdog.StartThread( | 1412 | = Watchdog.StartThread( |
1403 | Heartbeat, string.Format("Heartbeat ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, false); | 1413 | Heartbeat, string.Format("Heartbeat ({0})", RegionInfo.RegionName), ThreadPriority.Normal, false, false); |
1414 | |||
1415 | StartScripts(); | ||
1404 | } | 1416 | } |
1405 | 1417 | ||
1406 | /// <summary> | 1418 | /// <summary> |
@@ -1557,6 +1569,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1557 | 1569 | ||
1558 | try | 1570 | try |
1559 | { | 1571 | { |
1572 | EventManager.TriggerRegionHeartbeatStart(this); | ||
1573 | |||
1560 | // Apply taints in terrain module to terrain in physics scene | 1574 | // Apply taints in terrain module to terrain in physics scene |
1561 | if (Frame % m_update_terrain == 0) | 1575 | if (Frame % m_update_terrain == 0) |
1562 | { | 1576 | { |
@@ -3001,7 +3015,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3001 | // client is for a root or child agent. | 3015 | // client is for a root or child agent. |
3002 | client.SceneAgent = sp; | 3016 | client.SceneAgent = sp; |
3003 | 3017 | ||
3004 | // Cache the user's name | 3018 | // This is currently also being done earlier in NewUserConnection for real users to see if this |
3019 | // resolves problems where HG agents are occasionally seen by others as "Unknown user" in chat and other | ||
3020 | // places. However, we still need to do it here for NPCs. | ||
3005 | CacheUserName(sp, aCircuit); | 3021 | CacheUserName(sp, aCircuit); |
3006 | 3022 | ||
3007 | EventManager.TriggerOnNewClient(client); | 3023 | EventManager.TriggerOnNewClient(client); |
@@ -3025,7 +3041,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3025 | { | 3041 | { |
3026 | string first = aCircuit.firstname, last = aCircuit.lastname; | 3042 | string first = aCircuit.firstname, last = aCircuit.lastname; |
3027 | 3043 | ||
3028 | if (sp.PresenceType == PresenceType.Npc) | 3044 | if (sp != null && sp.PresenceType == PresenceType.Npc) |
3029 | { | 3045 | { |
3030 | UserManagementModule.AddUser(aCircuit.AgentID, first, last); | 3046 | UserManagementModule.AddUser(aCircuit.AgentID, first, last); |
3031 | } | 3047 | } |
@@ -3242,7 +3258,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3242 | { | 3258 | { |
3243 | //client.OnNameFromUUIDRequest += HandleUUIDNameRequest; | 3259 | //client.OnNameFromUUIDRequest += HandleUUIDNameRequest; |
3244 | client.OnMoneyTransferRequest += ProcessMoneyTransferRequest; | 3260 | client.OnMoneyTransferRequest += ProcessMoneyTransferRequest; |
3245 | client.OnSetStartLocationRequest += SetHomeRezPoint; | ||
3246 | client.OnRegionHandleRequest += RegionHandleRequest; | 3261 | client.OnRegionHandleRequest += RegionHandleRequest; |
3247 | } | 3262 | } |
3248 | 3263 | ||
@@ -3369,7 +3384,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3369 | { | 3384 | { |
3370 | //client.OnNameFromUUIDRequest -= HandleUUIDNameRequest; | 3385 | //client.OnNameFromUUIDRequest -= HandleUUIDNameRequest; |
3371 | client.OnMoneyTransferRequest -= ProcessMoneyTransferRequest; | 3386 | client.OnMoneyTransferRequest -= ProcessMoneyTransferRequest; |
3372 | client.OnSetStartLocationRequest -= SetHomeRezPoint; | ||
3373 | client.OnRegionHandleRequest -= RegionHandleRequest; | 3387 | client.OnRegionHandleRequest -= RegionHandleRequest; |
3374 | } | 3388 | } |
3375 | 3389 | ||
@@ -3496,33 +3510,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3496 | } | 3510 | } |
3497 | 3511 | ||
3498 | /// <summary> | 3512 | /// <summary> |
3499 | /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in | ||
3500 | /// </summary> | ||
3501 | /// <param name="remoteClient"></param> | ||
3502 | /// <param name="regionHandle"></param> | ||
3503 | /// <param name="position"></param> | ||
3504 | /// <param name="lookAt"></param> | ||
3505 | /// <param name="flags"></param> | ||
3506 | public virtual void SetHomeRezPoint(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags) | ||
3507 | { | ||
3508 | //Add half the avatar's height so that the user doesn't fall through prims | ||
3509 | ScenePresence presence; | ||
3510 | if (TryGetScenePresence(remoteClient.AgentId, out presence)) | ||
3511 | { | ||
3512 | if (presence.Appearance != null) | ||
3513 | { | ||
3514 | position.Z = position.Z + (presence.Appearance.AvatarHeight / 2); | ||
3515 | } | ||
3516 | } | ||
3517 | |||
3518 | if (GridUserService != null && GridUserService.SetHome(remoteClient.AgentId.ToString(), RegionInfo.RegionID, position, lookAt)) | ||
3519 | // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot. | ||
3520 | m_dialogModule.SendAlertToUser(remoteClient, "Home position set."); | ||
3521 | else | ||
3522 | m_dialogModule.SendAlertToUser(remoteClient, "Set Home request Failed."); | ||
3523 | } | ||
3524 | |||
3525 | /// <summary> | ||
3526 | /// Get the avatar apperance for the given client. | 3513 | /// Get the avatar apperance for the given client. |
3527 | /// </summary> | 3514 | /// </summary> |
3528 | /// <param name="client"></param> | 3515 | /// <param name="client"></param> |
@@ -3618,15 +3605,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3618 | if (closeChildAgents && CapsModule != null) | 3605 | if (closeChildAgents && CapsModule != null) |
3619 | CapsModule.RemoveCaps(agentID, avatar.ControllingClient.CircuitCode); | 3606 | CapsModule.RemoveCaps(agentID, avatar.ControllingClient.CircuitCode); |
3620 | 3607 | ||
3621 | // // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever | ||
3622 | // // this method is doing is HORRIBLE!!! | ||
3623 | // Commented pending deletion since this method no longer appears to do anything at all | ||
3624 | // avatar.Scene.NeedSceneCacheClear(avatar.UUID); | ||
3625 | |||
3626 | if (closeChildAgents && !isChildAgent) | 3608 | if (closeChildAgents && !isChildAgent) |
3627 | { | 3609 | { |
3628 | List<ulong> regions = avatar.KnownRegionHandles; | 3610 | List<ulong> regions = avatar.KnownRegionHandles; |
3629 | regions.Remove(RegionInfo.RegionHandle); | 3611 | regions.Remove(RegionInfo.RegionHandle); |
3612 | |||
3613 | // This ends up being done asynchronously so that a logout isn't held up where there are many present but unresponsive neighbours. | ||
3630 | m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); | 3614 | m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); |
3631 | } | 3615 | } |
3632 | 3616 | ||
@@ -3644,7 +3628,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3644 | delegate(IClientAPI client) | 3628 | delegate(IClientAPI client) |
3645 | { | 3629 | { |
3646 | //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway | 3630 | //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway |
3647 | try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); } | 3631 | try { client.SendKillObject(new List<uint> { avatar.LocalId }); } |
3648 | catch (NullReferenceException) { } | 3632 | catch (NullReferenceException) { } |
3649 | }); | 3633 | }); |
3650 | } | 3634 | } |
@@ -3725,7 +3709,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3725 | } | 3709 | } |
3726 | deleteIDs.Add(localID); | 3710 | deleteIDs.Add(localID); |
3727 | } | 3711 | } |
3728 | ForEachClient(delegate(IClientAPI client) { client.SendKillObject(m_regionHandle, deleteIDs); }); | 3712 | |
3713 | ForEachClient(c => c.SendKillObject(deleteIDs)); | ||
3729 | } | 3714 | } |
3730 | 3715 | ||
3731 | #endregion | 3716 | #endregion |
@@ -3881,7 +3866,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3881 | 3866 | ||
3882 | lock (agent) | 3867 | lock (agent) |
3883 | { | 3868 | { |
3884 | //On login test land permisions | 3869 | // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags. |
3870 | // We need the circuit data here for some of the subsequent checks. (groups, for example) | ||
3871 | // If the checks fail, we remove the circuit. | ||
3872 | agent.teleportFlags = teleportFlags; | ||
3873 | m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); | ||
3874 | |||
3875 | // On login test land permisions | ||
3885 | if (vialogin) | 3876 | if (vialogin) |
3886 | { | 3877 | { |
3887 | IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>(); | 3878 | IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>(); |
@@ -3890,6 +3881,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3890 | if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y)) | 3881 | if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y)) |
3891 | { | 3882 | { |
3892 | m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString()); | 3883 | m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString()); |
3884 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | ||
3893 | return false; | 3885 | return false; |
3894 | } | 3886 | } |
3895 | } | 3887 | } |
@@ -3901,11 +3893,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
3901 | try | 3893 | try |
3902 | { | 3894 | { |
3903 | if (!VerifyUserPresence(agent, out reason)) | 3895 | if (!VerifyUserPresence(agent, out reason)) |
3896 | { | ||
3897 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | ||
3904 | return false; | 3898 | return false; |
3905 | } catch (Exception e) | 3899 | } |
3900 | } | ||
3901 | catch (Exception e) | ||
3906 | { | 3902 | { |
3907 | m_log.ErrorFormat( | 3903 | m_log.ErrorFormat( |
3908 | "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); | 3904 | "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); |
3905 | |||
3906 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | ||
3909 | return false; | 3907 | return false; |
3910 | } | 3908 | } |
3911 | } | 3909 | } |
@@ -3918,6 +3916,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3918 | { | 3916 | { |
3919 | if (!AuthorizeUser(agent, out reason)) | 3917 | if (!AuthorizeUser(agent, out reason)) |
3920 | { | 3918 | { |
3919 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | ||
3921 | return false; | 3920 | return false; |
3922 | } | 3921 | } |
3923 | } | 3922 | } |
@@ -3926,6 +3925,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3926 | { | 3925 | { |
3927 | m_log.ErrorFormat( | 3926 | m_log.ErrorFormat( |
3928 | "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); | 3927 | "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); |
3928 | |||
3929 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | ||
3929 | return false; | 3930 | return false; |
3930 | } | 3931 | } |
3931 | 3932 | ||
@@ -3953,11 +3954,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3953 | CapsModule.SetAgentCapsSeeds(agent); | 3954 | CapsModule.SetAgentCapsSeeds(agent); |
3954 | } | 3955 | } |
3955 | } | 3956 | } |
3956 | } | ||
3957 | 3957 | ||
3958 | // In all cases, add or update the circuit data with the new agent circuit data and teleport flags | 3958 | // Try caching an incoming user name much earlier on to see if this helps with an issue |
3959 | agent.teleportFlags = teleportFlags; | 3959 | // where HG users are occasionally seen by others as "Unknown User" because their UUIDName |
3960 | m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); | 3960 | // request for the HG avatar appears to trigger before the user name is cached. |
3961 | CacheUserName(null, agent); | ||
3962 | } | ||
3961 | 3963 | ||
3962 | if (CapsModule != null) | 3964 | if (CapsModule != null) |
3963 | { | 3965 | { |
@@ -4365,8 +4367,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
4365 | m_log.DebugFormat( | 4367 | m_log.DebugFormat( |
4366 | "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName); | 4368 | "[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName); |
4367 | 4369 | ||
4368 | // XPTO: if this agent is not allowed here as root, always return false | ||
4369 | |||
4370 | // We have to wait until the viewer contacts this region after receiving EAC. | 4370 | // We have to wait until the viewer contacts this region after receiving EAC. |
4371 | // That calls AddNewClient, which finally creates the ScenePresence | 4371 | // That calls AddNewClient, which finally creates the ScenePresence |
4372 | int flags = GetUserFlags(cAgentData.AgentID); | 4372 | int flags = GetUserFlags(cAgentData.AgentID); |
@@ -5655,12 +5655,12 @@ Environment.Exit(1); | |||
5655 | List<SceneObjectGroup> objects, | 5655 | List<SceneObjectGroup> objects, |
5656 | out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) | 5656 | out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) |
5657 | { | 5657 | { |
5658 | minX = 256; | 5658 | minX = float.MaxValue; |
5659 | maxX = -256; | 5659 | maxX = float.MinValue; |
5660 | minY = 256; | 5660 | minY = float.MaxValue; |
5661 | maxY = -256; | 5661 | maxY = float.MinValue; |
5662 | minZ = 8192; | 5662 | minZ = float.MaxValue; |
5663 | maxZ = -256; | 5663 | maxZ = float.MinValue; |
5664 | 5664 | ||
5665 | List<Vector3> offsets = new List<Vector3>(); | 5665 | List<Vector3> offsets = new List<Vector3>(); |
5666 | 5666 | ||
diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs index 74c9582..4eef162 100644 --- a/OpenSim/Region/Framework/Scenes/SceneBase.cs +++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs | |||
@@ -562,6 +562,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
562 | get { return false; } | 562 | get { return false; } |
563 | } | 563 | } |
564 | 564 | ||
565 | public virtual void Start() | ||
566 | { | ||
567 | } | ||
568 | |||
565 | public void Restart() | 569 | public void Restart() |
566 | { | 570 | { |
567 | // This has to be here to fire the event | 571 | // This has to be here to fire the event |
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs index 775a4c2..df61dde 100644 --- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs | |||
@@ -222,8 +222,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
222 | { | 222 | { |
223 | foreach (ulong handle in regionslst) | 223 | foreach (ulong handle in regionslst) |
224 | { | 224 | { |
225 | ulong handleCopy = handle; | ||
225 | SendCloseChildAgentDelegate d = SendCloseChildAgentAsync; | 226 | SendCloseChildAgentDelegate d = SendCloseChildAgentAsync; |
226 | d.BeginInvoke(agentID, handle, | 227 | d.BeginInvoke(agentID, handleCopy, |
227 | SendCloseChildAgentCompleted, | 228 | SendCloseChildAgentCompleted, |
228 | d); | 229 | d); |
229 | } | 230 | } |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index f306651..0a18d8a 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -1867,11 +1867,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1867 | /// <summary> | 1867 | /// <summary> |
1868 | /// Delete this group from its scene. | 1868 | /// Delete this group from its scene. |
1869 | /// </summary> | 1869 | /// </summary> |
1870 | /// | 1870 | /// <remarks> |
1871 | /// This only handles the in-world consequences of deletion (e.g. any avatars sitting on it are forcibly stood | 1871 | /// This only handles the in-world consequences of deletion (e.g. any avatars sitting on it are forcibly stood |
1872 | /// up and all avatars receive notification of its removal. Removal of the scene object from database backup | 1872 | /// up and all avatars receive notification of its removal. Removal of the scene object from database backup |
1873 | /// must be handled by the caller. | 1873 | /// must be handled by the caller. |
1874 | /// | 1874 | /// </remarks> |
1875 | /// <param name="silent">If true then deletion is not broadcast to clients</param> | 1875 | /// <param name="silent">If true then deletion is not broadcast to clients</param> |
1876 | public void DeleteGroupFromScene(bool silent) | 1876 | public void DeleteGroupFromScene(bool silent) |
1877 | { | 1877 | { |
@@ -1885,10 +1885,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1885 | { | 1885 | { |
1886 | SceneObjectPart part = parts[i]; | 1886 | SceneObjectPart part = parts[i]; |
1887 | 1887 | ||
1888 | Scene.ForEachRootScenePresence(delegate(ScenePresence avatar) | 1888 | Scene.ForEachScenePresence(sp => |
1889 | { | 1889 | { |
1890 | if (avatar.ParentID == LocalId) | 1890 | if (!sp.IsChildAgent && sp.ParentID == LocalId) |
1891 | avatar.StandUp(); | 1891 | sp.StandUp(); |
1892 | 1892 | ||
1893 | if (!silent) | 1893 | if (!silent) |
1894 | { | 1894 | { |
@@ -1896,9 +1896,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1896 | if (part == m_rootPart) | 1896 | if (part == m_rootPart) |
1897 | { | 1897 | { |
1898 | if (!IsAttachment | 1898 | if (!IsAttachment |
1899 | || AttachedAvatar == avatar.ControllingClient.AgentId | 1899 | || AttachedAvatar == sp.UUID |
1900 | || !HasPrivateAttachmentPoint) | 1900 | || !HasPrivateAttachmentPoint) |
1901 | avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId }); | 1901 | sp.ControllingClient.SendKillObject(new List<uint> { part.LocalId }); |
1902 | } | 1902 | } |
1903 | } | 1903 | } |
1904 | }); | 1904 | }); |
@@ -2207,7 +2207,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2207 | if (!userExposed) | 2207 | if (!userExposed) |
2208 | dupe.IsAttachment = true; | 2208 | dupe.IsAttachment = true; |
2209 | 2209 | ||
2210 | dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); | 2210 | dupe.m_sittingAvatars = new List<UUID>(); |
2211 | 2211 | ||
2212 | if (!userExposed) | 2212 | if (!userExposed) |
2213 | { | 2213 | { |
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 261e958..f13f7ab 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -231,6 +231,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
231 | 231 | ||
232 | public double SoundRadius; | 232 | public double SoundRadius; |
233 | 233 | ||
234 | /// <summary> | ||
235 | /// Should sounds played from this prim be queued? | ||
236 | /// </summary> | ||
237 | /// <remarks> | ||
238 | /// This should only be changed by sound modules. It is up to sound modules as to how they interpret this setting. | ||
239 | /// </remarks> | ||
240 | public bool SoundQueueing { get; set; } | ||
234 | 241 | ||
235 | public uint TimeStampFull; | 242 | public uint TimeStampFull; |
236 | 243 | ||
@@ -815,7 +822,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
815 | } | 822 | } |
816 | 823 | ||
817 | // Tell the physics engines that this prim changed. | 824 | // Tell the physics engines that this prim changed. |
818 | ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); | 825 | if (ParentGroup != null && ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null) |
826 | ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); | ||
819 | } | 827 | } |
820 | catch (Exception e) | 828 | catch (Exception e) |
821 | { | 829 | { |
@@ -933,7 +941,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
933 | //m_log.Info("[PART]: RO2:" + actor.Orientation.ToString()); | 941 | //m_log.Info("[PART]: RO2:" + actor.Orientation.ToString()); |
934 | } | 942 | } |
935 | 943 | ||
936 | if (ParentGroup != null) | 944 | if (ParentGroup != null && ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null) |
937 | ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); | 945 | ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); |
938 | //} | 946 | //} |
939 | } | 947 | } |
@@ -1218,23 +1226,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
1218 | // the mappings more consistant. | 1226 | // the mappings more consistant. |
1219 | public Vector3 SitTargetPositionLL | 1227 | public Vector3 SitTargetPositionLL |
1220 | { | 1228 | { |
1221 | get { return new Vector3(m_sitTargetPosition.X, m_sitTargetPosition.Y,m_sitTargetPosition.Z); } | 1229 | get { return m_sitTargetPosition; } |
1222 | set { m_sitTargetPosition = value; } | 1230 | set { m_sitTargetPosition = value; } |
1223 | } | 1231 | } |
1224 | 1232 | ||
1225 | public Quaternion SitTargetOrientationLL | 1233 | public Quaternion SitTargetOrientationLL |
1226 | { | 1234 | { |
1227 | get | 1235 | get { return m_sitTargetOrientation; } |
1228 | { | 1236 | set { m_sitTargetOrientation = value; } |
1229 | return new Quaternion( | ||
1230 | m_sitTargetOrientation.X, | ||
1231 | m_sitTargetOrientation.Y, | ||
1232 | m_sitTargetOrientation.Z, | ||
1233 | m_sitTargetOrientation.W | ||
1234 | ); | ||
1235 | } | ||
1236 | |||
1237 | set { m_sitTargetOrientation = new Quaternion(value.X, value.Y, value.Z, value.W); } | ||
1238 | } | 1237 | } |
1239 | 1238 | ||
1240 | public bool Stopped | 1239 | public bool Stopped |
@@ -4350,30 +4349,31 @@ namespace OpenSim.Region.Framework.Scenes | |||
4350 | } | 4349 | } |
4351 | } | 4350 | } |
4352 | 4351 | ||
4353 | public void UpdateGroupPosition(Vector3 pos) | 4352 | public void UpdateGroupPosition(Vector3 newPos) |
4354 | { | 4353 | { |
4355 | if ((pos.X != GroupPosition.X) || | 4354 | Vector3 oldPos = GroupPosition; |
4356 | (pos.Y != GroupPosition.Y) || | 4355 | |
4357 | (pos.Z != GroupPosition.Z)) | 4356 | if ((newPos.X != oldPos.X) || |
4357 | (newPos.Y != oldPos.Y) || | ||
4358 | (newPos.Z != oldPos.Z)) | ||
4358 | { | 4359 | { |
4359 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); | ||
4360 | GroupPosition = newPos; | 4360 | GroupPosition = newPos; |
4361 | ScheduleTerseUpdate(); | 4361 | ScheduleTerseUpdate(); |
4362 | } | 4362 | } |
4363 | } | 4363 | } |
4364 | 4364 | ||
4365 | /// <summary> | 4365 | /// <summary> |
4366 | /// | 4366 | /// Update this part's offset position. |
4367 | /// </summary> | 4367 | /// </summary> |
4368 | /// <param name="pos"></param> | 4368 | /// <param name="pos"></param> |
4369 | public void UpdateOffSet(Vector3 pos) | 4369 | public void UpdateOffSet(Vector3 newPos) |
4370 | { | 4370 | { |
4371 | if ((pos.X != OffsetPosition.X) || | 4371 | Vector3 oldPos = OffsetPosition; |
4372 | (pos.Y != OffsetPosition.Y) || | ||
4373 | (pos.Z != OffsetPosition.Z)) | ||
4374 | { | ||
4375 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); | ||
4376 | 4372 | ||
4373 | if ((newPos.X != oldPos.X) || | ||
4374 | (newPos.Y != oldPos.Y) || | ||
4375 | (newPos.Z != oldPos.Z)) | ||
4376 | { | ||
4377 | if (ParentGroup.RootPart.GetStatusSandbox()) | 4377 | if (ParentGroup.RootPart.GetStatusSandbox()) |
4378 | { | 4378 | { |
4379 | if (Util.GetDistanceTo(ParentGroup.RootPart.StatusSandboxPos, newPos) > 10) | 4379 | if (Util.GetDistanceTo(ParentGroup.RootPart.StatusSandboxPos, newPos) > 10) |
@@ -5014,6 +5014,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
5014 | oldTex.DefaultTexture = fallbackOldFace; | 5014 | oldTex.DefaultTexture = fallbackOldFace; |
5015 | } | 5015 | } |
5016 | 5016 | ||
5017 | // Materials capable viewers can send a ObjectImage packet | ||
5018 | // when nothing in TE has changed. MaterialID should be updated | ||
5019 | // by the RenderMaterials CAP handler, so updating it here may cause a | ||
5020 | // race condtion. Therefore, if no non-materials TE fields have changed, | ||
5021 | // we should ignore any changes and not update Shape.TextureEntry | ||
5022 | |||
5023 | bool otherFieldsChanged = false; | ||
5024 | |||
5017 | for (int i = 0 ; i < GetNumberOfSides(); i++) | 5025 | for (int i = 0 ; i < GetNumberOfSides(); i++) |
5018 | { | 5026 | { |
5019 | 5027 | ||
@@ -5040,18 +5048,36 @@ namespace OpenSim.Region.Framework.Scenes | |||
5040 | // Max change, skip the rest of testing | 5048 | // Max change, skip the rest of testing |
5041 | if (changeFlags == (Changed.TEXTURE | Changed.COLOR)) | 5049 | if (changeFlags == (Changed.TEXTURE | Changed.COLOR)) |
5042 | break; | 5050 | break; |
5051 | |||
5052 | if (!otherFieldsChanged) | ||
5053 | { | ||
5054 | if (oldFace.Bump != newFace.Bump) otherFieldsChanged = true; | ||
5055 | if (oldFace.Fullbright != newFace.Fullbright) otherFieldsChanged = true; | ||
5056 | if (oldFace.Glow != newFace.Glow) otherFieldsChanged = true; | ||
5057 | if (oldFace.MediaFlags != newFace.MediaFlags) otherFieldsChanged = true; | ||
5058 | if (oldFace.OffsetU != newFace.OffsetU) otherFieldsChanged = true; | ||
5059 | if (oldFace.OffsetV != newFace.OffsetV) otherFieldsChanged = true; | ||
5060 | if (oldFace.RepeatU != newFace.RepeatU) otherFieldsChanged = true; | ||
5061 | if (oldFace.RepeatV != newFace.RepeatV) otherFieldsChanged = true; | ||
5062 | if (oldFace.Rotation != newFace.Rotation) otherFieldsChanged = true; | ||
5063 | if (oldFace.Shiny != newFace.Shiny) otherFieldsChanged = true; | ||
5064 | if (oldFace.TexMapType != newFace.TexMapType) otherFieldsChanged = true; | ||
5065 | } | ||
5043 | } | 5066 | } |
5044 | 5067 | ||
5045 | m_shape.TextureEntry = newTex.GetBytes(); | 5068 | if (changeFlags != 0 || otherFieldsChanged) |
5046 | if (changeFlags != 0) | 5069 | { |
5047 | TriggerScriptChangedEvent(changeFlags); | 5070 | m_shape.TextureEntry = newTex.GetBytes(); |
5048 | UpdateFlag = UpdateRequired.FULL; | 5071 | if (changeFlags != 0) |
5049 | ParentGroup.HasGroupChanged = true; | 5072 | TriggerScriptChangedEvent(changeFlags); |
5073 | UpdateFlag = UpdateRequired.FULL; | ||
5074 | ParentGroup.HasGroupChanged = true; | ||
5050 | 5075 | ||
5051 | //This is madness.. | 5076 | //This is madness.. |
5052 | //ParentGroup.ScheduleGroupForFullUpdate(); | 5077 | //ParentGroup.ScheduleGroupForFullUpdate(); |
5053 | //This is sparta | 5078 | //This is sparta |
5054 | ScheduleFullUpdate(); | 5079 | ScheduleFullUpdate(); |
5080 | } | ||
5055 | } | 5081 | } |
5056 | 5082 | ||
5057 | 5083 | ||
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 0ab267a..4ae0eb1 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -78,7 +78,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
78 | // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); | 78 | // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); |
79 | // } | 79 | // } |
80 | 80 | ||
81 | private void TriggerScenePresenceUpdated() | 81 | public void TriggerScenePresenceUpdated() |
82 | { | 82 | { |
83 | if (m_scene != null) | 83 | if (m_scene != null) |
84 | m_scene.EventManager.TriggerScenePresenceUpdated(this); | 84 | m_scene.EventManager.TriggerScenePresenceUpdated(this); |
@@ -1550,6 +1550,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1550 | // Create child agents in neighbouring regions | 1550 | // Create child agents in neighbouring regions |
1551 | if (openChildAgents && !IsChildAgent) | 1551 | if (openChildAgents && !IsChildAgent) |
1552 | { | 1552 | { |
1553 | // Remember in HandleUseCircuitCode, we delayed this to here | ||
1554 | SendInitialDataToMe(); | ||
1553 | 1555 | ||
1554 | IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); | 1556 | IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); |
1555 | if (m_agentTransfer != null) | 1557 | if (m_agentTransfer != null) |
@@ -2308,6 +2310,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2308 | AddToPhysicalScene(false); | 2310 | AddToPhysicalScene(false); |
2309 | 2311 | ||
2310 | Animator.TrySetMovementAnimation("STAND"); | 2312 | Animator.TrySetMovementAnimation("STAND"); |
2313 | TriggerScenePresenceUpdated(); | ||
2311 | } | 2314 | } |
2312 | 2315 | ||
2313 | private SceneObjectPart FindNextAvailableSitTarget(UUID targetID) | 2316 | private SceneObjectPart FindNextAvailableSitTarget(UUID targetID) |
@@ -2406,7 +2409,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2406 | ControllingClient.SendSitResponse( | 2409 | ControllingClient.SendSitResponse( |
2407 | part.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); | 2410 | part.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); |
2408 | 2411 | ||
2409 | m_requestedSitTargetUUID = targetID; | 2412 | m_requestedSitTargetUUID = part.UUID; |
2410 | 2413 | ||
2411 | HandleAgentSit(ControllingClient, UUID); | 2414 | HandleAgentSit(ControllingClient, UUID); |
2412 | 2415 | ||
@@ -2434,7 +2437,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2434 | if (part != null) | 2437 | if (part != null) |
2435 | { | 2438 | { |
2436 | m_requestedSitTargetID = part.LocalId; | 2439 | m_requestedSitTargetID = part.LocalId; |
2437 | m_requestedSitTargetUUID = targetID; | 2440 | m_requestedSitTargetUUID = part.UUID; |
2438 | 2441 | ||
2439 | } | 2442 | } |
2440 | else | 2443 | else |
@@ -2633,6 +2636,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2633 | } | 2636 | } |
2634 | Animator.TrySetMovementAnimation(sitAnimation); | 2637 | Animator.TrySetMovementAnimation(sitAnimation); |
2635 | SendAvatarDataToAllAgents(); | 2638 | SendAvatarDataToAllAgents(); |
2639 | TriggerScenePresenceUpdated(); | ||
2636 | } | 2640 | } |
2637 | } | 2641 | } |
2638 | 2642 | ||
@@ -2641,6 +2645,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2641 | // m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.. | 2645 | // m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.. |
2642 | m_AngularVelocity = Vector3.Zero; | 2646 | m_AngularVelocity = Vector3.Zero; |
2643 | Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); | 2647 | Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); |
2648 | TriggerScenePresenceUpdated(); | ||
2644 | SitGround = true; | 2649 | SitGround = true; |
2645 | RemoveFromPhysicalScene(); | 2650 | RemoveFromPhysicalScene(); |
2646 | } | 2651 | } |
@@ -2657,11 +2662,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2657 | public void HandleStartAnim(IClientAPI remoteClient, UUID animID) | 2662 | public void HandleStartAnim(IClientAPI remoteClient, UUID animID) |
2658 | { | 2663 | { |
2659 | Animator.AddAnimation(animID, UUID.Zero); | 2664 | Animator.AddAnimation(animID, UUID.Zero); |
2665 | TriggerScenePresenceUpdated(); | ||
2660 | } | 2666 | } |
2661 | 2667 | ||
2662 | public void HandleStopAnim(IClientAPI remoteClient, UUID animID) | 2668 | public void HandleStopAnim(IClientAPI remoteClient, UUID animID) |
2663 | { | 2669 | { |
2664 | Animator.RemoveAnimation(animID, false); | 2670 | Animator.RemoveAnimation(animID, false); |
2671 | TriggerScenePresenceUpdated(); | ||
2665 | } | 2672 | } |
2666 | 2673 | ||
2667 | public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack) | 2674 | public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack) |
@@ -3347,10 +3354,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3347 | if (byebyeRegions.Count > 0) | 3354 | if (byebyeRegions.Count > 0) |
3348 | { | 3355 | { |
3349 | m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); | 3356 | m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); |
3350 | Util.FireAndForget(delegate | 3357 | |
3351 | { | 3358 | m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, byebyeRegions); |
3352 | m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, byebyeRegions); | ||
3353 | }); | ||
3354 | } | 3359 | } |
3355 | 3360 | ||
3356 | foreach (ulong handle in byebyeRegions) | 3361 | foreach (ulong handle in byebyeRegions) |
@@ -3693,7 +3698,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3693 | 3698 | ||
3694 | // if (m_updateCount > 0) | 3699 | // if (m_updateCount > 0) |
3695 | // { | 3700 | // { |
3696 | Animator.UpdateMovementAnimations(); | 3701 | if (Animator.UpdateMovementAnimations()) |
3702 | TriggerScenePresenceUpdated(); | ||
3697 | // m_updateCount--; | 3703 | // m_updateCount--; |
3698 | // } | 3704 | // } |
3699 | 3705 | ||
diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs index 5398ab9..bf32251 100644 --- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs +++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs | |||
@@ -290,6 +290,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
290 | 290 | ||
291 | private void statsHeartBeat(object sender, EventArgs e) | 291 | private void statsHeartBeat(object sender, EventArgs e) |
292 | { | 292 | { |
293 | if (!m_scene.Active) | ||
294 | return; | ||
295 | |||
293 | SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[23]; | 296 | SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[23]; |
294 | SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock(); | 297 | SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock(); |
295 | 298 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs index 52ad538..d670dad 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs | |||
@@ -33,7 +33,9 @@ using NUnit.Framework; | |||
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | 35 | using OpenSim.Framework.Communications; |
36 | using OpenSim.Region.CoreModules.Framework.EntityTransfer; | ||
36 | using OpenSim.Region.CoreModules.Framework.InventoryAccess; | 37 | using OpenSim.Region.CoreModules.Framework.InventoryAccess; |
38 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | ||
37 | using OpenSim.Region.CoreModules.World.Permissions; | 39 | using OpenSim.Region.CoreModules.World.Permissions; |
38 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
39 | using OpenSim.Services.Interfaces; | 41 | using OpenSim.Services.Interfaces; |
@@ -52,6 +54,24 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
52 | [TestFixture] | 54 | [TestFixture] |
53 | public class SceneObjectDeRezTests : OpenSimTestCase | 55 | public class SceneObjectDeRezTests : OpenSimTestCase |
54 | { | 56 | { |
57 | [TestFixtureSetUp] | ||
58 | public void FixtureInit() | ||
59 | { | ||
60 | // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. | ||
61 | // This facility was added after the original async delete tests were written, so it may be possible now | ||
62 | // to not bother explicitly disabling their async (since everything will be running sync). | ||
63 | Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; | ||
64 | } | ||
65 | |||
66 | [TestFixtureTearDown] | ||
67 | public void TearDown() | ||
68 | { | ||
69 | // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple | ||
70 | // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression | ||
71 | // tests really shouldn't). | ||
72 | Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; | ||
73 | } | ||
74 | |||
55 | /// <summary> | 75 | /// <summary> |
56 | /// Test deleting an object from a scene. | 76 | /// Test deleting an object from a scene. |
57 | /// </summary> | 77 | /// </summary> |
@@ -59,46 +79,96 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
59 | public void TestDeRezSceneObject() | 79 | public void TestDeRezSceneObject() |
60 | { | 80 | { |
61 | TestHelpers.InMethod(); | 81 | TestHelpers.InMethod(); |
62 | // log4net.Config.XmlConfigurator.Configure(); | ||
63 | 82 | ||
64 | UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); | 83 | UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); |
65 | 84 | ||
66 | TestScene scene = new SceneHelpers().SetupScene(); | 85 | TestScene scene = new SceneHelpers().SetupScene(); |
67 | IConfigSource configSource = new IniConfigSource(); | 86 | SceneHelpers.SetupSceneModules(scene, new PermissionsModule()); |
68 | IConfig config = configSource.AddConfig("Startup"); | 87 | TestClient client = (TestClient)SceneHelpers.AddScenePresence(scene, userId).ControllingClient; |
69 | config.Set("serverside_object_permissions", true); | ||
70 | SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); | ||
71 | IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; | ||
72 | 88 | ||
73 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. | 89 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. |
74 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; | 90 | AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; |
75 | sogd.Enabled = false; | 91 | sogd.Enabled = false; |
76 | 92 | ||
77 | SceneObjectPart part | 93 | SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "so1", userId); |
78 | = new SceneObjectPart(userId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero); | 94 | uint soLocalId = so.LocalId; |
79 | part.Name = "obj1"; | ||
80 | scene.AddNewSceneObject(new SceneObjectGroup(part), false); | ||
81 | 95 | ||
82 | List<uint> localIds = new List<uint>(); | 96 | List<uint> localIds = new List<uint>(); |
83 | localIds.Add(part.LocalId); | 97 | localIds.Add(so.LocalId); |
84 | scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); | 98 | scene.DeRezObjects(client, localIds, UUID.Zero, DeRezAction.Delete, UUID.Zero); |
85 | 99 | ||
86 | // Check that object isn't deleted until we crank the sogd handle. | 100 | // Check that object isn't deleted until we crank the sogd handle. |
87 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); | 101 | SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); |
88 | Assert.That(retrievedPart, Is.Not.Null); | 102 | Assert.That(retrievedPart, Is.Not.Null); |
89 | Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); | 103 | Assert.That(retrievedPart.ParentGroup.IsDeleted, Is.False); |
90 | 104 | ||
91 | sogd.InventoryDeQueueAndDelete(); | 105 | sogd.InventoryDeQueueAndDelete(); |
92 | 106 | ||
93 | SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId); | 107 | SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); |
94 | Assert.That(retrievedPart2, Is.Null); | 108 | Assert.That(retrievedPart2, Is.Null); |
109 | |||
110 | Assert.That(client.ReceivedKills.Count, Is.EqualTo(1)); | ||
111 | Assert.That(client.ReceivedKills[0], Is.EqualTo(soLocalId)); | ||
112 | } | ||
113 | |||
114 | /// <summary> | ||
115 | /// Test that child and root agents correctly receive KillObject notifications. | ||
116 | /// </summary> | ||
117 | [Test] | ||
118 | public void TestDeRezSceneObjectToAgents() | ||
119 | { | ||
120 | TestHelpers.InMethod(); | ||
121 | // TestHelpers.EnableLogging(); | ||
122 | |||
123 | SceneHelpers sh = new SceneHelpers(); | ||
124 | TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); | ||
125 | TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999); | ||
126 | |||
127 | // We need this so that the creation of the root client for userB in sceneB can trigger the creation of a child client in sceneA | ||
128 | LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); | ||
129 | EntityTransferModule etmB = new EntityTransferModule(); | ||
130 | IConfigSource config = new IniConfigSource(); | ||
131 | IConfig modulesConfig = config.AddConfig("Modules"); | ||
132 | modulesConfig.Set("EntityTransferModule", etmB.Name); | ||
133 | modulesConfig.Set("SimulationServices", lscm.Name); | ||
134 | SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); | ||
135 | SceneHelpers.SetupSceneModules(sceneB, config, etmB); | ||
136 | |||
137 | // We need this for derez | ||
138 | SceneHelpers.SetupSceneModules(sceneA, new PermissionsModule()); | ||
139 | |||
140 | UserAccount uaA = UserAccountHelpers.CreateUserWithInventory(sceneA, "Andy", "AAA", 0x1, ""); | ||
141 | UserAccount uaB = UserAccountHelpers.CreateUserWithInventory(sceneA, "Brian", "BBB", 0x2, ""); | ||
142 | |||
143 | TestClient clientA = (TestClient)SceneHelpers.AddScenePresence(sceneA, uaA).ControllingClient; | ||
144 | |||
145 | // This is the more long-winded route we have to take to get a child client created for userB in sceneA | ||
146 | // rather than just calling AddScenePresence() as for userA | ||
147 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(uaB); | ||
148 | TestClient clientB = new TestClient(acd, sceneB); | ||
149 | List<TestClient> childClientsB = new List<TestClient>(); | ||
150 | EntityTransferHelpers.SetUpInformClientOfNeighbour(clientB, childClientsB); | ||
151 | |||
152 | SceneHelpers.AddScenePresence(sceneB, clientB, acd); | ||
153 | |||
154 | SceneObjectGroup so = SceneHelpers.AddSceneObject(sceneA); | ||
155 | uint soLocalId = so.LocalId; | ||
156 | |||
157 | sceneA.DeleteSceneObject(so, false); | ||
158 | |||
159 | Assert.That(clientA.ReceivedKills.Count, Is.EqualTo(1)); | ||
160 | Assert.That(clientA.ReceivedKills[0], Is.EqualTo(soLocalId)); | ||
161 | |||
162 | Assert.That(childClientsB[0].ReceivedKills.Count, Is.EqualTo(1)); | ||
163 | Assert.That(childClientsB[0].ReceivedKills[0], Is.EqualTo(soLocalId)); | ||
95 | } | 164 | } |
96 | 165 | ||
97 | /// <summary> | 166 | /// <summary> |
98 | /// Test deleting an object from a scene where the deleter is not the owner | 167 | /// Test deleting an object from a scene where the deleter is not the owner |
99 | /// </summary> | 168 | /// </summary> |
100 | /// | 169 | /// <remarks> |
101 | /// This test assumes that the deleter is not a god. | 170 | /// This test assumes that the deleter is not a god. |
171 | /// </remarks> | ||
102 | [Test] | 172 | [Test] |
103 | public void TestDeRezSceneObjectNotOwner() | 173 | public void TestDeRezSceneObjectNotOwner() |
104 | { | 174 | { |
@@ -109,10 +179,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
109 | UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001"); | 179 | UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001"); |
110 | 180 | ||
111 | TestScene scene = new SceneHelpers().SetupScene(); | 181 | TestScene scene = new SceneHelpers().SetupScene(); |
112 | IConfigSource configSource = new IniConfigSource(); | 182 | SceneHelpers.SetupSceneModules(scene, new PermissionsModule()); |
113 | IConfig config = configSource.AddConfig("Startup"); | ||
114 | config.Set("serverside_object_permissions", true); | ||
115 | SceneHelpers.SetupSceneModules(scene, configSource, new object[] { new PermissionsModule() }); | ||
116 | IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; | 183 | IClientAPI client = SceneHelpers.AddScenePresence(scene, userId).ControllingClient; |
117 | 184 | ||
118 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. | 185 | // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs index 8775949..5a72239 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceCrossingTests.cs | |||
@@ -95,11 +95,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
95 | SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); | 95 | SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); |
96 | 96 | ||
97 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); | 97 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); |
98 | TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); | 98 | TestClient tc = new TestClient(acd, sceneA); |
99 | List<TestClient> destinationTestClients = new List<TestClient>(); | 99 | List<TestClient> destinationTestClients = new List<TestClient>(); |
100 | EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); | 100 | EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); |
101 | 101 | ||
102 | ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); | 102 | ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, tc, acd); |
103 | originalSp.AbsolutePosition = new Vector3(128, 32, 10); | 103 | originalSp.AbsolutePosition = new Vector3(128, 32, 10); |
104 | 104 | ||
105 | // originalSp.Flying = true; | 105 | // originalSp.Flying = true; |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index de4458d..297c66b 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs | |||
@@ -139,7 +139,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
139 | Vector3 teleportPosition = new Vector3(10, 11, 12); | 139 | Vector3 teleportPosition = new Vector3(10, 11, 12); |
140 | Vector3 teleportLookAt = new Vector3(20, 21, 22); | 140 | Vector3 teleportLookAt = new Vector3(20, 21, 22); |
141 | 141 | ||
142 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); | 142 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); |
143 | sp.AbsolutePosition = new Vector3(30, 31, 32); | 143 | sp.AbsolutePosition = new Vector3(30, 31, 32); |
144 | 144 | ||
145 | List<TestClient> destinationTestClients = new List<TestClient>(); | 145 | List<TestClient> destinationTestClients = new List<TestClient>(); |
@@ -224,7 +224,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
224 | Vector3 teleportPosition = new Vector3(10, 11, 12); | 224 | Vector3 teleportPosition = new Vector3(10, 11, 12); |
225 | Vector3 teleportLookAt = new Vector3(20, 21, 22); | 225 | Vector3 teleportLookAt = new Vector3(20, 21, 22); |
226 | 226 | ||
227 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); | 227 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); |
228 | sp.AbsolutePosition = preTeleportPosition; | 228 | sp.AbsolutePosition = preTeleportPosition; |
229 | 229 | ||
230 | // Make sceneB return false on query access | 230 | // Make sceneB return false on query access |
@@ -300,7 +300,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
300 | Vector3 teleportPosition = new Vector3(10, 11, 12); | 300 | Vector3 teleportPosition = new Vector3(10, 11, 12); |
301 | Vector3 teleportLookAt = new Vector3(20, 21, 22); | 301 | Vector3 teleportLookAt = new Vector3(20, 21, 22); |
302 | 302 | ||
303 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); | 303 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); |
304 | sp.AbsolutePosition = preTeleportPosition; | 304 | sp.AbsolutePosition = preTeleportPosition; |
305 | 305 | ||
306 | // Make sceneB refuse CreateAgent | 306 | // Make sceneB refuse CreateAgent |
@@ -389,7 +389,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
389 | Vector3 teleportPosition = new Vector3(10, 11, 12); | 389 | Vector3 teleportPosition = new Vector3(10, 11, 12); |
390 | Vector3 teleportLookAt = new Vector3(20, 21, 22); | 390 | Vector3 teleportLookAt = new Vector3(20, 21, 22); |
391 | 391 | ||
392 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); | 392 | ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); |
393 | sp.AbsolutePosition = preTeleportPosition; | 393 | sp.AbsolutePosition = preTeleportPosition; |
394 | 394 | ||
395 | sceneA.RequestTeleportLocation( | 395 | sceneA.RequestTeleportLocation( |
@@ -428,7 +428,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
428 | public void TestSameSimulatorNeighbouringRegions() | 428 | public void TestSameSimulatorNeighbouringRegions() |
429 | { | 429 | { |
430 | TestHelpers.InMethod(); | 430 | TestHelpers.InMethod(); |
431 | TestHelpers.EnableLogging(); | 431 | // TestHelpers.EnableLogging(); |
432 | 432 | ||
433 | UUID userId = TestHelpers.ParseTail(0x1); | 433 | UUID userId = TestHelpers.ParseTail(0x1); |
434 | 434 | ||
@@ -458,11 +458,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests | |||
458 | Vector3 teleportLookAt = new Vector3(20, 21, 22); | 458 | Vector3 teleportLookAt = new Vector3(20, 21, 22); |
459 | 459 | ||
460 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); | 460 | AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); |
461 | TestClient tc = new TestClient(acd, sceneA, sh.SceneManager); | 461 | TestClient tc = new TestClient(acd, sceneA); |
462 | List<TestClient> destinationTestClients = new List<TestClient>(); | 462 | List<TestClient> destinationTestClients = new List<TestClient>(); |
463 | EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); | 463 | EntityTransferHelpers.SetUpInformClientOfNeighbour(tc, destinationTestClients); |
464 | 464 | ||
465 | ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd, sh.SceneManager); | 465 | ScenePresence beforeSceneASp = SceneHelpers.AddScenePresence(sceneA, tc, acd); |
466 | beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32); | 466 | beforeSceneASp.AbsolutePosition = new Vector3(30, 31, 32); |
467 | 467 | ||
468 | Assert.That(beforeSceneASp, Is.Not.Null); | 468 | Assert.That(beforeSceneASp, Is.Not.Null); |
diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index b09ae39..7b47275 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs | |||
@@ -34,6 +34,7 @@ using System.Threading; | |||
34 | using log4net; | 34 | using log4net; |
35 | using OpenMetaverse; | 35 | using OpenMetaverse; |
36 | using OpenMetaverse.Assets; | 36 | using OpenMetaverse.Assets; |
37 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
38 | using OpenSim.Region.Framework.Scenes.Serialization; | 39 | using OpenSim.Region.Framework.Scenes.Serialization; |
39 | using OpenSim.Services.Interfaces; | 40 | using OpenSim.Services.Interfaces; |
@@ -180,6 +181,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
180 | if (!assetUuids.ContainsKey(tii.AssetID)) | 181 | if (!assetUuids.ContainsKey(tii.AssetID)) |
181 | GatherAssetUuids(tii.AssetID, (AssetType)tii.Type, assetUuids); | 182 | GatherAssetUuids(tii.AssetID, (AssetType)tii.Type, assetUuids); |
182 | } | 183 | } |
184 | |||
185 | // get any texture UUIDs used for materials such as normal and specular maps | ||
186 | GatherMaterialsUuids(part, assetUuids); | ||
183 | } | 187 | } |
184 | catch (Exception e) | 188 | catch (Exception e) |
185 | { | 189 | { |
@@ -204,6 +208,68 @@ namespace OpenSim.Region.Framework.Scenes | |||
204 | // } | 208 | // } |
205 | // } | 209 | // } |
206 | 210 | ||
211 | |||
212 | /// <summary> | ||
213 | /// Gather all of the texture asset UUIDs used to reference "Materials" such as normal and specular maps | ||
214 | /// </summary> | ||
215 | /// <param name="part"></param> | ||
216 | /// <param name="assetUuids"></param> | ||
217 | public void GatherMaterialsUuids(SceneObjectPart part, IDictionary<UUID, AssetType> assetUuids) | ||
218 | { | ||
219 | // scan thru the dynAttrs map of this part for any textures used as materials | ||
220 | OSDMap OSMaterials = null; | ||
221 | |||
222 | lock (part.DynAttrs) | ||
223 | { | ||
224 | if (part.DynAttrs.ContainsKey("OS:Materials")) | ||
225 | OSMaterials = part.DynAttrs["OS:Materials"]; | ||
226 | if (OSMaterials != null && OSMaterials.ContainsKey("Materials")) | ||
227 | { | ||
228 | OSD osd = OSMaterials["Materials"]; | ||
229 | //m_log.Info("[UUID Gatherer]: found Materials: " + OSDParser.SerializeJsonString(osd)); | ||
230 | |||
231 | if (osd is OSDArray) | ||
232 | { | ||
233 | OSDArray matsArr = osd as OSDArray; | ||
234 | foreach (OSDMap matMap in matsArr) | ||
235 | { | ||
236 | try | ||
237 | { | ||
238 | if (matMap.ContainsKey("Material")) | ||
239 | { | ||
240 | OSDMap mat = matMap["Material"] as OSDMap; | ||
241 | if (mat.ContainsKey("NormMap")) | ||
242 | { | ||
243 | UUID normalMapId = mat["NormMap"].AsUUID(); | ||
244 | if (normalMapId != UUID.Zero) | ||
245 | { | ||
246 | assetUuids[normalMapId] = AssetType.Texture; | ||
247 | //m_log.Info("[UUID Gatherer]: found normal map ID: " + normalMapId.ToString()); | ||
248 | } | ||
249 | } | ||
250 | if (mat.ContainsKey("SpecMap")) | ||
251 | { | ||
252 | UUID specularMapId = mat["SpecMap"].AsUUID(); | ||
253 | if (specularMapId != UUID.Zero) | ||
254 | { | ||
255 | assetUuids[specularMapId] = AssetType.Texture; | ||
256 | //m_log.Info("[UUID Gatherer]: found specular map ID: " + specularMapId.ToString()); | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | |||
261 | } | ||
262 | catch (Exception e) | ||
263 | { | ||
264 | m_log.Warn("[UUID Gatherer]: exception getting materials: " + e.Message); | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | } | ||
269 | } | ||
270 | } | ||
271 | |||
272 | |||
207 | /// <summary> | 273 | /// <summary> |
208 | /// Get an asset synchronously, potentially using an asynchronous callback. If the | 274 | /// Get an asset synchronously, potentially using an asynchronous callback. If the |
209 | /// asynchronous callback is used, we will wait for it to complete. | 275 | /// asynchronous callback is used, we will wait for it to complete. |
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index dd72cfb..b28d96b 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs | |||
@@ -660,6 +660,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
660 | public event BakeTerrain OnBakeTerrain; | 660 | public event BakeTerrain OnBakeTerrain; |
661 | public event EstateChangeInfo OnEstateChangeInfo; | 661 | public event EstateChangeInfo OnEstateChangeInfo; |
662 | public event EstateManageTelehub OnEstateManageTelehub; | 662 | public event EstateManageTelehub OnEstateManageTelehub; |
663 | public event CachedTextureRequest OnCachedTextureRequest; | ||
663 | public event SetAppearance OnSetAppearance; | 664 | public event SetAppearance OnSetAppearance; |
664 | public event AvatarNowWearing OnAvatarNowWearing; | 665 | public event AvatarNowWearing OnAvatarNowWearing; |
665 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; | 666 | public event RezSingleAttachmentFromInv OnRezSingleAttachmentFromInv; |
@@ -943,13 +944,18 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server | |||
943 | { | 944 | { |
944 | 945 | ||
945 | } | 946 | } |
947 | |||
948 | public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures) | ||
949 | { | ||
946 | 950 | ||
951 | } | ||
952 | |||
947 | public void SendStartPingCheck(byte seq) | 953 | public void SendStartPingCheck(byte seq) |
948 | { | 954 | { |
949 | 955 | ||
950 | } | 956 | } |
951 | 957 | ||
952 | public void SendKillObject(ulong regionHandle, List<uint> localID) | 958 | public void SendKillObject(List<uint> localID) |
953 | { | 959 | { |
954 | 960 | ||
955 | } | 961 | } |
diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs index 018357a..c48e585 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs | |||
@@ -375,11 +375,13 @@ namespace OpenSim.Region.OptionalModules.Avatar.Concierge | |||
375 | scene.GetRootAgentCount(), scene.RegionInfo.RegionName, | 375 | scene.GetRootAgentCount(), scene.RegionInfo.RegionName, |
376 | scene.RegionInfo.RegionID, | 376 | scene.RegionInfo.RegionID, |
377 | DateTime.UtcNow.ToString("s"))); | 377 | DateTime.UtcNow.ToString("s"))); |
378 | |||
378 | scene.ForEachRootScenePresence(delegate(ScenePresence sp) | 379 | scene.ForEachRootScenePresence(delegate(ScenePresence sp) |
379 | { | 380 | { |
380 | list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", sp.Name, sp.UUID)); | 381 | list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", sp.Name, sp.UUID)); |
381 | list.Append("</avatars>"); | ||
382 | }); | 382 | }); |
383 | |||
384 | list.Append("</avatars>"); | ||
383 | string payload = list.ToString(); | 385 | string payload = list.ToString(); |
384 | 386 | ||
385 | // post via REST to broker | 387 | // post via REST to broker |
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs index e756c70..2f07c42 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs | |||
@@ -117,6 +117,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice | |||
117 | 117 | ||
118 | private IConfig m_config; | 118 | private IConfig m_config; |
119 | 119 | ||
120 | private object m_Lock; | ||
121 | |||
120 | public void Initialise(IConfigSource config) | 122 | public void Initialise(IConfigSource config) |
121 | { | 123 | { |
122 | 124 | ||
@@ -128,6 +130,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice | |||
128 | if (!m_config.GetBoolean("enabled", false)) | 130 | if (!m_config.GetBoolean("enabled", false)) |
129 | return; | 131 | return; |
130 | 132 | ||
133 | m_Lock = new object(); | ||
134 | |||
131 | try | 135 | try |
132 | { | 136 | { |
133 | // retrieve configuration variables | 137 | // retrieve configuration variables |
@@ -837,7 +841,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice | |||
837 | requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff); | 841 | requrl = String.Format("{0}&chan_roll_off={1}", requrl, m_vivoxChannelRollOff); |
838 | requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel); | 842 | requrl = String.Format("{0}&chan_dist_model={1}", requrl, m_vivoxChannelDistanceModel); |
839 | requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange); | 843 | requrl = String.Format("{0}&chan_max_range={1}", requrl, m_vivoxChannelMaximumRange); |
840 | requrl = String.Format("{0}&chan_ckamping_distance={1}", requrl, m_vivoxChannelClampingDistance); | 844 | requrl = String.Format("{0}&chan_clamping_distance={1}", requrl, m_vivoxChannelClampingDistance); |
841 | 845 | ||
842 | XmlElement resp = VivoxCall(requrl, true); | 846 | XmlElement resp = VivoxCall(requrl, true); |
843 | if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri)) | 847 | if (XmlFind(resp, "response.level0.body.chan_uri", out channelUri)) |
@@ -1118,25 +1122,32 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice | |||
1118 | 1122 | ||
1119 | doc = new XmlDocument(); | 1123 | doc = new XmlDocument(); |
1120 | 1124 | ||
1121 | try | 1125 | // Let's serialize all calls to Vivox. Most of these are driven by |
1126 | // the clients (CAPs), when the user arrives at the region. We don't | ||
1127 | // want to issue many simultaneous http requests to Vivox, because mono | ||
1128 | // doesn't like that | ||
1129 | lock (m_Lock) | ||
1122 | { | 1130 | { |
1123 | // Otherwise prepare the request | 1131 | try |
1124 | // m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); | 1132 | { |
1133 | // Otherwise prepare the request | ||
1134 | //m_log.DebugFormat("[VivoxVoice] Sending request <{0}>", requrl); | ||
1125 | 1135 | ||
1126 | HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); | 1136 | HttpWebRequest req = (HttpWebRequest)WebRequest.Create(requrl); |
1127 | 1137 | ||
1128 | // We are sending just parameters, no content | 1138 | // We are sending just parameters, no content |
1129 | req.ContentLength = 0; | 1139 | req.ContentLength = 0; |
1130 | 1140 | ||
1131 | // Send request and retrieve the response | 1141 | // Send request and retrieve the response |
1132 | using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse()) | 1142 | using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse()) |
1133 | using (Stream s = rsp.GetResponseStream()) | 1143 | using (Stream s = rsp.GetResponseStream()) |
1134 | using (XmlTextReader rdr = new XmlTextReader(s)) | 1144 | using (XmlTextReader rdr = new XmlTextReader(s)) |
1135 | doc.Load(rdr); | 1145 | doc.Load(rdr); |
1136 | } | 1146 | } |
1137 | catch (Exception e) | 1147 | catch (Exception e) |
1138 | { | 1148 | { |
1139 | m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message); | 1149 | m_log.ErrorFormat("[VivoxVoice] Error in admin call : {0}", e.Message); |
1150 | } | ||
1140 | } | 1151 | } |
1141 | 1152 | ||
1142 | // If we're debugging server responses, dump the whole | 1153 | // If we're debugging server responses, dump the whole |
diff --git a/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs new file mode 100644 index 0000000..4ab6609 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Materials/MaterialsDemoModule.cs | |||
@@ -0,0 +1,579 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Security.Cryptography; // for computing md5 hash | ||
33 | using log4net; | ||
34 | using Mono.Addins; | ||
35 | using Nini.Config; | ||
36 | |||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.StructuredData; | ||
39 | |||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Servers; | ||
42 | using OpenSim.Framework.Servers.HttpServer; | ||
43 | using OpenSim.Region.Framework.Interfaces; | ||
44 | using OpenSim.Region.Framework.Scenes; | ||
45 | |||
46 | using Ionic.Zlib; | ||
47 | |||
48 | // You will need to uncomment these lines if you are adding a region module to some other assembly which does not already | ||
49 | // specify its assembly. Otherwise, the region modules in the assembly will not be picked up when OpenSimulator scans | ||
50 | // the available DLLs | ||
51 | //[assembly: Addin("MaterialsDemoModule", "1.0")] | ||
52 | //[assembly: AddinDependency("OpenSim", "0.5")] | ||
53 | |||
54 | namespace OpenSim.Region.OptionalModules.MaterialsDemoModule | ||
55 | { | ||
56 | /// <summary> | ||
57 | /// | ||
58 | // # # ## ##### # # # # # #### | ||
59 | // # # # # # # ## # # ## # # # | ||
60 | // # # # # # # # # # # # # # # | ||
61 | // # ## # ###### ##### # # # # # # # # ### | ||
62 | // ## ## # # # # # ## # # ## # # | ||
63 | // # # # # # # # # # # # #### | ||
64 | // | ||
65 | // THIS MODULE IS FOR EXPERIMENTAL USE ONLY AND MAY CAUSE REGION OR ASSET CORRUPTION! | ||
66 | // | ||
67 | ////////////// WARNING ////////////////////////////////////////////////////////////////// | ||
68 | /// This is an *Experimental* module for developing support for materials-capable viewers | ||
69 | /// This module should NOT be used in a production environment! It may cause data corruption and | ||
70 | /// viewer crashes. It should be only used to evaluate implementations of materials. | ||
71 | /// | ||
72 | /// Materials are persisted via SceneObjectPart.dynattrs. This is a relatively new feature | ||
73 | /// of OpenSimulator and is not field proven at the time this module was written. Persistence | ||
74 | /// may fail or become corrupt and this could cause viewer crashes due to erroneous materials | ||
75 | /// data being sent to viewers. Materials descriptions might survive IAR, OAR, or other means | ||
76 | /// of archiving however the texture resources used by these materials probably will not as they | ||
77 | /// may not be adequately referenced to ensure proper archiving. | ||
78 | /// | ||
79 | /// | ||
80 | /// | ||
81 | /// To enable this module, add this string at the bottom of OpenSim.ini: | ||
82 | /// [MaterialsDemoModule] | ||
83 | /// | ||
84 | /// </summary> | ||
85 | /// | ||
86 | |||
87 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MaterialsDemoModule")] | ||
88 | public class MaterialsDemoModule : INonSharedRegionModule | ||
89 | { | ||
90 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
91 | |||
92 | public string Name { get { return "MaterialsDemoModule"; } } | ||
93 | |||
94 | public Type ReplaceableInterface { get { return null; } } | ||
95 | |||
96 | private Scene m_scene = null; | ||
97 | private bool m_enabled = false; | ||
98 | |||
99 | public Dictionary<UUID, OSDMap> m_knownMaterials = new Dictionary<UUID, OSDMap>(); | ||
100 | |||
101 | public void Initialise(IConfigSource source) | ||
102 | { | ||
103 | m_enabled = (source.Configs["MaterialsDemoModule"] != null); | ||
104 | if (!m_enabled) | ||
105 | return; | ||
106 | |||
107 | m_log.DebugFormat("[MaterialsDemoModule]: INITIALIZED MODULE"); | ||
108 | } | ||
109 | |||
110 | public void Close() | ||
111 | { | ||
112 | if (!m_enabled) | ||
113 | return; | ||
114 | |||
115 | m_log.DebugFormat("[MaterialsDemoModule]: CLOSED MODULE"); | ||
116 | } | ||
117 | |||
118 | public void AddRegion(Scene scene) | ||
119 | { | ||
120 | if (!m_enabled) | ||
121 | return; | ||
122 | |||
123 | m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} ADDED", scene.RegionInfo.RegionName); | ||
124 | m_scene = scene; | ||
125 | m_scene.EventManager.OnRegisterCaps += new EventManager.RegisterCapsEvent(OnRegisterCaps); | ||
126 | m_scene.EventManager.OnObjectAddedToScene += new Action<SceneObjectGroup>(EventManager_OnObjectAddedToScene); | ||
127 | } | ||
128 | |||
129 | void EventManager_OnObjectAddedToScene(SceneObjectGroup obj) | ||
130 | { | ||
131 | foreach (var part in obj.Parts) | ||
132 | if (part != null) | ||
133 | GetStoredMaterialsForPart(part); | ||
134 | } | ||
135 | |||
136 | void OnRegisterCaps(OpenMetaverse.UUID agentID, OpenSim.Framework.Capabilities.Caps caps) | ||
137 | { | ||
138 | string capsBase = "/CAPS/" + caps.CapsObjectPath; | ||
139 | |||
140 | IRequestHandler renderMaterialsPostHandler = new RestStreamHandler("POST", capsBase + "/", RenderMaterialsPostCap); | ||
141 | caps.RegisterHandler("RenderMaterials", renderMaterialsPostHandler); | ||
142 | |||
143 | // OpenSimulator CAPs infrastructure seems to be somewhat hostile towards any CAP that requires both GET | ||
144 | // and POST handlers, (at least at the time this was originally written), so we first set up a POST | ||
145 | // handler normally and then add a GET handler via MainServer | ||
146 | |||
147 | IRequestHandler renderMaterialsGetHandler = new RestStreamHandler("GET", capsBase + "/", RenderMaterialsGetCap); | ||
148 | MainServer.Instance.AddStreamHandler(renderMaterialsGetHandler); | ||
149 | |||
150 | // materials viewer seems to use either POST or PUT, so assign POST handler for PUT as well | ||
151 | IRequestHandler renderMaterialsPutHandler = new RestStreamHandler("PUT", capsBase + "/", RenderMaterialsPostCap); | ||
152 | MainServer.Instance.AddStreamHandler(renderMaterialsPutHandler); | ||
153 | } | ||
154 | |||
155 | public void RemoveRegion(Scene scene) | ||
156 | { | ||
157 | if (!m_enabled) | ||
158 | return; | ||
159 | |||
160 | m_log.DebugFormat("[MaterialsDemoModule]: REGION {0} REMOVED", scene.RegionInfo.RegionName); | ||
161 | } | ||
162 | |||
163 | public void RegionLoaded(Scene scene) | ||
164 | { | ||
165 | } | ||
166 | |||
167 | OSDMap GetMaterial(UUID id) | ||
168 | { | ||
169 | OSDMap map = null; | ||
170 | if (m_knownMaterials.ContainsKey(id)) | ||
171 | { | ||
172 | map = new OSDMap(); | ||
173 | map["ID"] = OSD.FromBinary(id.GetBytes()); | ||
174 | map["Material"] = m_knownMaterials[id]; | ||
175 | } | ||
176 | return map; | ||
177 | } | ||
178 | |||
179 | void GetStoredMaterialsForPart(SceneObjectPart part) | ||
180 | { | ||
181 | OSDMap OSMaterials = null; | ||
182 | OSDArray matsArr = null; | ||
183 | |||
184 | if (part.DynAttrs == null) | ||
185 | { | ||
186 | m_log.Warn("[MaterialsDemoModule]: NULL DYNATTRS :( "); | ||
187 | } | ||
188 | |||
189 | lock (part.DynAttrs) | ||
190 | { | ||
191 | if (part.DynAttrs.ContainsKey("OS:Materials")) | ||
192 | OSMaterials = part.DynAttrs["OS:Materials"]; | ||
193 | if (OSMaterials != null && OSMaterials.ContainsKey("Materials")) | ||
194 | { | ||
195 | |||
196 | OSD osd = OSMaterials["Materials"]; | ||
197 | if (osd is OSDArray) | ||
198 | matsArr = osd as OSDArray; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | if (OSMaterials == null) | ||
203 | return; | ||
204 | |||
205 | m_log.Info("[MaterialsDemoModule]: OSMaterials: " + OSDParser.SerializeJsonString(OSMaterials)); | ||
206 | |||
207 | |||
208 | if (matsArr == null) | ||
209 | { | ||
210 | m_log.Info("[MaterialsDemoModule]: matsArr is null :( "); | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | foreach (OSD elemOsd in matsArr) | ||
215 | { | ||
216 | if (elemOsd != null && elemOsd is OSDMap) | ||
217 | { | ||
218 | |||
219 | OSDMap matMap = elemOsd as OSDMap; | ||
220 | if (matMap.ContainsKey("ID") && matMap.ContainsKey("Material")) | ||
221 | { | ||
222 | try | ||
223 | { | ||
224 | m_knownMaterials[matMap["ID"].AsUUID()] = (OSDMap)matMap["Material"]; | ||
225 | } | ||
226 | catch (Exception e) | ||
227 | { | ||
228 | m_log.Warn("[MaterialsDemoModule]: exception decoding persisted material: " + e.ToString()); | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | |||
235 | |||
236 | void StoreMaterialsForPart(SceneObjectPart part) | ||
237 | { | ||
238 | try | ||
239 | { | ||
240 | if (part == null || part.Shape == null) | ||
241 | return; | ||
242 | |||
243 | Dictionary<UUID, OSDMap> mats = new Dictionary<UUID, OSDMap>(); | ||
244 | |||
245 | Primitive.TextureEntry te = part.Shape.Textures; | ||
246 | |||
247 | if (te.DefaultTexture != null) | ||
248 | { | ||
249 | if (m_knownMaterials.ContainsKey(te.DefaultTexture.MaterialID)) | ||
250 | mats[te.DefaultTexture.MaterialID] = m_knownMaterials[te.DefaultTexture.MaterialID]; | ||
251 | } | ||
252 | |||
253 | if (te.FaceTextures != null) | ||
254 | { | ||
255 | foreach (var face in te.FaceTextures) | ||
256 | { | ||
257 | if (face != null) | ||
258 | { | ||
259 | if (m_knownMaterials.ContainsKey(face.MaterialID)) | ||
260 | mats[face.MaterialID] = m_knownMaterials[face.MaterialID]; | ||
261 | } | ||
262 | } | ||
263 | } | ||
264 | if (mats.Count == 0) | ||
265 | return; | ||
266 | |||
267 | OSDArray matsArr = new OSDArray(); | ||
268 | foreach (KeyValuePair<UUID, OSDMap> kvp in mats) | ||
269 | { | ||
270 | OSDMap matOsd = new OSDMap(); | ||
271 | matOsd["ID"] = OSD.FromUUID(kvp.Key); | ||
272 | matOsd["Material"] = kvp.Value; | ||
273 | matsArr.Add(matOsd); | ||
274 | } | ||
275 | |||
276 | OSDMap OSMaterials = new OSDMap(); | ||
277 | OSMaterials["Materials"] = matsArr; | ||
278 | |||
279 | lock (part.DynAttrs) | ||
280 | part.DynAttrs["OS:Materials"] = OSMaterials; | ||
281 | } | ||
282 | catch (Exception e) | ||
283 | { | ||
284 | m_log.Warn("[MaterialsDemoModule]: exception in StoreMaterialsForPart(): " + e.ToString()); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | |||
289 | public string RenderMaterialsPostCap(string request, string path, | ||
290 | string param, IOSHttpRequest httpRequest, | ||
291 | IOSHttpResponse httpResponse) | ||
292 | { | ||
293 | m_log.Debug("[MaterialsDemoModule]: POST cap handler"); | ||
294 | |||
295 | OSDMap req = (OSDMap)OSDParser.DeserializeLLSDXml(request); | ||
296 | OSDMap resp = new OSDMap(); | ||
297 | |||
298 | OSDMap materialsFromViewer = null; | ||
299 | |||
300 | OSDArray respArr = new OSDArray(); | ||
301 | |||
302 | if (req.ContainsKey("Zipped")) | ||
303 | { | ||
304 | OSD osd = null; | ||
305 | |||
306 | byte[] inBytes = req["Zipped"].AsBinary(); | ||
307 | |||
308 | try | ||
309 | { | ||
310 | osd = ZDecompressBytesToOsd(inBytes); | ||
311 | |||
312 | if (osd != null) | ||
313 | { | ||
314 | if (osd is OSDArray) // assume array of MaterialIDs designating requested material entries | ||
315 | { | ||
316 | foreach (OSD elem in (OSDArray)osd) | ||
317 | { | ||
318 | |||
319 | try | ||
320 | { | ||
321 | UUID id = new UUID(elem.AsBinary(), 0); | ||
322 | |||
323 | if (m_knownMaterials.ContainsKey(id)) | ||
324 | { | ||
325 | m_log.Info("[MaterialsDemoModule]: request for known material ID: " + id.ToString()); | ||
326 | OSDMap matMap = new OSDMap(); | ||
327 | matMap["ID"] = OSD.FromBinary(id.GetBytes()); | ||
328 | |||
329 | matMap["Material"] = m_knownMaterials[id]; | ||
330 | respArr.Add(matMap); | ||
331 | } | ||
332 | else | ||
333 | m_log.Info("[MaterialsDemoModule]: request for UNKNOWN material ID: " + id.ToString()); | ||
334 | } | ||
335 | catch (Exception e) | ||
336 | { | ||
337 | // report something here? | ||
338 | continue; | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | else if (osd is OSDMap) // reqest to assign a material | ||
343 | { | ||
344 | materialsFromViewer = osd as OSDMap; | ||
345 | |||
346 | if (materialsFromViewer.ContainsKey("FullMaterialsPerFace")) | ||
347 | { | ||
348 | OSD matsOsd = materialsFromViewer["FullMaterialsPerFace"]; | ||
349 | if (matsOsd is OSDArray) | ||
350 | { | ||
351 | OSDArray matsArr = matsOsd as OSDArray; | ||
352 | |||
353 | try | ||
354 | { | ||
355 | foreach (OSDMap matsMap in matsArr) | ||
356 | { | ||
357 | m_log.Debug("[MaterialsDemoModule]: processing matsMap: " + OSDParser.SerializeJsonString(matsMap)); | ||
358 | |||
359 | uint matLocalID = 0; | ||
360 | try { matLocalID = matsMap["ID"].AsUInteger(); } | ||
361 | catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"ID\" from matsMap: " + e.Message); } | ||
362 | m_log.Debug("[MaterialsDemoModule]: matLocalId: " + matLocalID.ToString()); | ||
363 | |||
364 | |||
365 | OSDMap mat = null; | ||
366 | try { mat = matsMap["Material"] as OSDMap; } | ||
367 | catch (Exception e) { m_log.Warn("[MaterialsDemoModule]: cannot decode \"Material\" from matsMap: " + e.Message); } | ||
368 | m_log.Debug("[MaterialsDemoModule]: mat: " + OSDParser.SerializeJsonString(mat)); | ||
369 | |||
370 | UUID id = HashOsd(mat); | ||
371 | m_knownMaterials[id] = mat; | ||
372 | |||
373 | |||
374 | var sop = m_scene.GetSceneObjectPart(matLocalID); | ||
375 | if (sop == null) | ||
376 | m_log.Debug("[MaterialsDemoModule]: null SOP for localId: " + matLocalID.ToString()); | ||
377 | else | ||
378 | { | ||
379 | //var te = sop.Shape.Textures; | ||
380 | var te = new Primitive.TextureEntry(sop.Shape.TextureEntry, 0, sop.Shape.TextureEntry.Length); | ||
381 | |||
382 | if (te == null) | ||
383 | { | ||
384 | m_log.Debug("[MaterialsDemoModule]: null TextureEntry for localId: " + matLocalID.ToString()); | ||
385 | } | ||
386 | else | ||
387 | { | ||
388 | int face = -1; | ||
389 | |||
390 | if (matsMap.ContainsKey("Face")) | ||
391 | { | ||
392 | face = matsMap["Face"].AsInteger(); | ||
393 | if (te.FaceTextures == null) // && face == 0) | ||
394 | { | ||
395 | if (te.DefaultTexture == null) | ||
396 | m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture is null"); | ||
397 | else | ||
398 | { | ||
399 | if (te.DefaultTexture.MaterialID == null) | ||
400 | m_log.Debug("[MaterialsDemoModule]: te.DefaultTexture.MaterialID is null"); | ||
401 | else | ||
402 | { | ||
403 | te.DefaultTexture.MaterialID = id; | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | else | ||
408 | { | ||
409 | if (te.FaceTextures.Length >= face - 1) | ||
410 | { | ||
411 | if (te.FaceTextures[face] == null) | ||
412 | te.DefaultTexture.MaterialID = id; | ||
413 | else | ||
414 | te.FaceTextures[face].MaterialID = id; | ||
415 | } | ||
416 | } | ||
417 | } | ||
418 | else | ||
419 | { | ||
420 | if (te.DefaultTexture != null) | ||
421 | te.DefaultTexture.MaterialID = id; | ||
422 | } | ||
423 | |||
424 | m_log.Debug("[MaterialsDemoModule]: setting material ID for face " + face.ToString() + " to " + id.ToString()); | ||
425 | |||
426 | //we cant use sop.UpdateTextureEntry(te); because it filters so do it manually | ||
427 | |||
428 | if (sop.ParentGroup != null) | ||
429 | { | ||
430 | sop.Shape.TextureEntry = te.GetBytes(); | ||
431 | sop.TriggerScriptChangedEvent(Changed.TEXTURE); | ||
432 | sop.UpdateFlag = UpdateRequired.FULL; | ||
433 | sop.ParentGroup.HasGroupChanged = true; | ||
434 | |||
435 | sop.ScheduleFullUpdate(); | ||
436 | |||
437 | StoreMaterialsForPart(sop); | ||
438 | } | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | } | ||
443 | catch (Exception e) | ||
444 | { | ||
445 | m_log.Warn("[MaterialsDemoModule]: exception processing received material: " + e.Message); | ||
446 | } | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | } | ||
451 | |||
452 | } | ||
453 | catch (Exception e) | ||
454 | { | ||
455 | m_log.Warn("[MaterialsDemoModule]: exception decoding zipped CAP payload: " + e.Message); | ||
456 | //return ""; | ||
457 | } | ||
458 | m_log.Debug("[MaterialsDemoModule]: knownMaterials.Count: " + m_knownMaterials.Count.ToString()); | ||
459 | } | ||
460 | |||
461 | |||
462 | resp["Zipped"] = ZCompressOSD(respArr, false); | ||
463 | string response = OSDParser.SerializeLLSDXmlString(resp); | ||
464 | |||
465 | //m_log.Debug("[MaterialsDemoModule]: cap request: " + request); | ||
466 | m_log.Debug("[MaterialsDemoModule]: cap request (zipped portion): " + ZippedOsdBytesToString(req["Zipped"].AsBinary())); | ||
467 | m_log.Debug("[MaterialsDemoModule]: cap response: " + response); | ||
468 | return response; | ||
469 | } | ||
470 | |||
471 | |||
472 | public string RenderMaterialsGetCap(string request, string path, | ||
473 | string param, IOSHttpRequest httpRequest, | ||
474 | IOSHttpResponse httpResponse) | ||
475 | { | ||
476 | m_log.Debug("[MaterialsDemoModule]: GET cap handler"); | ||
477 | |||
478 | OSDMap resp = new OSDMap(); | ||
479 | |||
480 | |||
481 | int matsCount = 0; | ||
482 | |||
483 | OSDArray allOsd = new OSDArray(); | ||
484 | |||
485 | foreach (KeyValuePair<UUID, OSDMap> kvp in m_knownMaterials) | ||
486 | { | ||
487 | OSDMap matMap = new OSDMap(); | ||
488 | |||
489 | matMap["ID"] = OSD.FromBinary(kvp.Key.GetBytes()); | ||
490 | |||
491 | matMap["Material"] = kvp.Value; | ||
492 | allOsd.Add(matMap); | ||
493 | matsCount++; | ||
494 | } | ||
495 | |||
496 | |||
497 | resp["Zipped"] = ZCompressOSD(allOsd, false); | ||
498 | m_log.Debug("[MaterialsDemoModule]: matsCount: " + matsCount.ToString()); | ||
499 | |||
500 | return OSDParser.SerializeLLSDXmlString(resp); | ||
501 | } | ||
502 | |||
503 | static string ZippedOsdBytesToString(byte[] bytes) | ||
504 | { | ||
505 | try | ||
506 | { | ||
507 | return OSDParser.SerializeJsonString(ZDecompressBytesToOsd(bytes)); | ||
508 | } | ||
509 | catch (Exception e) | ||
510 | { | ||
511 | return "ZippedOsdBytesToString caught an exception: " + e.ToString(); | ||
512 | } | ||
513 | } | ||
514 | |||
515 | /// <summary> | ||
516 | /// computes a UUID by hashing a OSD object | ||
517 | /// </summary> | ||
518 | /// <param name="osd"></param> | ||
519 | /// <returns></returns> | ||
520 | private static UUID HashOsd(OSD osd) | ||
521 | { | ||
522 | using (var md5 = MD5.Create()) | ||
523 | using (MemoryStream ms = new MemoryStream(OSDParser.SerializeLLSDBinary(osd, false))) | ||
524 | return new UUID(md5.ComputeHash(ms), 0); | ||
525 | } | ||
526 | |||
527 | public static OSD ZCompressOSD(OSD inOsd, bool useHeader) | ||
528 | { | ||
529 | OSD osd = null; | ||
530 | |||
531 | using (MemoryStream msSinkCompressed = new MemoryStream()) | ||
532 | { | ||
533 | using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkCompressed, | ||
534 | Ionic.Zlib.CompressionMode.Compress, CompressionLevel.BestCompression, true)) | ||
535 | { | ||
536 | CopyStream(new MemoryStream(OSDParser.SerializeLLSDBinary(inOsd, useHeader)), zOut); | ||
537 | zOut.Close(); | ||
538 | } | ||
539 | |||
540 | msSinkCompressed.Seek(0L, SeekOrigin.Begin); | ||
541 | osd = OSD.FromBinary( msSinkCompressed.ToArray()); | ||
542 | } | ||
543 | |||
544 | return osd; | ||
545 | } | ||
546 | |||
547 | |||
548 | public static OSD ZDecompressBytesToOsd(byte[] input) | ||
549 | { | ||
550 | OSD osd = null; | ||
551 | |||
552 | using (MemoryStream msSinkUnCompressed = new MemoryStream()) | ||
553 | { | ||
554 | using (Ionic.Zlib.ZlibStream zOut = new Ionic.Zlib.ZlibStream(msSinkUnCompressed, CompressionMode.Decompress, true)) | ||
555 | { | ||
556 | CopyStream(new MemoryStream(input), zOut); | ||
557 | zOut.Close(); | ||
558 | } | ||
559 | msSinkUnCompressed.Seek(0L, SeekOrigin.Begin); | ||
560 | osd = OSDParser.DeserializeLLSDBinary(msSinkUnCompressed.ToArray()); | ||
561 | } | ||
562 | |||
563 | return osd; | ||
564 | } | ||
565 | |||
566 | static void CopyStream(System.IO.Stream input, System.IO.Stream output) | ||
567 | { | ||
568 | byte[] buffer = new byte[2048]; | ||
569 | int len; | ||
570 | while ((len = input.Read(buffer, 0, 2048)) > 0) | ||
571 | { | ||
572 | output.Write(buffer, 0, len); | ||
573 | } | ||
574 | |||
575 | output.Flush(); | ||
576 | } | ||
577 | |||
578 | } | ||
579 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs index 5d10e93..bcb21d0 100644 --- a/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs +++ b/OpenSim/Region/OptionalModules/World/MoneyModule/SampleMoneyModule.cs | |||
@@ -696,7 +696,7 @@ namespace OpenSim.Region.OptionalModules.World.MoneyModule | |||
696 | /// <param name="agentId"></param> | 696 | /// <param name="agentId"></param> |
697 | public void EconomyDataRequestHandler(IClientAPI user) | 697 | public void EconomyDataRequestHandler(IClientAPI user) |
698 | { | 698 | { |
699 | Scene s = LocateSceneClientIn(user.AgentId); | 699 | Scene s = (Scene)user.Scene; |
700 | 700 | ||
701 | user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, | 701 | user.SendEconomyData(EnergyEfficiency, s.RegionInfo.ObjectCapacity, ObjectCount, PriceEnergyUnit, PriceGroupCreate, |
702 | PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, | 702 | PriceObjectClaim, PriceObjectRent, PriceObjectScaleFactor, PriceParcelClaim, PriceParcelClaimFactor, |
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 4674489..c8aab54 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs | |||
@@ -393,6 +393,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
393 | public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; | 393 | public event EstateTeleportAllUsersHomeRequest OnEstateTeleportAllUsersHomeRequest; |
394 | public event EstateChangeInfo OnEstateChangeInfo; | 394 | public event EstateChangeInfo OnEstateChangeInfo; |
395 | public event EstateManageTelehub OnEstateManageTelehub; | 395 | public event EstateManageTelehub OnEstateManageTelehub; |
396 | public event CachedTextureRequest OnCachedTextureRequest; | ||
396 | public event ScriptReset OnScriptReset; | 397 | public event ScriptReset OnScriptReset; |
397 | public event GetScriptRunning OnGetScriptRunning; | 398 | public event GetScriptRunning OnGetScriptRunning; |
398 | public event SetScriptRunning OnSetScriptRunning; | 399 | public event SetScriptRunning OnSetScriptRunning; |
@@ -573,6 +574,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
573 | { | 574 | { |
574 | } | 575 | } |
575 | 576 | ||
577 | public void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures) | ||
578 | { | ||
579 | |||
580 | } | ||
581 | |||
576 | public virtual void Kick(string message) | 582 | public virtual void Kick(string message) |
577 | { | 583 | { |
578 | } | 584 | } |
@@ -590,7 +596,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC | |||
590 | 596 | ||
591 | } | 597 | } |
592 | 598 | ||
593 | public virtual void SendKillObject(ulong regionHandle, List<uint> localID) | 599 | public virtual void SendKillObject(List<uint> localID) |
594 | { | 600 | { |
595 | } | 601 | } |
596 | 602 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs index 77ea3ed..12a0c17 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | |||
@@ -75,11 +75,11 @@ private sealed class BulletBodyUnman : BulletBody | |||
75 | private sealed class BulletShapeUnman : BulletShape | 75 | private sealed class BulletShapeUnman : BulletShape |
76 | { | 76 | { |
77 | public IntPtr ptr; | 77 | public IntPtr ptr; |
78 | public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) | 78 | public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) |
79 | : base() | 79 | : base() |
80 | { | 80 | { |
81 | ptr = xx; | 81 | ptr = xx; |
82 | type = typ; | 82 | shapeType = typ; |
83 | } | 83 | } |
84 | public override bool HasPhysicalShape | 84 | public override bool HasPhysicalShape |
85 | { | 85 | { |
@@ -91,7 +91,7 @@ private sealed class BulletShapeUnman : BulletShape | |||
91 | } | 91 | } |
92 | public override BulletShape Clone() | 92 | public override BulletShape Clone() |
93 | { | 93 | { |
94 | return new BulletShapeUnman(ptr, type); | 94 | return new BulletShapeUnman(ptr, shapeType); |
95 | } | 95 | } |
96 | public override bool ReferenceSame(BulletShape other) | 96 | public override bool ReferenceSame(BulletShape other) |
97 | { | 97 | { |
@@ -251,23 +251,52 @@ public override BulletShape CreateMeshShape(BulletWorld world, | |||
251 | BSPhysicsShapeType.SHAPE_MESH); | 251 | BSPhysicsShapeType.SHAPE_MESH); |
252 | } | 252 | } |
253 | 253 | ||
254 | public override BulletShape CreateGImpactShape(BulletWorld world, | ||
255 | int indicesCount, int[] indices, | ||
256 | int verticesCount, float[] vertices) | ||
257 | { | ||
258 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
259 | return new BulletShapeUnman( | ||
260 | BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), | ||
261 | BSPhysicsShapeType.SHAPE_GIMPACT); | ||
262 | } | ||
263 | |||
254 | public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) | 264 | public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) |
255 | { | 265 | { |
256 | BulletWorldUnman worldu = world as BulletWorldUnman; | 266 | BulletWorldUnman worldu = world as BulletWorldUnman; |
257 | return new BulletShapeUnman( | 267 | return new BulletShapeUnman( |
258 | BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), | 268 | BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), |
259 | BSPhysicsShapeType.SHAPE_HULL); | 269 | BSPhysicsShapeType.SHAPE_HULL); |
260 | } | 270 | } |
261 | 271 | ||
262 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | 272 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) |
263 | { | 273 | { |
264 | BulletWorldUnman worldu = world as BulletWorldUnman; | 274 | BulletWorldUnman worldu = world as BulletWorldUnman; |
265 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; | 275 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; |
266 | return new BulletShapeUnman( | 276 | return new BulletShapeUnman( |
267 | BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr), | 277 | BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms), |
268 | BSPhysicsShapeType.SHAPE_HULL); | 278 | BSPhysicsShapeType.SHAPE_HULL); |
269 | } | 279 | } |
270 | 280 | ||
281 | public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | ||
282 | { | ||
283 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
284 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; | ||
285 | return new BulletShapeUnman( | ||
286 | BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr), | ||
287 | BSPhysicsShapeType.SHAPE_CONVEXHULL); | ||
288 | } | ||
289 | |||
290 | public override BulletShape CreateConvexHullShape(BulletWorld world, | ||
291 | int indicesCount, int[] indices, | ||
292 | int verticesCount, float[] vertices) | ||
293 | { | ||
294 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
295 | return new BulletShapeUnman( | ||
296 | BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), | ||
297 | BSPhysicsShapeType.SHAPE_CONVEXHULL); | ||
298 | } | ||
299 | |||
271 | public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) | 300 | public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) |
272 | { | 301 | { |
273 | BulletWorldUnman worldu = world as BulletWorldUnman; | 302 | BulletWorldUnman worldu = world as BulletWorldUnman; |
@@ -356,7 +385,7 @@ public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletSha | |||
356 | { | 385 | { |
357 | BulletWorldUnman worldu = world as BulletWorldUnman; | 386 | BulletWorldUnman worldu = world as BulletWorldUnman; |
358 | BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; | 387 | BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; |
359 | return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); | 388 | return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType); |
360 | } | 389 | } |
361 | 390 | ||
362 | public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) | 391 | public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) |
@@ -1407,11 +1436,24 @@ public static extern IntPtr CreateMeshShape2(IntPtr world, | |||
1407 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | 1436 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); |
1408 | 1437 | ||
1409 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1438 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1439 | public static extern IntPtr CreateGImpactShape2(IntPtr world, | ||
1440 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
1441 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
1442 | |||
1443 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1410 | public static extern IntPtr CreateHullShape2(IntPtr world, | 1444 | public static extern IntPtr CreateHullShape2(IntPtr world, |
1411 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); | 1445 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); |
1412 | 1446 | ||
1413 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1447 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1414 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | 1448 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms); |
1449 | |||
1450 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1451 | public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | ||
1452 | |||
1453 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1454 | public static extern IntPtr CreateConvexHullShape2(IntPtr world, | ||
1455 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
1456 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
1415 | 1457 | ||
1416 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1458 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1417 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); | 1459 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); |
@@ -1476,7 +1518,7 @@ public static extern void DestroyObject2(IntPtr sim, IntPtr obj); | |||
1476 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); | 1518 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); |
1477 | 1519 | ||
1478 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1520 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1479 | public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, | 1521 | public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, |
1480 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, | 1522 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, |
1481 | float scaleFactor, float collisionMargin); | 1523 | float scaleFactor, float collisionMargin); |
1482 | 1524 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs index 6fc10e9..6db5f5e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | |||
@@ -81,11 +81,11 @@ private sealed class BulletBodyXNA : BulletBody | |||
81 | private sealed class BulletShapeXNA : BulletShape | 81 | private sealed class BulletShapeXNA : BulletShape |
82 | { | 82 | { |
83 | public CollisionShape shape; | 83 | public CollisionShape shape; |
84 | public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) | 84 | public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) |
85 | : base() | 85 | : base() |
86 | { | 86 | { |
87 | shape = xx; | 87 | shape = xx; |
88 | type = typ; | 88 | shapeType = typ; |
89 | } | 89 | } |
90 | public override bool HasPhysicalShape | 90 | public override bool HasPhysicalShape |
91 | { | 91 | { |
@@ -97,7 +97,7 @@ private sealed class BulletShapeXNA : BulletShape | |||
97 | } | 97 | } |
98 | public override BulletShape Clone() | 98 | public override BulletShape Clone() |
99 | { | 99 | { |
100 | return new BulletShapeXNA(shape, type); | 100 | return new BulletShapeXNA(shape, shapeType); |
101 | } | 101 | } |
102 | public override bool ReferenceSame(BulletShape other) | 102 | public override bool ReferenceSame(BulletShape other) |
103 | { | 103 | { |
@@ -137,8 +137,8 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
137 | internal int LastEntityProperty = 0; | 137 | internal int LastEntityProperty = 0; |
138 | 138 | ||
139 | internal EntityProperties[] UpdatedObjects; | 139 | internal EntityProperties[] UpdatedObjects; |
140 | internal Dictionary<uint, GhostObject> specialCollisionObjects; | 140 | internal Dictionary<uint, GhostObject> specialCollisionObjects; |
141 | 141 | ||
142 | private static int m_collisionsThisFrame; | 142 | private static int m_collisionsThisFrame; |
143 | private BSScene PhysicsScene { get; set; } | 143 | private BSScene PhysicsScene { get; set; } |
144 | 144 | ||
@@ -151,7 +151,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
151 | } | 151 | } |
152 | 152 | ||
153 | /// <summary> | 153 | /// <summary> |
154 | /// | 154 | /// |
155 | /// </summary> | 155 | /// </summary> |
156 | /// <param name="p"></param> | 156 | /// <param name="p"></param> |
157 | /// <param name="p_2"></param> | 157 | /// <param name="p_2"></param> |
@@ -174,7 +174,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
174 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | 174 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
175 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; | 175 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; |
176 | world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); | 176 | world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); |
177 | 177 | ||
178 | return true; | 178 | return true; |
179 | 179 | ||
180 | } | 180 | } |
@@ -300,7 +300,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
300 | public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { | 300 | public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { |
301 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | 301 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
302 | return world.GetForceUpdateAllAabbs(); | 302 | return world.GetForceUpdateAllAabbs(); |
303 | 303 | ||
304 | } | 304 | } |
305 | public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) | 305 | public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) |
306 | { | 306 | { |
@@ -404,7 +404,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
404 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); | 404 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); |
405 | mat._origin = vposition; | 405 | mat._origin = vposition; |
406 | collisionObject.SetWorldTransform(mat); | 406 | collisionObject.SetWorldTransform(mat); |
407 | 407 | ||
408 | } | 408 | } |
409 | 409 | ||
410 | public override Vector3 GetPosition(BulletBody pCollisionObject) | 410 | public override Vector3 GetPosition(BulletBody pCollisionObject) |
@@ -457,7 +457,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
457 | { | 457 | { |
458 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | 458 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
459 | collisionObject.Activate(pforceactivation); | 459 | collisionObject.Activate(pforceactivation); |
460 | 460 | ||
461 | } | 461 | } |
462 | 462 | ||
463 | public override Quaternion GetOrientation(BulletBody pCollisionObject) | 463 | public override Quaternion GetOrientation(BulletBody pCollisionObject) |
@@ -486,7 +486,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
486 | { | 486 | { |
487 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | 487 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
488 | return collisionObject.GetCcdSweptSphereRadius(); | 488 | return collisionObject.GetCcdSweptSphereRadius(); |
489 | 489 | ||
490 | } | 490 | } |
491 | 491 | ||
492 | public override IntPtr GetUserPointer(BulletBody pCollisionObject) | 492 | public override IntPtr GetUserPointer(BulletBody pCollisionObject) |
@@ -559,8 +559,8 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
559 | } | 559 | } |
560 | 560 | ||
561 | 561 | ||
562 | public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | 562 | public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, |
563 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, | 563 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, |
564 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | 564 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) |
565 | 565 | ||
566 | { | 566 | { |
@@ -604,7 +604,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
604 | } | 604 | } |
605 | 605 | ||
606 | /// <summary> | 606 | /// <summary> |
607 | /// | 607 | /// |
608 | /// </summary> | 608 | /// </summary> |
609 | /// <param name="pWorld"></param> | 609 | /// <param name="pWorld"></param> |
610 | /// <param name="pBody1"></param> | 610 | /// <param name="pBody1"></param> |
@@ -824,7 +824,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
824 | { | 824 | { |
825 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | 825 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
826 | float angularDamping = body.GetAngularDamping(); | 826 | float angularDamping = body.GetAngularDamping(); |
827 | body.SetDamping(lin_damping, angularDamping); | 827 | body.SetDamping(lin_damping, angularDamping); |
828 | } | 828 | } |
829 | 829 | ||
830 | public override float GetLinearDamping(BulletBody pBody) | 830 | public override float GetLinearDamping(BulletBody pBody) |
@@ -907,7 +907,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
907 | RigidBody bo = co as RigidBody; | 907 | RigidBody bo = co as RigidBody; |
908 | if (bo == null) | 908 | if (bo == null) |
909 | { | 909 | { |
910 | 910 | ||
911 | if (world.IsInWorld(co)) | 911 | if (world.IsInWorld(co)) |
912 | { | 912 | { |
913 | world.RemoveCollisionObject(co); | 913 | world.RemoveCollisionObject(co); |
@@ -915,7 +915,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
915 | } | 915 | } |
916 | else | 916 | else |
917 | { | 917 | { |
918 | 918 | ||
919 | if (world.IsInWorld(bo)) | 919 | if (world.IsInWorld(bo)) |
920 | { | 920 | { |
921 | world.RemoveRigidBody(bo); | 921 | world.RemoveRigidBody(bo); |
@@ -947,7 +947,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
947 | 947 | ||
948 | // TODO: Turn this from a reference copy to a Value Copy. | 948 | // TODO: Turn this from a reference copy to a Value Copy. |
949 | BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); | 949 | BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); |
950 | 950 | ||
951 | return shape2; | 951 | return shape2; |
952 | } | 952 | } |
953 | 953 | ||
@@ -957,7 +957,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
957 | return false; | 957 | return false; |
958 | } | 958 | } |
959 | //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); | 959 | //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
960 | 960 | ||
961 | public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | 961 | public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) |
962 | { | 962 | { |
963 | CollisionWorld world = (pWorld as BulletWorldXNA).world; | 963 | CollisionWorld world = (pWorld as BulletWorldXNA).world; |
@@ -993,11 +993,11 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
993 | m_startWorldTransform = IndexedMatrix.Identity; | 993 | m_startWorldTransform = IndexedMatrix.Identity; |
994 | */ | 994 | */ |
995 | body.SetUserPointer(pLocalID); | 995 | body.SetUserPointer(pLocalID); |
996 | 996 | ||
997 | return new BulletBodyXNA(pLocalID, body); | 997 | return new BulletBodyXNA(pLocalID, body); |
998 | } | 998 | } |
999 | 999 | ||
1000 | 1000 | ||
1001 | public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | 1001 | public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) |
1002 | { | 1002 | { |
1003 | 1003 | ||
@@ -1025,7 +1025,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1025 | public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) | 1025 | public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) |
1026 | { | 1026 | { |
1027 | 1027 | ||
1028 | /* TODO */ | 1028 | /* TODO */ |
1029 | return Vector3.Zero; | 1029 | return Vector3.Zero; |
1030 | } | 1030 | } |
1031 | public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } | 1031 | public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } |
@@ -1035,7 +1035,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1035 | { | 1035 | { |
1036 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | 1036 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
1037 | return collisionObject.IsStaticObject(); | 1037 | return collisionObject.IsStaticObject(); |
1038 | 1038 | ||
1039 | } | 1039 | } |
1040 | public override bool IsKinematicObject(BulletBody pCollisionObject) | 1040 | public override bool IsKinematicObject(BulletBody pCollisionObject) |
1041 | { | 1041 | { |
@@ -1098,10 +1098,10 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1098 | return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); | 1098 | return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); |
1099 | } | 1099 | } |
1100 | 1100 | ||
1101 | private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, | 1101 | private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, |
1102 | ConfigurationParameters[] o, | 1102 | ConfigurationParameters[] o, |
1103 | int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, | 1103 | int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, |
1104 | int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, | 1104 | int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, |
1105 | object mDebugLogCallbackHandle) | 1105 | object mDebugLogCallbackHandle) |
1106 | { | 1106 | { |
1107 | CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); | 1107 | CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); |
@@ -1138,9 +1138,9 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1138 | p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; | 1138 | p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; |
1139 | p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; | 1139 | p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; |
1140 | p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; | 1140 | p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; |
1141 | 1141 | ||
1142 | p.vehicleAngularDamping = BSParam.VehicleAngularDamping; | 1142 | p.vehicleAngularDamping = BSParam.VehicleAngularDamping; |
1143 | 1143 | ||
1144 | p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; | 1144 | p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; |
1145 | p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; | 1145 | p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; |
1146 | p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; | 1146 | p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; |
@@ -1160,7 +1160,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1160 | p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; | 1160 | p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; |
1161 | p.physicsLoggingFrames = o[0].physicsLoggingFrames; | 1161 | p.physicsLoggingFrames = o[0].physicsLoggingFrames; |
1162 | DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); | 1162 | DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); |
1163 | 1163 | ||
1164 | DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); | 1164 | DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); |
1165 | CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); | 1165 | CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); |
1166 | 1166 | ||
@@ -1263,7 +1263,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1263 | } | 1263 | } |
1264 | } | 1264 | } |
1265 | return ret; | 1265 | return ret; |
1266 | 1266 | ||
1267 | } | 1267 | } |
1268 | 1268 | ||
1269 | public override float GetAngularMotionDisc(BulletShape pShape) | 1269 | public override float GetAngularMotionDisc(BulletShape pShape) |
@@ -1353,10 +1353,10 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1353 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | 1353 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1354 | gObj.SetCollisionShape(shape); | 1354 | gObj.SetCollisionShape(shape); |
1355 | gObj.SetUserPointer(pLocalID); | 1355 | gObj.SetUserPointer(pLocalID); |
1356 | 1356 | ||
1357 | if (specialCollisionObjects.ContainsKey(pLocalID)) | 1357 | if (specialCollisionObjects.ContainsKey(pLocalID)) |
1358 | specialCollisionObjects[pLocalID] = gObj; | 1358 | specialCollisionObjects[pLocalID] = gObj; |
1359 | else | 1359 | else |
1360 | specialCollisionObjects.Add(pLocalID, gObj); | 1360 | specialCollisionObjects.Add(pLocalID, gObj); |
1361 | 1361 | ||
1362 | // TODO: Add to Special CollisionObjects! | 1362 | // TODO: Add to Special CollisionObjects! |
@@ -1447,8 +1447,8 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1447 | return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); | 1447 | return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); |
1448 | } | 1448 | } |
1449 | 1449 | ||
1450 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { | 1450 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { |
1451 | 1451 | ||
1452 | if (cShape == null) | 1452 | if (cShape == null) |
1453 | return null; | 1453 | return null; |
1454 | CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; | 1454 | CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; |
@@ -1456,7 +1456,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1456 | BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); | 1456 | BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); |
1457 | 1457 | ||
1458 | 1458 | ||
1459 | return retShape; | 1459 | return retShape; |
1460 | } | 1460 | } |
1461 | 1461 | ||
1462 | public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) | 1462 | public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) |
@@ -1475,7 +1475,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1475 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 1475 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; |
1476 | break; | 1476 | break; |
1477 | case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: | 1477 | case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: |
1478 | ret = BSPhysicsShapeType.SHAPE_MESH; | 1478 | ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; |
1479 | break; | 1479 | break; |
1480 | case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: | 1480 | case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: |
1481 | ret = BSPhysicsShapeType.SHAPE_HULL; | 1481 | ret = BSPhysicsShapeType.SHAPE_HULL; |
@@ -1503,7 +1503,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1503 | ret = BSPhysicsShapeType.SHAPE_CONE; | 1503 | ret = BSPhysicsShapeType.SHAPE_CONE; |
1504 | break; | 1504 | break; |
1505 | case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: | 1505 | case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: |
1506 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 1506 | ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; |
1507 | break; | 1507 | break; |
1508 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: | 1508 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: |
1509 | ret = BSPhysicsShapeType.SHAPE_CYLINDER; | 1509 | ret = BSPhysicsShapeType.SHAPE_CYLINDER; |
@@ -1547,7 +1547,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1547 | break; | 1547 | break; |
1548 | ///Used for GIMPACT Trimesh integration | 1548 | ///Used for GIMPACT Trimesh integration |
1549 | case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: | 1549 | case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: |
1550 | ret = BSPhysicsShapeType.SHAPE_MESH; | 1550 | ret = BSPhysicsShapeType.SHAPE_GIMPACT; |
1551 | break; | 1551 | break; |
1552 | ///Multimaterial mesh | 1552 | ///Multimaterial mesh |
1553 | case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: | 1553 | case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: |
@@ -1598,8 +1598,8 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1598 | return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); | 1598 | return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); |
1599 | } | 1599 | } |
1600 | 1600 | ||
1601 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | 1601 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, |
1602 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, | 1602 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, |
1603 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | 1603 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) |
1604 | 1604 | ||
1605 | { | 1605 | { |
@@ -1745,7 +1745,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1745 | { | 1745 | { |
1746 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | 1746 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1747 | CompoundShape compoundshape = new CompoundShape(false); | 1747 | CompoundShape compoundshape = new CompoundShape(false); |
1748 | 1748 | ||
1749 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); | 1749 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); |
1750 | int ii = 1; | 1750 | int ii = 1; |
1751 | 1751 | ||
@@ -1761,7 +1761,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1761 | int ender = ((ii + 4) + (vertexCount*3)); | 1761 | int ender = ((ii + 4) + (vertexCount*3)); |
1762 | for (int iii = ii + 4; iii < ender; iii+=3) | 1762 | for (int iii = ii + 4; iii < ender; iii+=3) |
1763 | { | 1763 | { |
1764 | 1764 | ||
1765 | virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); | 1765 | virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); |
1766 | } | 1766 | } |
1767 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); | 1767 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); |
@@ -1769,26 +1769,35 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1769 | compoundshape.AddChildShape(ref childTrans, convexShape); | 1769 | compoundshape.AddChildShape(ref childTrans, convexShape); |
1770 | ii += (vertexCount*3 + 4); | 1770 | ii += (vertexCount*3 + 4); |
1771 | } | 1771 | } |
1772 | 1772 | ||
1773 | return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); | 1773 | return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); |
1774 | } | 1774 | } |
1775 | 1775 | ||
1776 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | 1776 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) |
1777 | { | ||
1778 | /* TODO */ return null; | ||
1779 | } | ||
1780 | |||
1781 | public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | ||
1777 | { | 1782 | { |
1778 | /* TODO */ return null; | 1783 | /* TODO */ return null; |
1784 | } | ||
1779 | 1785 | ||
1786 | public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
1787 | { | ||
1788 | /* TODO */ return null; | ||
1780 | } | 1789 | } |
1781 | 1790 | ||
1782 | public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | 1791 | public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) |
1783 | { | 1792 | { |
1784 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); | 1793 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); |
1785 | 1794 | ||
1786 | for (int iter = 0; iter < pVerticesCount; iter++) | 1795 | for (int iter = 0; iter < pVerticesCount; iter++) |
1787 | { | 1796 | { |
1788 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; | 1797 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; |
1789 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; | 1798 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; |
1790 | } | 1799 | } |
1791 | 1800 | ||
1792 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); | 1801 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); |
1793 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); | 1802 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); |
1794 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); | 1803 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); |
@@ -1802,7 +1811,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1802 | mesh.m_vertexStride = 3; | 1811 | mesh.m_vertexStride = 3; |
1803 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | 1812 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; |
1804 | mesh.m_triangleIndexStride = 3; | 1813 | mesh.m_triangleIndexStride = 3; |
1805 | 1814 | ||
1806 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | 1815 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); |
1807 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | 1816 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); |
1808 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); | 1817 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); |
@@ -1811,9 +1820,14 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1811 | return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); | 1820 | return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); |
1812 | 1821 | ||
1813 | } | 1822 | } |
1823 | public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
1824 | { | ||
1825 | // TODO: | ||
1826 | return null; | ||
1827 | } | ||
1814 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) | 1828 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) |
1815 | { | 1829 | { |
1816 | 1830 | ||
1817 | String fileName = "objTest3.raw"; | 1831 | String fileName = "objTest3.raw"; |
1818 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | 1832 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); |
1819 | StreamWriter sw = new StreamWriter(completePath); | 1833 | StreamWriter sw = new StreamWriter(completePath); |
@@ -1839,7 +1853,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1839 | string s = vertices[indices[i * 3]].ToString("0.0000"); | 1853 | string s = vertices[indices[i * 3]].ToString("0.0000"); |
1840 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | 1854 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); |
1841 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | 1855 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); |
1842 | 1856 | ||
1843 | sw.Write(s + "\n"); | 1857 | sw.Write(s + "\n"); |
1844 | } | 1858 | } |
1845 | 1859 | ||
@@ -1861,7 +1875,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1861 | mesh.m_vertexStride = 3; | 1875 | mesh.m_vertexStride = 3; |
1862 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | 1876 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; |
1863 | mesh.m_triangleIndexStride = 3; | 1877 | mesh.m_triangleIndexStride = 3; |
1864 | 1878 | ||
1865 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | 1879 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); |
1866 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | 1880 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); |
1867 | 1881 | ||
@@ -1892,7 +1906,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1892 | sw.Close(); | 1906 | sw.Close(); |
1893 | } | 1907 | } |
1894 | 1908 | ||
1895 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | 1909 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, |
1896 | float scaleFactor, float collisionMargin) | 1910 | float scaleFactor, float collisionMargin) |
1897 | { | 1911 | { |
1898 | const int upAxis = 2; | 1912 | const int upAxis = 2; |
@@ -1934,14 +1948,14 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1934 | /* TODO */ | 1948 | /* TODO */ |
1935 | updatedEntityCount = 0; | 1949 | updatedEntityCount = 0; |
1936 | collidersCount = 0; | 1950 | collidersCount = 0; |
1937 | 1951 | ||
1938 | 1952 | ||
1939 | int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); | 1953 | int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); |
1940 | 1954 | ||
1941 | return ret; | 1955 | return ret; |
1942 | } | 1956 | } |
1943 | 1957 | ||
1944 | private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, | 1958 | private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, |
1945 | out int updatedEntityCount, out EntityProperties[] updatedEntities, | 1959 | out int updatedEntityCount, out EntityProperties[] updatedEntities, |
1946 | out int collidersCount, out CollisionDesc[] colliders) | 1960 | out int collidersCount, out CollisionDesc[] colliders) |
1947 | { | 1961 | { |
@@ -1950,24 +1964,24 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1950 | return epic; | 1964 | return epic; |
1951 | } | 1965 | } |
1952 | 1966 | ||
1953 | private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, | 1967 | private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, |
1954 | out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) | 1968 | out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) |
1955 | { | 1969 | { |
1956 | int numSimSteps = 0; | 1970 | int numSimSteps = 0; |
1957 | Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); | 1971 | Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); |
1958 | Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); | 1972 | Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); |
1959 | LastEntityProperty=0; | 1973 | LastEntityProperty=0; |
1960 | 1974 | ||
1961 | 1975 | ||
1962 | 1976 | ||
1963 | 1977 | ||
1964 | 1978 | ||
1965 | 1979 | ||
1966 | LastCollisionDesc=0; | 1980 | LastCollisionDesc=0; |
1967 | 1981 | ||
1968 | updatedEntityCount = 0; | 1982 | updatedEntityCount = 0; |
1969 | collidersCount = 0; | 1983 | collidersCount = 0; |
1970 | 1984 | ||
1971 | 1985 | ||
1972 | if (pWorld is BulletWorldXNA) | 1986 | if (pWorld is BulletWorldXNA) |
1973 | { | 1987 | { |
@@ -2024,7 +2038,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2024 | 2038 | ||
2025 | collidersCount = LastCollisionDesc; | 2039 | collidersCount = LastCollisionDesc; |
2026 | colliders = UpdatedCollisions; | 2040 | colliders = UpdatedCollisions; |
2027 | 2041 | ||
2028 | 2042 | ||
2029 | } | 2043 | } |
2030 | else | 2044 | else |
@@ -2032,15 +2046,15 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2032 | //if (updatedEntities is null) | 2046 | //if (updatedEntities is null) |
2033 | //updatedEntities = new List<BulletXNA.EntityProperties>(); | 2047 | //updatedEntities = new List<BulletXNA.EntityProperties>(); |
2034 | //updatedEntityCount = 0; | 2048 | //updatedEntityCount = 0; |
2035 | 2049 | ||
2036 | 2050 | ||
2037 | //collidersCount = 0; | 2051 | //collidersCount = 0; |
2038 | 2052 | ||
2039 | updatedEntities = new EntityProperties[0]; | 2053 | updatedEntities = new EntityProperties[0]; |
2040 | 2054 | ||
2041 | 2055 | ||
2042 | colliders = new CollisionDesc[0]; | 2056 | colliders = new CollisionDesc[0]; |
2043 | 2057 | ||
2044 | } | 2058 | } |
2045 | return numSimSteps; | 2059 | return numSimSteps; |
2046 | } | 2060 | } |
@@ -2048,7 +2062,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2048 | { | 2062 | { |
2049 | IOverlappingPairCache cache = obj.GetOverlappingPairCache(); | 2063 | IOverlappingPairCache cache = obj.GetOverlappingPairCache(); |
2050 | ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); | 2064 | ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); |
2051 | 2065 | ||
2052 | DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; | 2066 | DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; |
2053 | PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); | 2067 | PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); |
2054 | BroadphasePair collisionPair; | 2068 | BroadphasePair collisionPair; |
@@ -2060,7 +2074,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2060 | ManifoldPoint pt; | 2074 | ManifoldPoint pt; |
2061 | 2075 | ||
2062 | int numPairs = pairs.Count; | 2076 | int numPairs = pairs.Count; |
2063 | 2077 | ||
2064 | for (int i = 0; i < numPairs; i++) | 2078 | for (int i = 0; i < numPairs; i++) |
2065 | { | 2079 | { |
2066 | manifoldArray.Clear(); | 2080 | manifoldArray.Clear(); |
@@ -2069,7 +2083,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2069 | collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); | 2083 | collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); |
2070 | if (collisionPair == null) | 2084 | if (collisionPair == null) |
2071 | continue; | 2085 | continue; |
2072 | 2086 | ||
2073 | collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); | 2087 | collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); |
2074 | for (int j = 0; j < manifoldArray.Count; j++) | 2088 | for (int j = 0; j < manifoldArray.Count; j++) |
2075 | { | 2089 | { |
@@ -2092,7 +2106,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2092 | } | 2106 | } |
2093 | private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) | 2107 | private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) |
2094 | { | 2108 | { |
2095 | 2109 | ||
2096 | IndexedVector3 contactNormal = norm; | 2110 | IndexedVector3 contactNormal = norm; |
2097 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && | 2111 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && |
2098 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) | 2112 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) |
@@ -2162,11 +2176,11 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2162 | if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) | 2176 | if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) |
2163 | { | 2177 | { |
2164 | CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; | 2178 | CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; |
2165 | 2179 | ||
2166 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); | 2180 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); |
2167 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); | 2181 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); |
2168 | using ( | 2182 | using ( |
2169 | ClosestNotMeRayResultCallback rayCallback = | 2183 | ClosestNotMeRayResultCallback rayCallback = |
2170 | new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) | 2184 | new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) |
2171 | ) | 2185 | ) |
2172 | { | 2186 | { |
@@ -2182,9 +2196,9 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2182 | return false; | 2196 | return false; |
2183 | } | 2197 | } |
2184 | } | 2198 | } |
2185 | |||
2186 | 2199 | ||
2187 | 2200 | ||
2201 | |||
2188 | 2202 | ||
2189 | public class SimMotionState : DefaultMotionState | 2203 | public class SimMotionState : DefaultMotionState |
2190 | { | 2204 | { |
@@ -2277,12 +2291,12 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2277 | m_lastProperties = m_properties; | 2291 | m_lastProperties = m_properties; |
2278 | if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) | 2292 | if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) |
2279 | m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); | 2293 | m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); |
2280 | 2294 | ||
2281 | //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; | 2295 | //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; |
2282 | } | 2296 | } |
2283 | 2297 | ||
2284 | 2298 | ||
2285 | 2299 | ||
2286 | 2300 | ||
2287 | } | 2301 | } |
2288 | public override void SetRigidBody(RigidBody body) | 2302 | public override void SetRigidBody(RigidBody body) |
@@ -2305,7 +2319,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2305 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && | 2319 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && |
2306 | (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); | 2320 | (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); |
2307 | } | 2321 | } |
2308 | 2322 | ||
2309 | } | 2323 | } |
2310 | } | 2324 | } |
2311 | 2325 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs new file mode 100755 index 0000000..ac8c30c --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs | |||
@@ -0,0 +1,351 @@ | |||
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 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorAvatarMove : BSActor | ||
40 | { | ||
41 | BSVMotor m_velocityMotor; | ||
42 | |||
43 | // Set to true if we think we're going up stairs. | ||
44 | // This state is remembered because collisions will turn on and off as we go up stairs. | ||
45 | int m_walkingUpStairs; | ||
46 | float m_lastStepUp; | ||
47 | |||
48 | public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
49 | : base(physicsScene, pObj, actorName) | ||
50 | { | ||
51 | m_velocityMotor = null; | ||
52 | m_walkingUpStairs = 0; | ||
53 | m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID); | ||
54 | } | ||
55 | |||
56 | // BSActor.isActive | ||
57 | public override bool isActive | ||
58 | { | ||
59 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
60 | } | ||
61 | |||
62 | // Release any connections and resources used by the actor. | ||
63 | // BSActor.Dispose() | ||
64 | public override void Dispose() | ||
65 | { | ||
66 | Enabled = false; | ||
67 | } | ||
68 | |||
69 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
70 | // Called at taint-time. | ||
71 | // BSActor.Refresh() | ||
72 | public override void Refresh() | ||
73 | { | ||
74 | m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID); | ||
75 | |||
76 | // If the object is physically active, add the hoverer prestep action | ||
77 | if (isActive) | ||
78 | { | ||
79 | ActivateAvatarMove(); | ||
80 | } | ||
81 | else | ||
82 | { | ||
83 | DeactivateAvatarMove(); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
88 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
89 | // Called at taint-time. | ||
90 | // BSActor.RemoveDependencies() | ||
91 | public override void RemoveDependencies() | ||
92 | { | ||
93 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
94 | } | ||
95 | |||
96 | // Usually called when target velocity changes to set the current velocity and the target | ||
97 | // into the movement motor. | ||
98 | public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) | ||
99 | { | ||
100 | m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate() | ||
101 | { | ||
102 | if (m_velocityMotor != null) | ||
103 | { | ||
104 | m_velocityMotor.Reset(); | ||
105 | m_velocityMotor.SetTarget(targ); | ||
106 | m_velocityMotor.SetCurrent(vel); | ||
107 | m_velocityMotor.Enabled = true; | ||
108 | } | ||
109 | }); | ||
110 | } | ||
111 | |||
112 | // If a hover motor has not been created, create one and start the hovering. | ||
113 | private void ActivateAvatarMove() | ||
114 | { | ||
115 | if (m_velocityMotor == null) | ||
116 | { | ||
117 | // Infinite decay and timescale values so motor only changes current to target values. | ||
118 | m_velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
119 | 0.2f, // time scale | ||
120 | BSMotor.Infinite, // decay time scale | ||
121 | 1f // efficiency | ||
122 | ); | ||
123 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
124 | SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); | ||
125 | |||
126 | m_physicsScene.BeforeStep += Mover; | ||
127 | |||
128 | m_walkingUpStairs = 0; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | private void DeactivateAvatarMove() | ||
133 | { | ||
134 | if (m_velocityMotor != null) | ||
135 | { | ||
136 | m_physicsScene.BeforeStep -= Mover; | ||
137 | m_velocityMotor = null; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
142 | private void Mover(float timeStep) | ||
143 | { | ||
144 | // Don't do movement while the object is selected. | ||
145 | if (!isActive) | ||
146 | return; | ||
147 | |||
148 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
149 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
150 | |||
151 | // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity | ||
152 | // specified for the avatar is the one that should be used. For falling, if the avatar | ||
153 | // is not flying and is not colliding then it is presumed to be falling and the Z | ||
154 | // component is not fooled with (thus allowing gravity to do its thing). | ||
155 | // When the avatar is standing, though, the user has specified a velocity of zero and | ||
156 | // the avatar should be standing. But if the avatar is pushed by something in the world | ||
157 | // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to | ||
158 | // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity | ||
159 | // errors can creap in and the avatar will slowly float off in some direction. | ||
160 | // So, the problem is that, when an avatar is standing, we cannot tell creaping error | ||
161 | // from real pushing. | ||
162 | // The code below uses whether the collider is static or moving to decide whether to zero motion. | ||
163 | |||
164 | m_velocityMotor.Step(timeStep); | ||
165 | m_controllingPrim.IsStationary = false; | ||
166 | |||
167 | // If we're not supposed to be moving, make sure things are zero. | ||
168 | if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero) | ||
169 | { | ||
170 | // The avatar shouldn't be moving | ||
171 | m_velocityMotor.Zero(); | ||
172 | |||
173 | if (m_controllingPrim.IsColliding) | ||
174 | { | ||
175 | // If we are colliding with a stationary object, presume we're standing and don't move around | ||
176 | if (!m_controllingPrim.ColliderIsMoving) | ||
177 | { | ||
178 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); | ||
179 | m_controllingPrim.IsStationary = true; | ||
180 | m_controllingPrim.ZeroMotion(true /* inTaintTime */); | ||
181 | } | ||
182 | |||
183 | // Standing has more friction on the ground | ||
184 | if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction) | ||
185 | { | ||
186 | m_controllingPrim.Friction = BSParam.AvatarStandingFriction; | ||
187 | m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); | ||
188 | } | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | if (m_controllingPrim.Flying) | ||
193 | { | ||
194 | // Flying and not collising and velocity nearly zero. | ||
195 | m_controllingPrim.ZeroMotion(true /* inTaintTime */); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", | ||
200 | m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | // Supposed to be moving. | ||
205 | OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue; | ||
206 | |||
207 | if (m_controllingPrim.Friction != BSParam.AvatarFriction) | ||
208 | { | ||
209 | // Probably starting up walking. Set friction to moving friction. | ||
210 | m_controllingPrim.Friction = BSParam.AvatarFriction; | ||
211 | m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); | ||
212 | } | ||
213 | |||
214 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
215 | // The check for RawVelocity.Z < 0 makes jumping work (temporary upward force). | ||
216 | if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) | ||
217 | { | ||
218 | if (m_controllingPrim.RawVelocity.Z < 0) | ||
219 | stepVelocity.Z = m_controllingPrim.RawVelocity.Z; | ||
220 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
221 | } | ||
222 | |||
223 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
224 | OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; | ||
225 | |||
226 | // Add special movement force to allow avatars to walk up stepped surfaces. | ||
227 | moveForce += WalkUpStairs(); | ||
228 | |||
229 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", | ||
230 | m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce); | ||
231 | m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | // Decide if the character is colliding with a low object and compute a force to pop the | ||
236 | // avatar up so it can walk up and over the low objects. | ||
237 | private OMV.Vector3 WalkUpStairs() | ||
238 | { | ||
239 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
240 | |||
241 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}", | ||
242 | m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying, | ||
243 | m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z); | ||
244 | // This test is done if moving forward, not flying and is colliding with something. | ||
245 | // Check for stairs climbing if colliding, not flying and moving forward | ||
246 | if ( m_controllingPrim.IsColliding | ||
247 | && !m_controllingPrim.Flying | ||
248 | && m_controllingPrim.TargetVelocitySpeed > 0.1f ) | ||
249 | { | ||
250 | // The range near the character's feet where we will consider stairs | ||
251 | // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; | ||
252 | // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off | ||
253 | // from the height. Revisit size and this computation when height is scaled properly. | ||
254 | float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - 0.05f; | ||
255 | float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; | ||
256 | |||
257 | // Look for a collision point that is near the character's feet and is oriented the same as the charactor is. | ||
258 | // Find the highest 'good' collision. | ||
259 | OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero; | ||
260 | foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList) | ||
261 | { | ||
262 | // Don't care about collisions with the terrain | ||
263 | if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) | ||
264 | { | ||
265 | OMV.Vector3 touchPosition = kvp.Value.Position; | ||
266 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", | ||
267 | m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); | ||
268 | if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) | ||
269 | { | ||
270 | // This contact is within the 'near the feet' range. | ||
271 | // The normal should be our contact point to the object so it is pointing away | ||
272 | // thus the difference between our facing orientation and the normal should be small. | ||
273 | OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; | ||
274 | OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); | ||
275 | float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); | ||
276 | if (diff < BSParam.AvatarStepApproachFactor) | ||
277 | { | ||
278 | if (highestTouchPosition.Z < touchPosition.Z) | ||
279 | highestTouchPosition = touchPosition; | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | m_walkingUpStairs = 0; | ||
285 | // If there is a good step sensing, move the avatar over the step. | ||
286 | if (highestTouchPosition != OMV.Vector3.Zero) | ||
287 | { | ||
288 | // Remember that we are going up stairs. This is needed because collisions | ||
289 | // will stop when we move up so this smoothes out that effect. | ||
290 | m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps; | ||
291 | |||
292 | m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin; | ||
293 | ret = ComputeStairCorrection(m_lastStepUp); | ||
294 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}", | ||
295 | m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret); | ||
296 | } | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | // If we used to be going up stairs but are not now, smooth the case where collision goes away while | ||
301 | // we are bouncing up the stairs. | ||
302 | if (m_walkingUpStairs > 0) | ||
303 | { | ||
304 | m_walkingUpStairs--; | ||
305 | ret = ComputeStairCorrection(m_lastStepUp); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | private OMV.Vector3 ComputeStairCorrection(float stepUp) | ||
313 | { | ||
314 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
315 | OMV.Vector3 displacement = OMV.Vector3.Zero; | ||
316 | |||
317 | if (stepUp > 0f) | ||
318 | { | ||
319 | // Found the stairs contact point. Push up a little to raise the character. | ||
320 | if (BSParam.AvatarStepForceFactor > 0f) | ||
321 | { | ||
322 | float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; | ||
323 | ret = new OMV.Vector3(0f, 0f, upForce); | ||
324 | } | ||
325 | |||
326 | // Also move the avatar up for the new height | ||
327 | if (BSParam.AvatarStepUpCorrectionFactor > 0f) | ||
328 | { | ||
329 | // Move the avatar up related to the height of the collision | ||
330 | displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor); | ||
331 | m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; | ||
332 | } | ||
333 | else | ||
334 | { | ||
335 | if (BSParam.AvatarStepUpCorrectionFactor < 0f) | ||
336 | { | ||
337 | // Move the avatar up about the specified step height | ||
338 | displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight); | ||
339 | m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; | ||
340 | } | ||
341 | } | ||
342 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,disp={1},force={2}", | ||
343 | m_controllingPrim.LocalID, displacement, ret); | ||
344 | |||
345 | } | ||
346 | return ret; | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | |||
351 | |||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs new file mode 100755 index 0000000..8a79809 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs | |||
@@ -0,0 +1,173 @@ | |||
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 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorHover : BSActor | ||
40 | { | ||
41 | private BSFMotor m_hoverMotor; | ||
42 | |||
43 | public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_hoverMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | } | ||
62 | |||
63 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
64 | // Called at taint-time. | ||
65 | // BSActor.Refresh() | ||
66 | public override void Refresh() | ||
67 | { | ||
68 | m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID); | ||
69 | |||
70 | // If not active any more, turn me off | ||
71 | if (!m_controllingPrim.HoverActive) | ||
72 | { | ||
73 | SetEnabled(false); | ||
74 | } | ||
75 | |||
76 | // If the object is physically active, add the hoverer prestep action | ||
77 | if (isActive) | ||
78 | { | ||
79 | ActivateHover(); | ||
80 | } | ||
81 | else | ||
82 | { | ||
83 | DeactivateHover(); | ||
84 | } | ||
85 | } | ||
86 | |||
87 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
88 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
89 | // Called at taint-time. | ||
90 | // BSActor.RemoveDependencies() | ||
91 | public override void RemoveDependencies() | ||
92 | { | ||
93 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
94 | } | ||
95 | |||
96 | // If a hover motor has not been created, create one and start the hovering. | ||
97 | private void ActivateHover() | ||
98 | { | ||
99 | if (m_hoverMotor == null) | ||
100 | { | ||
101 | // Turning the target on | ||
102 | m_hoverMotor = new BSFMotor("BSActorHover", | ||
103 | m_controllingPrim.HoverTau, // timeScale | ||
104 | BSMotor.Infinite, // decay time scale | ||
105 | 1f // efficiency | ||
106 | ); | ||
107 | m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); | ||
108 | m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); | ||
109 | m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
110 | |||
111 | m_physicsScene.BeforeStep += Hoverer; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | private void DeactivateHover() | ||
116 | { | ||
117 | if (m_hoverMotor != null) | ||
118 | { | ||
119 | m_physicsScene.BeforeStep -= Hoverer; | ||
120 | m_hoverMotor = null; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
125 | private void Hoverer(float timeStep) | ||
126 | { | ||
127 | // Don't do hovering while the object is selected. | ||
128 | if (!isActive) | ||
129 | return; | ||
130 | |||
131 | m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); | ||
132 | m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); | ||
133 | float targetHeight = m_hoverMotor.Step(timeStep); | ||
134 | |||
135 | // 'targetHeight' is where we'd like the Z of the prim to be at this moment. | ||
136 | // Compute the amount of force to push us there. | ||
137 | float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass; | ||
138 | // Undo anything the object thinks it's doing at the moment | ||
139 | moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass; | ||
140 | |||
141 | m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce)); | ||
142 | m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", | ||
143 | m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass); | ||
144 | } | ||
145 | |||
146 | // Based on current position, determine what we should be hovering at now. | ||
147 | // Must recompute often. What if we walked offa cliff> | ||
148 | private float ComputeCurrentHoverHeight() | ||
149 | { | ||
150 | float ret = m_controllingPrim.HoverHeight; | ||
151 | float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition); | ||
152 | |||
153 | switch (m_controllingPrim.HoverType) | ||
154 | { | ||
155 | case PIDHoverType.Ground: | ||
156 | ret = groundHeight + m_controllingPrim.HoverHeight; | ||
157 | break; | ||
158 | case PIDHoverType.GroundAndWater: | ||
159 | float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition); | ||
160 | if (groundHeight > waterHeight) | ||
161 | { | ||
162 | ret = groundHeight + m_controllingPrim.HoverHeight; | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | ret = waterHeight + m_controllingPrim.HoverHeight; | ||
167 | } | ||
168 | break; | ||
169 | } | ||
170 | return ret; | ||
171 | } | ||
172 | } | ||
173 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs new file mode 100755 index 0000000..8b0fdeb --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs | |||
@@ -0,0 +1,187 @@ | |||
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 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OMV = OpenMetaverse; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | public class BSActorLockAxis : BSActor | ||
38 | { | ||
39 | BSConstraint LockAxisConstraint = null; | ||
40 | |||
41 | public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
42 | : base(physicsScene, pObj, actorName) | ||
43 | { | ||
44 | m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); | ||
45 | LockAxisConstraint = null; | ||
46 | } | ||
47 | |||
48 | // BSActor.isActive | ||
49 | public override bool isActive | ||
50 | { | ||
51 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
52 | } | ||
53 | |||
54 | // Release any connections and resources used by the actor. | ||
55 | // BSActor.Dispose() | ||
56 | public override void Dispose() | ||
57 | { | ||
58 | RemoveAxisLockConstraint(); | ||
59 | } | ||
60 | |||
61 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
62 | // Called at taint-time. | ||
63 | // BSActor.Refresh() | ||
64 | public override void Refresh() | ||
65 | { | ||
66 | m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}", | ||
67 | m_controllingPrim.LocalID, m_controllingPrim.LockedAngularAxis, Enabled, m_controllingPrim.IsPhysicallyActive); | ||
68 | // If all the axis are free, we don't need to exist | ||
69 | if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree) | ||
70 | { | ||
71 | Enabled = false; | ||
72 | } | ||
73 | |||
74 | // If the object is physically active, add the axis locking constraint | ||
75 | if (isActive) | ||
76 | { | ||
77 | AddAxisLockConstraint(); | ||
78 | } | ||
79 | else | ||
80 | { | ||
81 | RemoveAxisLockConstraint(); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
86 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
87 | // Called at taint-time. | ||
88 | // BSActor.RemoveDependencies() | ||
89 | public override void RemoveDependencies() | ||
90 | { | ||
91 | if (LockAxisConstraint != null) | ||
92 | { | ||
93 | // If a constraint is set up, remove it from the physical scene | ||
94 | RemoveAxisLockConstraint(); | ||
95 | // Schedule a call before the next simulation step to restore the constraint. | ||
96 | m_physicsScene.PostTaintObject("BSActorLockAxis:" + ActorName, m_controllingPrim.LocalID, delegate() | ||
97 | { | ||
98 | Refresh(); | ||
99 | }); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | private void AddAxisLockConstraint() | ||
104 | { | ||
105 | if (LockAxisConstraint == null) | ||
106 | { | ||
107 | // Lock that axis by creating a 6DOF constraint that has one end in the world and | ||
108 | // the other in the object. | ||
109 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 | ||
110 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 | ||
111 | |||
112 | // Remove any existing axis constraint (just to be sure) | ||
113 | RemoveAxisLockConstraint(); | ||
114 | |||
115 | BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody, | ||
116 | OMV.Vector3.Zero, OMV.Quaternion.Identity, | ||
117 | false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); | ||
118 | LockAxisConstraint = axisConstrainer; | ||
119 | m_physicsScene.Constraints.AddConstraint(LockAxisConstraint); | ||
120 | |||
121 | // The constraint is tied to the world and oriented to the prim. | ||
122 | |||
123 | // Free to move linearly in the region | ||
124 | OMV.Vector3 linearLow = OMV.Vector3.Zero; | ||
125 | OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize; | ||
126 | if (m_controllingPrim.LockedLinearAxis.X != BSPhysObject.FreeAxis) | ||
127 | { | ||
128 | linearLow.X = m_controllingPrim.RawPosition.X; | ||
129 | linearHigh.X = m_controllingPrim.RawPosition.X; | ||
130 | } | ||
131 | if (m_controllingPrim.LockedLinearAxis.Y != BSPhysObject.FreeAxis) | ||
132 | { | ||
133 | linearLow.Y = m_controllingPrim.RawPosition.Y; | ||
134 | linearHigh.Y = m_controllingPrim.RawPosition.Y; | ||
135 | } | ||
136 | if (m_controllingPrim.LockedLinearAxis.Z != BSPhysObject.FreeAxis) | ||
137 | { | ||
138 | linearLow.Z = m_controllingPrim.RawPosition.Z; | ||
139 | linearHigh.Z = m_controllingPrim.RawPosition.Z; | ||
140 | } | ||
141 | axisConstrainer.SetLinearLimits(linearLow, linearHigh); | ||
142 | |||
143 | // Angular with some axis locked | ||
144 | float fPI = (float)Math.PI; | ||
145 | OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI); | ||
146 | OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI); | ||
147 | if (m_controllingPrim.LockedAngularAxis.X != BSPhysObject.FreeAxis) | ||
148 | { | ||
149 | angularLow.X = 0f; | ||
150 | angularHigh.X = 0f; | ||
151 | } | ||
152 | if (m_controllingPrim.LockedAngularAxis.Y != BSPhysObject.FreeAxis) | ||
153 | { | ||
154 | angularLow.Y = 0f; | ||
155 | angularHigh.Y = 0f; | ||
156 | } | ||
157 | if (m_controllingPrim.LockedAngularAxis.Z != BSPhysObject.FreeAxis) | ||
158 | { | ||
159 | angularLow.Z = 0f; | ||
160 | angularHigh.Z = 0f; | ||
161 | } | ||
162 | if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh)) | ||
163 | { | ||
164 | m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID); | ||
165 | } | ||
166 | |||
167 | m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", | ||
168 | m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh); | ||
169 | |||
170 | // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. | ||
171 | axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); | ||
172 | |||
173 | axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | private void RemoveAxisLockConstraint() | ||
178 | { | ||
179 | if (LockAxisConstraint != null) | ||
180 | { | ||
181 | m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint); | ||
182 | LockAxisConstraint = null; | ||
183 | m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID); | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs new file mode 100755 index 0000000..75ff24e --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs | |||
@@ -0,0 +1,157 @@ | |||
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 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorMoveToTarget : BSActor | ||
40 | { | ||
41 | private BSVMotor m_targetMotor; | ||
42 | |||
43 | public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_targetMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | } | ||
62 | |||
63 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
64 | // Called at taint-time. | ||
65 | // BSActor.Refresh() | ||
66 | public override void Refresh() | ||
67 | { | ||
68 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}", | ||
69 | m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive, | ||
70 | m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau ); | ||
71 | |||
72 | // If not active any more... | ||
73 | if (!m_controllingPrim.MoveToTargetActive) | ||
74 | { | ||
75 | Enabled = false; | ||
76 | } | ||
77 | |||
78 | if (isActive) | ||
79 | { | ||
80 | ActivateMoveToTarget(); | ||
81 | } | ||
82 | else | ||
83 | { | ||
84 | DeactivateMoveToTarget(); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
89 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
90 | // Called at taint-time. | ||
91 | // BSActor.RemoveDependencies() | ||
92 | public override void RemoveDependencies() | ||
93 | { | ||
94 | // Nothing to do for the moveToTarget since it is all software at pre-step action time. | ||
95 | } | ||
96 | |||
97 | // If a hover motor has not been created, create one and start the hovering. | ||
98 | private void ActivateMoveToTarget() | ||
99 | { | ||
100 | if (m_targetMotor == null) | ||
101 | { | ||
102 | // We're taking over after this. | ||
103 | m_controllingPrim.ZeroMotion(true); | ||
104 | |||
105 | m_targetMotor = new BSVMotor("BSActorMoveToTargget.Activate", | ||
106 | m_controllingPrim.MoveToTargetTau, // timeScale | ||
107 | BSMotor.Infinite, // decay time scale | ||
108 | 1f // efficiency | ||
109 | ); | ||
110 | m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
111 | m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); | ||
112 | m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); | ||
113 | |||
114 | m_physicsScene.BeforeStep += Mover; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | private void DeactivateMoveToTarget() | ||
119 | { | ||
120 | if (m_targetMotor != null) | ||
121 | { | ||
122 | m_physicsScene.BeforeStep -= Mover; | ||
123 | m_targetMotor = null; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
128 | private void Mover(float timeStep) | ||
129 | { | ||
130 | // Don't do hovering while the object is selected. | ||
131 | if (!isActive) | ||
132 | return; | ||
133 | |||
134 | OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) | ||
135 | |||
136 | // 'movePosition' is where we'd like the prim to be at this moment. | ||
137 | OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep); | ||
138 | |||
139 | // If we are very close to our target, turn off the movement motor. | ||
140 | if (m_targetMotor.ErrorIsZero()) | ||
141 | { | ||
142 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}", | ||
143 | m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); | ||
144 | m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; | ||
145 | // Setting the position does not cause the physics engine to generate a property update. Force it. | ||
146 | m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); | ||
147 | } | ||
148 | else | ||
149 | { | ||
150 | m_controllingPrim.ForcePosition = movePosition; | ||
151 | // Setting the position does not cause the physics engine to generate a property update. Force it. | ||
152 | m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); | ||
153 | } | ||
154 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition); | ||
155 | } | ||
156 | } | ||
157 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs new file mode 100755 index 0000000..96fa0b6 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs | |||
@@ -0,0 +1,137 @@ | |||
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 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorSetForce : BSActor | ||
40 | { | ||
41 | BSFMotor m_forceMotor; | ||
42 | |||
43 | public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_forceMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | } | ||
62 | |||
63 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
64 | // Called at taint-time. | ||
65 | // BSActor.Refresh() | ||
66 | public override void Refresh() | ||
67 | { | ||
68 | m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID); | ||
69 | |||
70 | // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) | ||
71 | if (m_controllingPrim.RawForce == OMV.Vector3.Zero) | ||
72 | { | ||
73 | m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName); | ||
74 | Enabled = false; | ||
75 | return; | ||
76 | } | ||
77 | |||
78 | // If the object is physically active, add the hoverer prestep action | ||
79 | if (isActive) | ||
80 | { | ||
81 | ActivateSetForce(); | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | DeactivateSetForce(); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
90 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
91 | // Called at taint-time. | ||
92 | // BSActor.RemoveDependencies() | ||
93 | public override void RemoveDependencies() | ||
94 | { | ||
95 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
96 | } | ||
97 | |||
98 | // If a hover motor has not been created, create one and start the hovering. | ||
99 | private void ActivateSetForce() | ||
100 | { | ||
101 | if (m_forceMotor == null) | ||
102 | { | ||
103 | // A fake motor that might be used someday | ||
104 | m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f); | ||
105 | |||
106 | m_physicsScene.BeforeStep += Mover; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | private void DeactivateSetForce() | ||
111 | { | ||
112 | if (m_forceMotor != null) | ||
113 | { | ||
114 | m_physicsScene.BeforeStep -= Mover; | ||
115 | m_forceMotor = null; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
120 | private void Mover(float timeStep) | ||
121 | { | ||
122 | // Don't do force while the object is selected. | ||
123 | if (!isActive) | ||
124 | return; | ||
125 | |||
126 | m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce); | ||
127 | if (m_controllingPrim.PhysBody.HasPhysicalBody) | ||
128 | { | ||
129 | m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce); | ||
130 | m_controllingPrim.ActivateIfPhysical(false); | ||
131 | } | ||
132 | |||
133 | // TODO: | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs new file mode 100755 index 0000000..65098e1 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs | |||
@@ -0,0 +1,138 @@ | |||
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 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public class BSActorSetTorque : BSActor | ||
40 | { | ||
41 | BSFMotor m_torqueMotor; | ||
42 | |||
43 | public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
44 | : base(physicsScene, pObj, actorName) | ||
45 | { | ||
46 | m_torqueMotor = null; | ||
47 | m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID); | ||
48 | } | ||
49 | |||
50 | // BSActor.isActive | ||
51 | public override bool isActive | ||
52 | { | ||
53 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
54 | } | ||
55 | |||
56 | // Release any connections and resources used by the actor. | ||
57 | // BSActor.Dispose() | ||
58 | public override void Dispose() | ||
59 | { | ||
60 | Enabled = false; | ||
61 | } | ||
62 | |||
63 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
64 | // Called at taint-time. | ||
65 | // BSActor.Refresh() | ||
66 | public override void Refresh() | ||
67 | { | ||
68 | m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); | ||
69 | |||
70 | // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) | ||
71 | if (m_controllingPrim.RawTorque == OMV.Vector3.Zero) | ||
72 | { | ||
73 | m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName); | ||
74 | Enabled = false; | ||
75 | return; | ||
76 | } | ||
77 | |||
78 | // If the object is physically active, add the hoverer prestep action | ||
79 | if (isActive) | ||
80 | { | ||
81 | ActivateSetTorque(); | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | DeactivateSetTorque(); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
90 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
91 | // Called at taint-time. | ||
92 | // BSActor.RemoveDependencies() | ||
93 | public override void RemoveDependencies() | ||
94 | { | ||
95 | // Nothing to do for the hoverer since it is all software at pre-step action time. | ||
96 | } | ||
97 | |||
98 | // If a hover motor has not been created, create one and start the hovering. | ||
99 | private void ActivateSetTorque() | ||
100 | { | ||
101 | if (m_torqueMotor == null) | ||
102 | { | ||
103 | // A fake motor that might be used someday | ||
104 | m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f); | ||
105 | |||
106 | m_physicsScene.BeforeStep += Mover; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | private void DeactivateSetTorque() | ||
111 | { | ||
112 | if (m_torqueMotor != null) | ||
113 | { | ||
114 | m_physicsScene.BeforeStep -= Mover; | ||
115 | m_torqueMotor = null; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
120 | private void Mover(float timeStep) | ||
121 | { | ||
122 | // Don't do force while the object is selected. | ||
123 | if (!isActive) | ||
124 | return; | ||
125 | |||
126 | m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); | ||
127 | if (m_controllingPrim.PhysBody.HasPhysicalBody) | ||
128 | { | ||
129 | m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true); | ||
130 | m_controllingPrim.ActivateIfPhysical(false); | ||
131 | } | ||
132 | |||
133 | // TODO: | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | |||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs new file mode 100755 index 0000000..fff63e4 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs | |||
@@ -0,0 +1,160 @@ | |||
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 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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
32 | { | ||
33 | public class BSActorCollection | ||
34 | { | ||
35 | private BSScene m_physicsScene { get; set; } | ||
36 | private Dictionary<string, BSActor> m_actors; | ||
37 | |||
38 | public BSActorCollection(BSScene physicsScene) | ||
39 | { | ||
40 | m_physicsScene = physicsScene; | ||
41 | m_actors = new Dictionary<string, BSActor>(); | ||
42 | } | ||
43 | public void Add(string name, BSActor actor) | ||
44 | { | ||
45 | lock (m_actors) | ||
46 | { | ||
47 | if (!m_actors.ContainsKey(name)) | ||
48 | { | ||
49 | m_actors[name] = actor; | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | public bool RemoveAndRelease(string name) | ||
54 | { | ||
55 | bool ret = false; | ||
56 | lock (m_actors) | ||
57 | { | ||
58 | if (m_actors.ContainsKey(name)) | ||
59 | { | ||
60 | BSActor beingRemoved = m_actors[name]; | ||
61 | m_actors.Remove(name); | ||
62 | beingRemoved.Dispose(); | ||
63 | ret = true; | ||
64 | } | ||
65 | } | ||
66 | return ret; | ||
67 | } | ||
68 | public void Clear() | ||
69 | { | ||
70 | lock (m_actors) | ||
71 | { | ||
72 | Release(); | ||
73 | m_actors.Clear(); | ||
74 | } | ||
75 | } | ||
76 | public void Dispose() | ||
77 | { | ||
78 | Clear(); | ||
79 | } | ||
80 | public bool HasActor(string name) | ||
81 | { | ||
82 | return m_actors.ContainsKey(name); | ||
83 | } | ||
84 | public bool TryGetActor(string actorName, out BSActor theActor) | ||
85 | { | ||
86 | return m_actors.TryGetValue(actorName, out theActor); | ||
87 | } | ||
88 | public void ForEachActor(Action<BSActor> act) | ||
89 | { | ||
90 | lock (m_actors) | ||
91 | { | ||
92 | foreach (KeyValuePair<string, BSActor> kvp in m_actors) | ||
93 | act(kvp.Value); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | public void Enable(bool enabl) | ||
98 | { | ||
99 | ForEachActor(a => a.SetEnabled(enabl)); | ||
100 | } | ||
101 | public void Release() | ||
102 | { | ||
103 | ForEachActor(a => a.Dispose()); | ||
104 | } | ||
105 | public void Refresh() | ||
106 | { | ||
107 | ForEachActor(a => a.Refresh()); | ||
108 | } | ||
109 | public void RemoveDependencies() | ||
110 | { | ||
111 | ForEachActor(a => a.RemoveDependencies()); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | // ============================================================================= | ||
116 | /// <summary> | ||
117 | /// Each physical object can have 'actors' who are pushing the object around. | ||
118 | /// This can be used for hover, locking axis, making vehicles, etc. | ||
119 | /// Each physical object can have multiple actors acting on it. | ||
120 | /// | ||
121 | /// An actor usually registers itself with physics scene events (pre-step action) | ||
122 | /// and modifies the parameters on the host physical object. | ||
123 | /// </summary> | ||
124 | public abstract class BSActor | ||
125 | { | ||
126 | protected BSScene m_physicsScene { get; private set; } | ||
127 | protected BSPhysObject m_controllingPrim { get; private set; } | ||
128 | public virtual bool Enabled { get; set; } | ||
129 | public string ActorName { get; private set; } | ||
130 | |||
131 | public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
132 | { | ||
133 | m_physicsScene = physicsScene; | ||
134 | m_controllingPrim = pObj; | ||
135 | ActorName = actorName; | ||
136 | Enabled = true; | ||
137 | } | ||
138 | |||
139 | // Return 'true' if activily updating the prim | ||
140 | public virtual bool isActive | ||
141 | { | ||
142 | get { return Enabled; } | ||
143 | } | ||
144 | |||
145 | // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled. | ||
146 | // Anyone else should assign true/false to 'Enabled'. | ||
147 | public void SetEnabled(bool setEnabled) | ||
148 | { | ||
149 | Enabled = setEnabled; | ||
150 | } | ||
151 | // Release any connections and resources used by the actor. | ||
152 | public abstract void Dispose(); | ||
153 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
154 | public abstract void Refresh(); | ||
155 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
156 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
157 | public abstract void RemoveDependencies(); | ||
158 | |||
159 | } | ||
160 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs index 5765b0d..6cdc112 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs | |||
@@ -70,6 +70,8 @@ public enum BSPhysicsShapeType | |||
70 | SHAPE_COMPOUND = 22, | 70 | SHAPE_COMPOUND = 22, |
71 | SHAPE_HEIGHTMAP = 23, | 71 | SHAPE_HEIGHTMAP = 23, |
72 | SHAPE_AVATAR = 24, | 72 | SHAPE_AVATAR = 24, |
73 | SHAPE_CONVEXHULL= 25, | ||
74 | SHAPE_GIMPACT = 26, | ||
73 | }; | 75 | }; |
74 | 76 | ||
75 | // The native shapes have predefined shape hash keys | 77 | // The native shapes have predefined shape hash keys |
@@ -191,6 +193,21 @@ public struct ConfigurationParameters | |||
191 | public const float numericFalse = 0f; | 193 | public const float numericFalse = 0f; |
192 | } | 194 | } |
193 | 195 | ||
196 | // Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library. | ||
197 | [StructLayout(LayoutKind.Sequential)] | ||
198 | public struct HACDParams | ||
199 | { | ||
200 | // usual default values | ||
201 | public float maxVerticesPerHull; // 100 | ||
202 | public float minClusters; // 2 | ||
203 | public float compacityWeight; // 0.1 | ||
204 | public float volumeWeight; // 0.0 | ||
205 | public float concavity; // 100 | ||
206 | public float addExtraDistPoints; // false | ||
207 | public float addNeighboursDistPoints; // false | ||
208 | public float addFacesPoints; // false | ||
209 | public float shouldAdjustCollisionMargin; // false | ||
210 | } | ||
194 | 211 | ||
195 | // The states a bullet collision object can have | 212 | // The states a bullet collision object can have |
196 | public enum ActivationState : uint | 213 | public enum ActivationState : uint |
@@ -282,7 +299,7 @@ public abstract class BSAPITemplate | |||
282 | { | 299 | { |
283 | // Returns the name of the underlying Bullet engine | 300 | // Returns the name of the underlying Bullet engine |
284 | public abstract string BulletEngineName { get; } | 301 | public abstract string BulletEngineName { get; } |
285 | public abstract string BulletEngineVersion { get; protected set;} | 302 | public abstract string BulletEngineVersion { get; protected set;} |
286 | 303 | ||
287 | // Initialization and simulation | 304 | // Initialization and simulation |
288 | public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, | 305 | public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, |
@@ -305,10 +322,20 @@ public abstract BulletShape CreateMeshShape(BulletWorld world, | |||
305 | int indicesCount, int[] indices, | 322 | int indicesCount, int[] indices, |
306 | int verticesCount, float[] vertices ); | 323 | int verticesCount, float[] vertices ); |
307 | 324 | ||
325 | public abstract BulletShape CreateGImpactShape(BulletWorld world, | ||
326 | int indicesCount, int[] indices, | ||
327 | int verticesCount, float[] vertices ); | ||
328 | |||
308 | public abstract BulletShape CreateHullShape(BulletWorld world, | 329 | public abstract BulletShape CreateHullShape(BulletWorld world, |
309 | int hullCount, float[] hulls); | 330 | int hullCount, float[] hulls); |
310 | 331 | ||
311 | public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape); | 332 | public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms); |
333 | |||
334 | public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape); | ||
335 | |||
336 | public abstract BulletShape CreateConvexHullShape(BulletWorld world, | ||
337 | int indicesCount, int[] indices, | ||
338 | int verticesCount, float[] vertices ); | ||
312 | 339 | ||
313 | public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); | 340 | public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); |
314 | 341 | ||
@@ -351,7 +378,7 @@ public abstract void DestroyObject(BulletWorld sim, BulletBody obj); | |||
351 | // ===================================================================================== | 378 | // ===================================================================================== |
352 | public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); | 379 | public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); |
353 | 380 | ||
354 | public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | 381 | public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, |
355 | float scaleFactor, float collisionMargin); | 382 | float scaleFactor, float collisionMargin); |
356 | 383 | ||
357 | // ===================================================================================== | 384 | // ===================================================================================== |
@@ -366,7 +393,7 @@ public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, | |||
366 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | 393 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); |
367 | 394 | ||
368 | public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, | 395 | public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, |
369 | Vector3 frameInBloc, Quaternion frameInBrot, | 396 | Vector3 frameInBloc, Quaternion frameInBrot, |
370 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); | 397 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); |
371 | 398 | ||
372 | public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | 399 | public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 90c2d9c..48f842e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
@@ -46,9 +46,6 @@ public sealed class BSCharacter : BSPhysObject | |||
46 | private OMV.Vector3 _position; | 46 | private OMV.Vector3 _position; |
47 | private float _mass; | 47 | private float _mass; |
48 | private float _avatarVolume; | 48 | private float _avatarVolume; |
49 | private OMV.Vector3 _force; | ||
50 | private OMV.Vector3 _velocity; | ||
51 | private OMV.Vector3 _torque; | ||
52 | private float _collisionScore; | 49 | private float _collisionScore; |
53 | private OMV.Vector3 _acceleration; | 50 | private OMV.Vector3 _acceleration; |
54 | private OMV.Quaternion _orientation; | 51 | private OMV.Quaternion _orientation; |
@@ -62,15 +59,12 @@ public sealed class BSCharacter : BSPhysObject | |||
62 | private bool _kinematic; | 59 | private bool _kinematic; |
63 | private float _buoyancy; | 60 | private float _buoyancy; |
64 | 61 | ||
65 | private BSVMotor _velocityMotor; | 62 | private BSActorAvatarMove m_moveActor; |
63 | private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; | ||
66 | 64 | ||
67 | private OMV.Vector3 _PIDTarget; | 65 | private OMV.Vector3 _PIDTarget; |
68 | private bool _usePID; | 66 | private bool _usePID; |
69 | private float _PIDTau; | 67 | private float _PIDTau; |
70 | private bool _useHoverPID; | ||
71 | private float _PIDHoverHeight; | ||
72 | private PIDHoverType _PIDHoverType; | ||
73 | private float _PIDHoverTao; | ||
74 | 68 | ||
75 | public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) | 69 | public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) |
76 | : base(parent_scene, localID, avName, "BSCharacter") | 70 | : base(parent_scene, localID, avName, "BSCharacter") |
@@ -80,7 +74,7 @@ public sealed class BSCharacter : BSPhysObject | |||
80 | 74 | ||
81 | _flying = isFlying; | 75 | _flying = isFlying; |
82 | _orientation = OMV.Quaternion.Identity; | 76 | _orientation = OMV.Quaternion.Identity; |
83 | _velocity = OMV.Vector3.Zero; | 77 | RawVelocity = OMV.Vector3.Zero; |
84 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | 78 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); |
85 | Friction = BSParam.AvatarStandingFriction; | 79 | Friction = BSParam.AvatarStandingFriction; |
86 | Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; | 80 | Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; |
@@ -97,17 +91,22 @@ public sealed class BSCharacter : BSPhysObject | |||
97 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 91 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
98 | ComputeAvatarVolumeAndMass(); | 92 | ComputeAvatarVolumeAndMass(); |
99 | 93 | ||
100 | SetupMovementMotor(); | 94 | // The avatar's movement is controlled by this motor that speeds up and slows down |
95 | // the avatar seeking to reach the motor's target speed. | ||
96 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
97 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
98 | m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); | ||
99 | PhysicalActors.Add(AvatarMoveActorName, m_moveActor); | ||
101 | 100 | ||
102 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | 101 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", |
103 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); | 102 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); |
104 | 103 | ||
105 | // do actual creation in taint time | 104 | // do actual creation in taint time |
106 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 105 | PhysScene.TaintedObject("BSCharacter.create", delegate() |
107 | { | 106 | { |
108 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 107 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
109 | // New body and shape into PhysBody and PhysShape | 108 | // New body and shape into PhysBody and PhysShape |
110 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); | 109 | PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this); |
111 | 110 | ||
112 | SetPhysicalProperties(); | 111 | SetPhysicalProperties(); |
113 | }); | 112 | }); |
@@ -120,214 +119,63 @@ public sealed class BSCharacter : BSPhysObject | |||
120 | base.Destroy(); | 119 | base.Destroy(); |
121 | 120 | ||
122 | DetailLog("{0},BSCharacter.Destroy", LocalID); | 121 | DetailLog("{0},BSCharacter.Destroy", LocalID); |
123 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 122 | PhysScene.TaintedObject("BSCharacter.destroy", delegate() |
124 | { | 123 | { |
125 | PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); | 124 | PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); |
126 | PhysBody.Clear(); | 125 | PhysBody.Clear(); |
127 | PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */); | 126 | PhysShape.Dereference(PhysScene); |
128 | PhysShape.Clear(); | 127 | PhysShape = new BSShapeNull(); |
129 | }); | 128 | }); |
130 | } | 129 | } |
131 | 130 | ||
132 | private void SetPhysicalProperties() | 131 | private void SetPhysicalProperties() |
133 | { | 132 | { |
134 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 133 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
135 | 134 | ||
136 | ZeroMotion(true); | 135 | ZeroMotion(true); |
137 | ForcePosition = _position; | 136 | ForcePosition = _position; |
138 | 137 | ||
139 | // Set the velocity | 138 | // Set the velocity |
140 | _velocityMotor.Reset(); | 139 | if (m_moveActor != null) |
141 | _velocityMotor.SetTarget(_velocity); | 140 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false); |
142 | _velocityMotor.SetCurrent(_velocity); | 141 | |
143 | ForceVelocity = _velocity; | 142 | ForceVelocity = RawVelocity; |
144 | 143 | ||
145 | // This will enable or disable the flying buoyancy of the avatar. | 144 | // This will enable or disable the flying buoyancy of the avatar. |
146 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. | 145 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. |
147 | Flying = _flying; | 146 | Flying = _flying; |
148 | 147 | ||
149 | PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); | 148 | PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); |
150 | PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); | 149 | PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin); |
151 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | 150 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); |
152 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 151 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
153 | if (BSParam.CcdMotionThreshold > 0f) | 152 | if (BSParam.CcdMotionThreshold > 0f) |
154 | { | 153 | { |
155 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 154 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
156 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 155 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
157 | } | 156 | } |
158 | 157 | ||
159 | UpdatePhysicalMassProperties(RawMass, false); | 158 | UpdatePhysicalMassProperties(RawMass, false); |
160 | 159 | ||
161 | // Make so capsule does not fall over | 160 | // Make so capsule does not fall over |
162 | PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); | 161 | PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); |
162 | |||
163 | // The avatar mover sets some parameters. | ||
164 | PhysicalActors.Refresh(); | ||
163 | 165 | ||
164 | PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); | 166 | PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); |
165 | 167 | ||
166 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | 168 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); |
167 | 169 | ||
168 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | 170 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
169 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); | 171 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); |
170 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); | 172 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); |
171 | 173 | ||
172 | // Do this after the object has been added to the world | 174 | // Do this after the object has been added to the world |
173 | PhysBody.collisionType = CollisionType.Avatar; | 175 | PhysBody.collisionType = CollisionType.Avatar; |
174 | PhysBody.ApplyCollisionMask(PhysicsScene); | 176 | PhysBody.ApplyCollisionMask(PhysScene); |
175 | } | ||
176 | |||
177 | // The avatar's movement is controlled by this motor that speeds up and slows down | ||
178 | // the avatar seeking to reach the motor's target speed. | ||
179 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
180 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
181 | private void SetupMovementMotor() | ||
182 | { | ||
183 | // Infinite decay and timescale values so motor only changes current to target values. | ||
184 | _velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
185 | 0.2f, // time scale | ||
186 | BSMotor.Infinite, // decay time scale | ||
187 | BSMotor.InfiniteVector, // friction timescale | ||
188 | 1f // efficiency | ||
189 | ); | ||
190 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
191 | |||
192 | RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep) | ||
193 | { | ||
194 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
195 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
196 | |||
197 | // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity | ||
198 | // specified for the avatar is the one that should be used. For falling, if the avatar | ||
199 | // is not flying and is not colliding then it is presumed to be falling and the Z | ||
200 | // component is not fooled with (thus allowing gravity to do its thing). | ||
201 | // When the avatar is standing, though, the user has specified a velocity of zero and | ||
202 | // the avatar should be standing. But if the avatar is pushed by something in the world | ||
203 | // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to | ||
204 | // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity | ||
205 | // errors can creap in and the avatar will slowly float off in some direction. | ||
206 | // So, the problem is that, when an avatar is standing, we cannot tell creaping error | ||
207 | // from real pushing. | ||
208 | // The code below uses whether the collider is static or moving to decide whether to zero motion. | ||
209 | |||
210 | _velocityMotor.Step(timeStep); | ||
211 | |||
212 | // If we're not supposed to be moving, make sure things are zero. | ||
213 | if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero) | ||
214 | { | ||
215 | // The avatar shouldn't be moving | ||
216 | _velocityMotor.Zero(); | ||
217 | |||
218 | if (IsColliding) | ||
219 | { | ||
220 | // If we are colliding with a stationary object, presume we're standing and don't move around | ||
221 | if (!ColliderIsMoving) | ||
222 | { | ||
223 | DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID); | ||
224 | ZeroMotion(true /* inTaintTime */); | ||
225 | } | ||
226 | |||
227 | // Standing has more friction on the ground | ||
228 | if (Friction != BSParam.AvatarStandingFriction) | ||
229 | { | ||
230 | Friction = BSParam.AvatarStandingFriction; | ||
231 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | ||
232 | } | ||
233 | } | ||
234 | else | ||
235 | { | ||
236 | if (Flying) | ||
237 | { | ||
238 | // Flying and not collising and velocity nearly zero. | ||
239 | ZeroMotion(true /* inTaintTime */); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding); | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | // Supposed to be moving. | ||
248 | OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue; | ||
249 | |||
250 | if (Friction != BSParam.AvatarFriction) | ||
251 | { | ||
252 | // Probably starting up walking. Set friction to moving friction. | ||
253 | Friction = BSParam.AvatarFriction; | ||
254 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | ||
255 | } | ||
256 | |||
257 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
258 | // The check for _velocity.Z < 0 makes jumping work (temporary upward force). | ||
259 | if (!Flying && !IsColliding) | ||
260 | { | ||
261 | if (_velocity.Z < 0) | ||
262 | stepVelocity.Z = _velocity.Z; | ||
263 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
264 | } | ||
265 | |||
266 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
267 | OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass; | ||
268 | |||
269 | // Should we check for move force being small and forcing velocity to zero? | ||
270 | |||
271 | // Add special movement force to allow avatars to walk up stepped surfaces. | ||
272 | moveForce += WalkUpStairs(); | ||
273 | |||
274 | DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); | ||
275 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce); | ||
276 | } | ||
277 | }); | ||
278 | } | 177 | } |
279 | 178 | ||
280 | // Decide if the character is colliding with a low object and compute a force to pop the | ||
281 | // avatar up so it can walk up and over the low objects. | ||
282 | private OMV.Vector3 WalkUpStairs() | ||
283 | { | ||
284 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
285 | |||
286 | // This test is done if moving forward, not flying and is colliding with something. | ||
287 | // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}", | ||
288 | // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count); | ||
289 | if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */) | ||
290 | { | ||
291 | // The range near the character's feet where we will consider stairs | ||
292 | float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f; | ||
293 | float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; | ||
294 | |||
295 | // Look for a collision point that is near the character's feet and is oriented the same as the charactor is | ||
296 | foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList) | ||
297 | { | ||
298 | // Don't care about collisions with the terrain | ||
299 | if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID) | ||
300 | { | ||
301 | OMV.Vector3 touchPosition = kvp.Value.Position; | ||
302 | // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", | ||
303 | // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); | ||
304 | if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) | ||
305 | { | ||
306 | // This contact is within the 'near the feet' range. | ||
307 | // The normal should be our contact point to the object so it is pointing away | ||
308 | // thus the difference between our facing orientation and the normal should be small. | ||
309 | OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation; | ||
310 | OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); | ||
311 | float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); | ||
312 | if (diff < BSParam.AvatarStepApproachFactor) | ||
313 | { | ||
314 | // Found the stairs contact point. Push up a little to raise the character. | ||
315 | float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor; | ||
316 | ret = new OMV.Vector3(0f, 0f, upForce); | ||
317 | |||
318 | // Also move the avatar up for the new height | ||
319 | OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f); | ||
320 | ForcePosition = RawPosition + displacement; | ||
321 | } | ||
322 | DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}", | ||
323 | LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret); | ||
324 | } | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | return ret; | ||
330 | } | ||
331 | 179 | ||
332 | public override void RequestPhysicsterseUpdate() | 180 | public override void RequestPhysicsterseUpdate() |
333 | { | 181 | { |
@@ -355,14 +203,14 @@ public sealed class BSCharacter : BSPhysObject | |||
355 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", | 203 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", |
356 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); | 204 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); |
357 | 205 | ||
358 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 206 | PhysScene.TaintedObject("BSCharacter.setSize", delegate() |
359 | { | 207 | { |
360 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) | 208 | if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) |
361 | { | 209 | { |
362 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | 210 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); |
363 | UpdatePhysicalMassProperties(RawMass, true); | 211 | UpdatePhysicalMassProperties(RawMass, true); |
364 | // Make sure this change appears as a property update event | 212 | // Make sure this change appears as a property update event |
365 | PhysicsScene.PE.PushUpdate(PhysBody); | 213 | PhysScene.PE.PushUpdate(PhysBody); |
366 | } | 214 | } |
367 | }); | 215 | }); |
368 | 216 | ||
@@ -373,11 +221,6 @@ public sealed class BSCharacter : BSPhysObject | |||
373 | { | 221 | { |
374 | set { BaseShape = value; } | 222 | set { BaseShape = value; } |
375 | } | 223 | } |
376 | // I want the physics engine to make an avatar capsule | ||
377 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
378 | { | ||
379 | get {return BSPhysicsShapeType.SHAPE_CAPSULE; } | ||
380 | } | ||
381 | 224 | ||
382 | public override bool Grabbed { | 225 | public override bool Grabbed { |
383 | set { _grabbed = value; } | 226 | set { _grabbed = value; } |
@@ -399,29 +242,29 @@ public sealed class BSCharacter : BSPhysObject | |||
399 | // Called at taint time! | 242 | // Called at taint time! |
400 | public override void ZeroMotion(bool inTaintTime) | 243 | public override void ZeroMotion(bool inTaintTime) |
401 | { | 244 | { |
402 | _velocity = OMV.Vector3.Zero; | 245 | RawVelocity = OMV.Vector3.Zero; |
403 | _acceleration = OMV.Vector3.Zero; | 246 | _acceleration = OMV.Vector3.Zero; |
404 | _rotationalVelocity = OMV.Vector3.Zero; | 247 | _rotationalVelocity = OMV.Vector3.Zero; |
405 | 248 | ||
406 | // Zero some other properties directly into the physics engine | 249 | // Zero some other properties directly into the physics engine |
407 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 250 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
408 | { | 251 | { |
409 | if (PhysBody.HasPhysicalBody) | 252 | if (PhysBody.HasPhysicalBody) |
410 | PhysicsScene.PE.ClearAllForces(PhysBody); | 253 | PhysScene.PE.ClearAllForces(PhysBody); |
411 | }); | 254 | }); |
412 | } | 255 | } |
413 | public override void ZeroAngularMotion(bool inTaintTime) | 256 | public override void ZeroAngularMotion(bool inTaintTime) |
414 | { | 257 | { |
415 | _rotationalVelocity = OMV.Vector3.Zero; | 258 | _rotationalVelocity = OMV.Vector3.Zero; |
416 | 259 | ||
417 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 260 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
418 | { | 261 | { |
419 | if (PhysBody.HasPhysicalBody) | 262 | if (PhysBody.HasPhysicalBody) |
420 | { | 263 | { |
421 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); | 264 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); |
422 | PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); | 265 | PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); |
423 | // The next also get rid of applied linear force but the linear velocity is untouched. | 266 | // The next also get rid of applied linear force but the linear velocity is untouched. |
424 | PhysicsScene.PE.ClearForces(PhysBody); | 267 | PhysScene.PE.ClearForces(PhysBody); |
425 | } | 268 | } |
426 | }); | 269 | }); |
427 | } | 270 | } |
@@ -443,7 +286,7 @@ public sealed class BSCharacter : BSPhysObject | |||
443 | set { | 286 | set { |
444 | _position = value; | 287 | _position = value; |
445 | 288 | ||
446 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 289 | PhysScene.TaintedObject("BSCharacter.setPosition", delegate() |
447 | { | 290 | { |
448 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 291 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
449 | PositionSanityCheck(); | 292 | PositionSanityCheck(); |
@@ -453,14 +296,14 @@ public sealed class BSCharacter : BSPhysObject | |||
453 | } | 296 | } |
454 | public override OMV.Vector3 ForcePosition { | 297 | public override OMV.Vector3 ForcePosition { |
455 | get { | 298 | get { |
456 | _position = PhysicsScene.PE.GetPosition(PhysBody); | 299 | _position = PhysScene.PE.GetPosition(PhysBody); |
457 | return _position; | 300 | return _position; |
458 | } | 301 | } |
459 | set { | 302 | set { |
460 | _position = value; | 303 | _position = value; |
461 | if (PhysBody.HasPhysicalBody) | 304 | if (PhysBody.HasPhysicalBody) |
462 | { | 305 | { |
463 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 306 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); |
464 | } | 307 | } |
465 | } | 308 | } |
466 | } | 309 | } |
@@ -474,18 +317,18 @@ public sealed class BSCharacter : BSPhysObject | |||
474 | bool ret = false; | 317 | bool ret = false; |
475 | 318 | ||
476 | // TODO: check for out of bounds | 319 | // TODO: check for out of bounds |
477 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) | 320 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) |
478 | { | 321 | { |
479 | // The character is out of the known/simulated area. | 322 | // The character is out of the known/simulated area. |
480 | // Force the avatar position to be within known. ScenePresence will use the position | 323 | // Force the avatar position to be within known. ScenePresence will use the position |
481 | // plus the velocity to decide if the avatar is moving out of the region. | 324 | // plus the velocity to decide if the avatar is moving out of the region. |
482 | RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); | 325 | RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); |
483 | DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); | 326 | DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); |
484 | return true; | 327 | return true; |
485 | } | 328 | } |
486 | 329 | ||
487 | // If below the ground, move the avatar up | 330 | // If below the ground, move the avatar up |
488 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | 331 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); |
489 | if (Position.Z < terrainHeight) | 332 | if (Position.Z < terrainHeight) |
490 | { | 333 | { |
491 | DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 334 | DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); |
@@ -494,7 +337,7 @@ public sealed class BSCharacter : BSPhysObject | |||
494 | } | 337 | } |
495 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 338 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
496 | { | 339 | { |
497 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | 340 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
498 | if (Position.Z < waterHeight) | 341 | if (Position.Z < waterHeight) |
499 | { | 342 | { |
500 | _position.Z = waterHeight; | 343 | _position.Z = waterHeight; |
@@ -515,7 +358,7 @@ public sealed class BSCharacter : BSPhysObject | |||
515 | { | 358 | { |
516 | // The new position value must be pushed into the physics engine but we can't | 359 | // The new position value must be pushed into the physics engine but we can't |
517 | // just assign to "Position" because of potential call loops. | 360 | // just assign to "Position" because of potential call loops. |
518 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | 361 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() |
519 | { | 362 | { |
520 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 363 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
521 | ForcePosition = _position; | 364 | ForcePosition = _position; |
@@ -528,25 +371,25 @@ public sealed class BSCharacter : BSPhysObject | |||
528 | public override float Mass { get { return _mass; } } | 371 | public override float Mass { get { return _mass; } } |
529 | 372 | ||
530 | // used when we only want this prim's mass and not the linkset thing | 373 | // used when we only want this prim's mass and not the linkset thing |
531 | public override float RawMass { | 374 | public override float RawMass { |
532 | get {return _mass; } | 375 | get {return _mass; } |
533 | } | 376 | } |
534 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | 377 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) |
535 | { | 378 | { |
536 | OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | 379 | OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); |
537 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); | 380 | PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia); |
538 | } | 381 | } |
539 | 382 | ||
540 | public override OMV.Vector3 Force { | 383 | public override OMV.Vector3 Force { |
541 | get { return _force; } | 384 | get { return RawForce; } |
542 | set { | 385 | set { |
543 | _force = value; | 386 | RawForce = value; |
544 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | 387 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); |
545 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 388 | PhysScene.TaintedObject("BSCharacter.SetForce", delegate() |
546 | { | 389 | { |
547 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 390 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); |
548 | if (PhysBody.HasPhysicalBody) | 391 | if (PhysBody.HasPhysicalBody) |
549 | PhysicsScene.PE.SetObjectForce(PhysBody, _force); | 392 | PhysScene.PE.SetObjectForce(PhysBody, RawForce); |
550 | }); | 393 | }); |
551 | } | 394 | } |
552 | } | 395 | } |
@@ -569,61 +412,49 @@ public sealed class BSCharacter : BSPhysObject | |||
569 | { | 412 | { |
570 | get | 413 | get |
571 | { | 414 | { |
572 | return m_targetVelocity; | 415 | return base.m_targetVelocity; |
573 | } | 416 | } |
574 | set | 417 | set |
575 | { | 418 | { |
576 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); | 419 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); |
577 | m_targetVelocity = value; | 420 | m_targetVelocity = value; |
578 | OMV.Vector3 targetVel = value; | 421 | OMV.Vector3 targetVel = value; |
579 | if (_setAlwaysRun) | 422 | if (_setAlwaysRun && !_flying) |
580 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); | 423 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); |
581 | 424 | ||
582 | PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | 425 | if (m_moveActor != null) |
583 | { | 426 | m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */); |
584 | _velocityMotor.Reset(); | ||
585 | _velocityMotor.SetTarget(targetVel); | ||
586 | _velocityMotor.SetCurrent(_velocity); | ||
587 | _velocityMotor.Enabled = true; | ||
588 | }); | ||
589 | } | 427 | } |
590 | } | 428 | } |
591 | public override OMV.Vector3 RawVelocity | ||
592 | { | ||
593 | get { return _velocity; } | ||
594 | set { _velocity = value; } | ||
595 | } | ||
596 | // Directly setting velocity means this is what the user really wants now. | 429 | // Directly setting velocity means this is what the user really wants now. |
597 | public override OMV.Vector3 Velocity { | 430 | public override OMV.Vector3 Velocity { |
598 | get { return _velocity; } | 431 | get { return RawVelocity; } |
599 | set { | 432 | set { |
600 | _velocity = value; | 433 | RawVelocity = value; |
601 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | 434 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity); |
602 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | 435 | PhysScene.TaintedObject("BSCharacter.setVelocity", delegate() |
603 | { | 436 | { |
604 | _velocityMotor.Reset(); | 437 | if (m_moveActor != null) |
605 | _velocityMotor.SetCurrent(_velocity); | 438 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */); |
606 | _velocityMotor.SetTarget(_velocity); | ||
607 | _velocityMotor.Enabled = false; | ||
608 | 439 | ||
609 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | 440 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity); |
610 | ForceVelocity = _velocity; | 441 | ForceVelocity = RawVelocity; |
611 | }); | 442 | }); |
612 | } | 443 | } |
613 | } | 444 | } |
614 | public override OMV.Vector3 ForceVelocity { | 445 | public override OMV.Vector3 ForceVelocity { |
615 | get { return _velocity; } | 446 | get { return RawVelocity; } |
616 | set { | 447 | set { |
617 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | 448 | PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); |
618 | 449 | ||
619 | _velocity = value; | 450 | RawVelocity = value; |
620 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | 451 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); |
621 | PhysicsScene.PE.Activate(PhysBody, true); | 452 | PhysScene.PE.Activate(PhysBody, true); |
622 | } | 453 | } |
623 | } | 454 | } |
624 | public override OMV.Vector3 Torque { | 455 | public override OMV.Vector3 Torque { |
625 | get { return _torque; } | 456 | get { return RawTorque; } |
626 | set { _torque = value; | 457 | set { RawTorque = value; |
627 | } | 458 | } |
628 | } | 459 | } |
629 | public override float CollisionScore { | 460 | public override float CollisionScore { |
@@ -648,9 +479,19 @@ public sealed class BSCharacter : BSPhysObject | |||
648 | if (_orientation != value) | 479 | if (_orientation != value) |
649 | { | 480 | { |
650 | _orientation = value; | 481 | _orientation = value; |
651 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 482 | PhysScene.TaintedObject("BSCharacter.setOrientation", delegate() |
652 | { | 483 | { |
653 | ForceOrientation = _orientation; | 484 | // Bullet assumes we know what we are doing when forcing orientation |
485 | // so it lets us go against all the rules and just compensates for them later. | ||
486 | // This forces rotation to be only around the Z axis and doesn't change any of the other axis. | ||
487 | // This keeps us from flipping the capsule over which the veiwer does not understand. | ||
488 | float oRoll, oPitch, oYaw; | ||
489 | _orientation.GetEulerAngles(out oRoll, out oPitch, out oYaw); | ||
490 | OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw); | ||
491 | // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}", | ||
492 | // LocalID, _orientation, OMV.Vector3.UnitX * _orientation, | ||
493 | // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation); | ||
494 | ForceOrientation = trimmedOrientation; | ||
654 | }); | 495 | }); |
655 | } | 496 | } |
656 | } | 497 | } |
@@ -660,7 +501,7 @@ public sealed class BSCharacter : BSPhysObject | |||
660 | { | 501 | { |
661 | get | 502 | get |
662 | { | 503 | { |
663 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); | 504 | _orientation = PhysScene.PE.GetOrientation(PhysBody); |
664 | return _orientation; | 505 | return _orientation; |
665 | } | 506 | } |
666 | set | 507 | set |
@@ -669,7 +510,7 @@ public sealed class BSCharacter : BSPhysObject | |||
669 | if (PhysBody.HasPhysicalBody) | 510 | if (PhysBody.HasPhysicalBody) |
670 | { | 511 | { |
671 | // _position = PhysicsScene.PE.GetPosition(BSBody); | 512 | // _position = PhysicsScene.PE.GetPosition(BSBody); |
672 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 513 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); |
673 | } | 514 | } |
674 | } | 515 | } |
675 | } | 516 | } |
@@ -718,14 +559,14 @@ public sealed class BSCharacter : BSPhysObject | |||
718 | public override bool FloatOnWater { | 559 | public override bool FloatOnWater { |
719 | set { | 560 | set { |
720 | _floatOnWater = value; | 561 | _floatOnWater = value; |
721 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | 562 | PhysScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() |
722 | { | 563 | { |
723 | if (PhysBody.HasPhysicalBody) | 564 | if (PhysBody.HasPhysicalBody) |
724 | { | 565 | { |
725 | if (_floatOnWater) | 566 | if (_floatOnWater) |
726 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 567 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
727 | else | 568 | else |
728 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 569 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
729 | } | 570 | } |
730 | }); | 571 | }); |
731 | } | 572 | } |
@@ -746,7 +587,7 @@ public sealed class BSCharacter : BSPhysObject | |||
746 | public override float Buoyancy { | 587 | public override float Buoyancy { |
747 | get { return _buoyancy; } | 588 | get { return _buoyancy; } |
748 | set { _buoyancy = value; | 589 | set { _buoyancy = value; |
749 | PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() | 590 | PhysScene.TaintedObject("BSCharacter.setBuoyancy", delegate() |
750 | { | 591 | { |
751 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 592 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
752 | ForceBuoyancy = _buoyancy; | 593 | ForceBuoyancy = _buoyancy; |
@@ -755,8 +596,8 @@ public sealed class BSCharacter : BSPhysObject | |||
755 | } | 596 | } |
756 | public override float ForceBuoyancy { | 597 | public override float ForceBuoyancy { |
757 | get { return _buoyancy; } | 598 | get { return _buoyancy; } |
758 | set { | 599 | set { |
759 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); | 600 | PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); |
760 | 601 | ||
761 | _buoyancy = value; | 602 | _buoyancy = value; |
762 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 603 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
@@ -764,7 +605,7 @@ public sealed class BSCharacter : BSPhysObject | |||
764 | float grav = BSParam.Gravity * (1f - _buoyancy); | 605 | float grav = BSParam.Gravity * (1f - _buoyancy); |
765 | Gravity = new OMV.Vector3(0f, 0f, grav); | 606 | Gravity = new OMV.Vector3(0f, 0f, grav); |
766 | if (PhysBody.HasPhysicalBody) | 607 | if (PhysBody.HasPhysicalBody) |
767 | PhysicsScene.PE.SetGravity(PhysBody, Gravity); | 608 | PhysScene.PE.SetGravity(PhysBody, Gravity); |
768 | } | 609 | } |
769 | } | 610 | } |
770 | 611 | ||
@@ -779,31 +620,10 @@ public sealed class BSCharacter : BSPhysObject | |||
779 | set { _PIDTau = value; } | 620 | set { _PIDTau = value; } |
780 | } | 621 | } |
781 | 622 | ||
782 | // Used for llSetHoverHeight and maybe vehicle height | ||
783 | // Hover Height will override MoveTo target's Z | ||
784 | public override bool PIDHoverActive { | ||
785 | set { _useHoverPID = value; } | ||
786 | } | ||
787 | public override float PIDHoverHeight { | ||
788 | set { _PIDHoverHeight = value; } | ||
789 | } | ||
790 | public override PIDHoverType PIDHoverType { | ||
791 | set { _PIDHoverType = value; } | ||
792 | } | ||
793 | public override float PIDHoverTau { | ||
794 | set { _PIDHoverTao = value; } | ||
795 | } | ||
796 | |||
797 | // For RotLookAt | ||
798 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
799 | public override bool APIDActive { set { return; } } | ||
800 | public override float APIDStrength { set { return; } } | ||
801 | public override float APIDDamping { set { return; } } | ||
802 | |||
803 | public override void AddForce(OMV.Vector3 force, bool pushforce) | 623 | public override void AddForce(OMV.Vector3 force, bool pushforce) |
804 | { | 624 | { |
805 | // Since this force is being applied in only one step, make this a force per second. | 625 | // Since this force is being applied in only one step, make this a force per second. |
806 | OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; | 626 | OMV.Vector3 addForce = force / PhysScene.LastTimeStep; |
807 | AddForce(addForce, pushforce, false); | 627 | AddForce(addForce, pushforce, false); |
808 | } | 628 | } |
809 | private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | 629 | private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
@@ -812,13 +632,13 @@ public sealed class BSCharacter : BSPhysObject | |||
812 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); | 632 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); |
813 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); | 633 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); |
814 | 634 | ||
815 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() | 635 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() |
816 | { | 636 | { |
817 | // Bullet adds this central force to the total force for this tick | 637 | // Bullet adds this central force to the total force for this tick |
818 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); | 638 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); |
819 | if (PhysBody.HasPhysicalBody) | 639 | if (PhysBody.HasPhysicalBody) |
820 | { | 640 | { |
821 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | 641 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); |
822 | } | 642 | } |
823 | }); | 643 | }); |
824 | } | 644 | } |
@@ -829,7 +649,7 @@ public sealed class BSCharacter : BSPhysObject | |||
829 | } | 649 | } |
830 | } | 650 | } |
831 | 651 | ||
832 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 652 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
833 | } | 653 | } |
834 | public override void SetMomentum(OMV.Vector3 momentum) { | 654 | public override void SetMomentum(OMV.Vector3 momentum) { |
835 | } | 655 | } |
@@ -837,14 +657,14 @@ public sealed class BSCharacter : BSPhysObject | |||
837 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) | 657 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) |
838 | { | 658 | { |
839 | OMV.Vector3 newScale; | 659 | OMV.Vector3 newScale; |
840 | 660 | ||
841 | // Bullet's capsule total height is the "passed height + radius * 2"; | 661 | // Bullet's capsule total height is the "passed height + radius * 2"; |
842 | // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) | 662 | // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1) |
843 | // The number we pass in for 'scaling' is the multiplier to get that base | 663 | // The number we pass in for 'scaling' is the multiplier to get that base |
844 | // shape to be the size desired. | 664 | // shape to be the size desired. |
845 | // So, when creating the scale for the avatar height, we take the passed height | 665 | // So, when creating the scale for the avatar height, we take the passed height |
846 | // (size.Z) and remove the caps. | 666 | // (size.Z) and remove the caps. |
847 | // Another oddity of the Bullet capsule implementation is that it presumes the Y | 667 | // An oddity of the Bullet capsule implementation is that it presumes the Y |
848 | // dimension is the radius of the capsule. Even though some of the code allows | 668 | // dimension is the radius of the capsule. Even though some of the code allows |
849 | // for a asymmetrical capsule, other parts of the code presume it is cylindrical. | 669 | // for a asymmetrical capsule, other parts of the code presume it is cylindrical. |
850 | 670 | ||
@@ -852,8 +672,27 @@ public sealed class BSCharacter : BSPhysObject | |||
852 | newScale.X = size.X / 2f; | 672 | newScale.X = size.X / 2f; |
853 | newScale.Y = size.Y / 2f; | 673 | newScale.Y = size.Y / 2f; |
854 | 674 | ||
675 | float heightAdjust = BSParam.AvatarHeightMidFudge; | ||
676 | if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) | ||
677 | { | ||
678 | // An avatar is between 1.61 and 2.12 meters. Midpoint is 1.87m. | ||
679 | // The "times 4" relies on the fact that the difference from the midpoint to the extremes is exactly 0.25 | ||
680 | float midHeightOffset = size.Z - 1.87f; | ||
681 | if (midHeightOffset < 0f) | ||
682 | { | ||
683 | // Small avatar. Add the adjustment based on the distance from midheight | ||
684 | heightAdjust += -1f * midHeightOffset * 4f * BSParam.AvatarHeightLowFudge; | ||
685 | } | ||
686 | else | ||
687 | { | ||
688 | // Large avatar. Add the adjustment based on the distance from midheight | ||
689 | heightAdjust += midHeightOffset * 4f * BSParam.AvatarHeightHighFudge; | ||
690 | } | ||
691 | } | ||
855 | // The total scale height is the central cylindar plus the caps on the two ends. | 692 | // The total scale height is the central cylindar plus the caps on the two ends. |
856 | newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; | 693 | newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; |
694 | // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); | ||
695 | |||
857 | // If smaller than the endcaps, just fake like we're almost that small | 696 | // If smaller than the endcaps, just fake like we're almost that small |
858 | if (newScale.Z < 0) | 697 | if (newScale.Z < 0) |
859 | newScale.Z = 0.1f; | 698 | newScale.Z = 0.1f; |
@@ -882,15 +721,18 @@ public sealed class BSCharacter : BSPhysObject | |||
882 | // the world that things have changed. | 721 | // the world that things have changed. |
883 | public override void UpdateProperties(EntityProperties entprop) | 722 | public override void UpdateProperties(EntityProperties entprop) |
884 | { | 723 | { |
885 | _position = entprop.Position; | 724 | // Don't change position if standing on a stationary object. |
725 | if (!IsStationary) | ||
726 | _position = entprop.Position; | ||
727 | |||
886 | _orientation = entprop.Rotation; | 728 | _orientation = entprop.Rotation; |
887 | 729 | ||
888 | // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar | 730 | // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar |
889 | // and will send agent updates to the clients if velocity changes by more than | 731 | // and will send agent updates to the clients if velocity changes by more than |
890 | // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many | 732 | // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many |
891 | // extra updates. | 733 | // extra updates. |
892 | if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f)) | 734 | if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) |
893 | _velocity = entprop.Velocity; | 735 | RawVelocity = entprop.Velocity; |
894 | 736 | ||
895 | _acceleration = entprop.Acceleration; | 737 | _acceleration = entprop.Acceleration; |
896 | _rotationalVelocity = entprop.RotationalVelocity; | 738 | _rotationalVelocity = entprop.RotationalVelocity; |
@@ -913,7 +755,7 @@ public sealed class BSCharacter : BSPhysObject | |||
913 | // base.RequestPhysicsterseUpdate(); | 755 | // base.RequestPhysicsterseUpdate(); |
914 | 756 | ||
915 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 757 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
916 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | 758 | LocalID, _position, _orientation, RawVelocity, _acceleration, _rotationalVelocity); |
917 | } | 759 | } |
918 | } | 760 | } |
919 | } | 761 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index b813974..42b5c49 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs | |||
@@ -85,7 +85,9 @@ public abstract class BSConstraint : IDisposable | |||
85 | { | 85 | { |
86 | bool ret = false; | 86 | bool ret = false; |
87 | if (m_enabled) | 87 | if (m_enabled) |
88 | { | ||
88 | ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); | 89 | ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); |
90 | } | ||
89 | return ret; | 91 | return ret; |
90 | } | 92 | } |
91 | 93 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs index 476a0e5..d0949f5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs | |||
@@ -97,14 +97,14 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
97 | 97 | ||
98 | // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object | 98 | // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object |
99 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot, | 99 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot, |
100 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 100 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) |
101 | : base(world) | 101 | : base(world) |
102 | { | 102 | { |
103 | m_body1 = obj1; | 103 | m_body1 = obj1; |
104 | m_body2 = obj1; // Look out for confusion down the road | 104 | m_body2 = obj1; // Look out for confusion down the road |
105 | m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1, | 105 | m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1, |
106 | frameInBloc, frameInBrot, | 106 | frameInBloc, frameInBrot, |
107 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); | 107 | useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); |
108 | m_enabled = true; | 108 | m_enabled = true; |
109 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", | 109 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", |
110 | BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString); | 110 | BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs index 7714a03..ed89f63 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs | |||
@@ -45,7 +45,7 @@ public sealed class BSConstraintHinge : BSConstraint | |||
45 | m_body1 = obj1; | 45 | m_body1 = obj1; |
46 | m_body2 = obj2; | 46 | m_body2 = obj2; |
47 | m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, | 47 | m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, |
48 | pivotInA, pivotInB, axisInA, axisInB, | 48 | pivotInA, pivotInB, axisInA, axisInB, |
49 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); | 49 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); |
50 | m_enabled = true; | 50 | m_enabled = true; |
51 | } | 51 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 65df741..311cf4f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -40,13 +40,14 @@ using OpenSim.Region.Physics.Manager; | |||
40 | 40 | ||
41 | namespace OpenSim.Region.Physics.BulletSPlugin | 41 | namespace OpenSim.Region.Physics.BulletSPlugin |
42 | { | 42 | { |
43 | public sealed class BSDynamics | 43 | public sealed class BSDynamics : BSActor |
44 | { | 44 | { |
45 | private static string LogHeader = "[BULLETSIM VEHICLE]"; | 45 | private static string LogHeader = "[BULLETSIM VEHICLE]"; |
46 | 46 | ||
47 | private BSScene PhysicsScene { get; set; } | ||
48 | // the prim this dynamic controller belongs to | 47 | // the prim this dynamic controller belongs to |
49 | private BSPrim Prim { get; set; } | 48 | private BSPrim ControllingPrim { get; set; } |
49 | |||
50 | private bool m_haveRegisteredForSceneEvents; | ||
50 | 51 | ||
51 | // mass of the vehicle fetched each time we're calles | 52 | // mass of the vehicle fetched each time we're calles |
52 | private float m_vehicleMass; | 53 | private float m_vehicleMass; |
@@ -129,11 +130,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
129 | public bool enableAngularDeflection; | 130 | public bool enableAngularDeflection; |
130 | public bool enableAngularBanking; | 131 | public bool enableAngularBanking; |
131 | 132 | ||
132 | public BSDynamics(BSScene myScene, BSPrim myPrim) | 133 | public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) |
134 | : base(myScene, myPrim, actorName) | ||
133 | { | 135 | { |
134 | PhysicsScene = myScene; | 136 | ControllingPrim = myPrim; |
135 | Prim = myPrim; | ||
136 | Type = Vehicle.TYPE_NONE; | 137 | Type = Vehicle.TYPE_NONE; |
138 | m_haveRegisteredForSceneEvents = false; | ||
137 | SetupVehicleDebugging(); | 139 | SetupVehicleDebugging(); |
138 | } | 140 | } |
139 | 141 | ||
@@ -144,7 +146,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
144 | enableAngularVerticalAttraction = true; | 146 | enableAngularVerticalAttraction = true; |
145 | enableAngularDeflection = false; | 147 | enableAngularDeflection = false; |
146 | enableAngularBanking = true; | 148 | enableAngularBanking = true; |
147 | if (BSParam.VehicleDebuggingEnabled) | 149 | if (BSParam.VehicleDebuggingEnable) |
148 | { | 150 | { |
149 | enableAngularVerticalAttraction = true; | 151 | enableAngularVerticalAttraction = true; |
150 | enableAngularDeflection = false; | 152 | enableAngularDeflection = false; |
@@ -155,7 +157,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
155 | // Return 'true' if this vehicle is doing vehicle things | 157 | // Return 'true' if this vehicle is doing vehicle things |
156 | public bool IsActive | 158 | public bool IsActive |
157 | { | 159 | { |
158 | get { return (Type != Vehicle.TYPE_NONE && Prim.IsPhysicallyActive); } | 160 | get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); } |
159 | } | 161 | } |
160 | 162 | ||
161 | // Return 'true' if this a vehicle that should be sitting on the ground | 163 | // Return 'true' if this a vehicle that should be sitting on the ground |
@@ -167,7 +169,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
167 | #region Vehicle parameter setting | 169 | #region Vehicle parameter setting |
168 | public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | 170 | public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) |
169 | { | 171 | { |
170 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 172 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
171 | switch (pParam) | 173 | switch (pParam) |
172 | { | 174 | { |
173 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | 175 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: |
@@ -195,7 +197,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
195 | break; | 197 | break; |
196 | case Vehicle.BUOYANCY: | 198 | case Vehicle.BUOYANCY: |
197 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); | 199 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); |
198 | m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy); | 200 | m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); |
199 | break; | 201 | break; |
200 | case Vehicle.HOVER_EFFICIENCY: | 202 | case Vehicle.HOVER_EFFICIENCY: |
201 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); | 203 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); |
@@ -233,7 +235,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
233 | // set all of the components to the same value | 235 | // set all of the components to the same value |
234 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 236 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
235 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | 237 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); |
236 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
237 | break; | 238 | break; |
238 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 239 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
239 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | 240 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); |
@@ -242,7 +243,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
242 | break; | 243 | break; |
243 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 244 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
244 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | 245 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); |
245 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
246 | break; | 246 | break; |
247 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 247 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
248 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | 248 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); |
@@ -258,12 +258,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
258 | 258 | ||
259 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) | 259 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) |
260 | { | 260 | { |
261 | VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 261 | VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
262 | switch (pParam) | 262 | switch (pParam) |
263 | { | 263 | { |
264 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 264 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
265 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 265 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
266 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
267 | break; | 266 | break; |
268 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 267 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
269 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | 268 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
@@ -276,7 +275,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
276 | break; | 275 | break; |
277 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 276 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
278 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 277 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
279 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
280 | break; | 278 | break; |
281 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 279 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
282 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 280 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -294,7 +292,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
294 | 292 | ||
295 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | 293 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) |
296 | { | 294 | { |
297 | VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 295 | VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
298 | switch (pParam) | 296 | switch (pParam) |
299 | { | 297 | { |
300 | case Vehicle.REFERENCE_FRAME: | 298 | case Vehicle.REFERENCE_FRAME: |
@@ -308,7 +306,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
308 | 306 | ||
309 | internal void ProcessVehicleFlags(int pParam, bool remove) | 307 | internal void ProcessVehicleFlags(int pParam, bool remove) |
310 | { | 308 | { |
311 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); | 309 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove); |
312 | VehicleFlag parm = (VehicleFlag)pParam; | 310 | VehicleFlag parm = (VehicleFlag)pParam; |
313 | if (pParam == -1) | 311 | if (pParam == -1) |
314 | m_flags = (VehicleFlag)0; | 312 | m_flags = (VehicleFlag)0; |
@@ -323,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
323 | 321 | ||
324 | public void ProcessTypeChange(Vehicle pType) | 322 | public void ProcessTypeChange(Vehicle pType) |
325 | { | 323 | { |
326 | VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); | 324 | VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType); |
327 | // Set Defaults For Type | 325 | // Set Defaults For Type |
328 | Type = pType; | 326 | Type = pType; |
329 | switch (pType) | 327 | switch (pType) |
@@ -557,34 +555,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
557 | break; | 555 | break; |
558 | } | 556 | } |
559 | 557 | ||
560 | // Update any physical parameters based on this type. | 558 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f); |
561 | Refresh(); | 559 | m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
562 | |||
563 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, | ||
564 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, | ||
565 | 1f); | ||
566 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
567 | 560 | ||
568 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, | 561 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f); |
569 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, | 562 | m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
570 | 1f); | ||
571 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
572 | 563 | ||
573 | /* Not implemented | 564 | /* Not implemented |
574 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, | 565 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, |
575 | BSMotor.Infinite, BSMotor.InfiniteVector, | 566 | BSMotor.Infinite, BSMotor.InfiniteVector, |
576 | m_verticalAttractionEfficiency); | 567 | m_verticalAttractionEfficiency); |
577 | // Z goes away and we keep X and Y | 568 | // Z goes away and we keep X and Y |
578 | m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); | ||
579 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | 569 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
580 | */ | 570 | */ |
571 | |||
572 | if (this.Type == Vehicle.TYPE_NONE) | ||
573 | { | ||
574 | UnregisterForSceneEvents(); | ||
575 | } | ||
576 | else | ||
577 | { | ||
578 | RegisterForSceneEvents(); | ||
579 | } | ||
580 | |||
581 | // Update any physical parameters based on this type. | ||
582 | Refresh(); | ||
581 | } | 583 | } |
582 | #endregion // Vehicle parameter setting | 584 | #endregion // Vehicle parameter setting |
583 | 585 | ||
584 | public void Refresh() | 586 | // BSActor.Refresh() |
587 | public override void Refresh() | ||
585 | { | 588 | { |
586 | // If asking for a refresh, reset the physical parameters before the next simulation step. | 589 | // If asking for a refresh, reset the physical parameters before the next simulation step. |
587 | PhysicsScene.PostTaintObject("BSDynamics.Refresh", Prim.LocalID, delegate() | 590 | // Called whether active or not since the active state may be updated before the next step. |
591 | m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate() | ||
588 | { | 592 | { |
589 | SetPhysicalParameters(); | 593 | SetPhysicalParameters(); |
590 | }); | 594 | }); |
@@ -597,49 +601,91 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
597 | if (IsActive) | 601 | if (IsActive) |
598 | { | 602 | { |
599 | // Remember the mass so we don't have to fetch it every step | 603 | // Remember the mass so we don't have to fetch it every step |
600 | m_vehicleMass = Prim.TotalMass; | 604 | m_vehicleMass = ControllingPrim.TotalMass; |
601 | 605 | ||
602 | // Friction affects are handled by this vehicle code | 606 | // Friction affects are handled by this vehicle code |
603 | PhysicsScene.PE.SetFriction(Prim.PhysBody, BSParam.VehicleFriction); | 607 | m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); |
604 | PhysicsScene.PE.SetRestitution(Prim.PhysBody, BSParam.VehicleRestitution); | 608 | m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); |
605 | 609 | ||
606 | // Moderate angular movement introduced by Bullet. | 610 | // Moderate angular movement introduced by Bullet. |
607 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | 611 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. |
608 | // Maybe compute linear and angular factor and damping from params. | 612 | // Maybe compute linear and angular factor and damping from params. |
609 | PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, BSParam.VehicleAngularDamping); | 613 | m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping); |
610 | PhysicsScene.PE.SetLinearFactor(Prim.PhysBody, BSParam.VehicleLinearFactor); | 614 | m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor); |
611 | PhysicsScene.PE.SetAngularFactorV(Prim.PhysBody, BSParam.VehicleAngularFactor); | 615 | m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor); |
612 | 616 | ||
613 | // Vehicles report collision events so we know when it's on the ground | 617 | // Vehicles report collision events so we know when it's on the ground |
614 | PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | 618 | m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); |
615 | 619 | ||
616 | Prim.Inertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass); | 620 | Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); |
617 | PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, Prim.Inertia); | 621 | ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; |
618 | PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody); | 622 | m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); |
623 | m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); | ||
619 | 624 | ||
620 | // Set the gravity for the vehicle depending on the buoyancy | 625 | // Set the gravity for the vehicle depending on the buoyancy |
621 | // TODO: what should be done if prim and vehicle buoyancy differ? | 626 | // TODO: what should be done if prim and vehicle buoyancy differ? |
622 | m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy); | 627 | m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); |
623 | // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. | 628 | // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. |
624 | PhysicsScene.PE.SetGravity(Prim.PhysBody, Vector3.Zero); | 629 | m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); |
625 | 630 | ||
626 | VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", | 631 | VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", |
627 | Prim.LocalID, m_vehicleMass, Prim.Inertia, m_VehicleGravity, | 632 | ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, |
628 | BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution, | 633 | BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution, |
629 | BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor | 634 | BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor |
630 | ); | 635 | ); |
631 | } | 636 | } |
632 | else | 637 | else |
633 | { | 638 | { |
634 | if (Prim.PhysBody.HasPhysicalBody) | 639 | if (ControllingPrim.PhysBody.HasPhysicalBody) |
635 | PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | 640 | m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); |
636 | } | 641 | } |
637 | } | 642 | } |
638 | 643 | ||
639 | public bool RemoveBodyDependencies(BSPhysObject prim) | 644 | // BSActor.RemoveBodyDependencies |
645 | public override void RemoveDependencies() | ||
640 | { | 646 | { |
641 | Refresh(); | 647 | Refresh(); |
642 | return IsActive; | 648 | } |
649 | |||
650 | // BSActor.Release() | ||
651 | public override void Dispose() | ||
652 | { | ||
653 | UnregisterForSceneEvents(); | ||
654 | Type = Vehicle.TYPE_NONE; | ||
655 | Enabled = false; | ||
656 | return; | ||
657 | } | ||
658 | |||
659 | private void RegisterForSceneEvents() | ||
660 | { | ||
661 | if (!m_haveRegisteredForSceneEvents) | ||
662 | { | ||
663 | m_physicsScene.BeforeStep += this.Step; | ||
664 | m_physicsScene.AfterStep += this.PostStep; | ||
665 | ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty; | ||
666 | m_haveRegisteredForSceneEvents = true; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | private void UnregisterForSceneEvents() | ||
671 | { | ||
672 | if (m_haveRegisteredForSceneEvents) | ||
673 | { | ||
674 | m_physicsScene.BeforeStep -= this.Step; | ||
675 | m_physicsScene.AfterStep -= this.PostStep; | ||
676 | ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty; | ||
677 | m_haveRegisteredForSceneEvents = false; | ||
678 | } | ||
679 | } | ||
680 | |||
681 | private void PreUpdateProperty(ref EntityProperties entprop) | ||
682 | { | ||
683 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet | ||
684 | // TODO: handle physics introduced by Bullet with computed vehicle physics. | ||
685 | if (IsActive) | ||
686 | { | ||
687 | entprop.RotationalVelocity = Vector3.Zero; | ||
688 | } | ||
643 | } | 689 | } |
644 | 690 | ||
645 | #region Known vehicle value functions | 691 | #region Known vehicle value functions |
@@ -686,14 +732,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
686 | if (m_knownChanged != 0) | 732 | if (m_knownChanged != 0) |
687 | { | 733 | { |
688 | if ((m_knownChanged & m_knownChangedPosition) != 0) | 734 | if ((m_knownChanged & m_knownChangedPosition) != 0) |
689 | Prim.ForcePosition = m_knownPosition; | 735 | ControllingPrim.ForcePosition = m_knownPosition; |
690 | 736 | ||
691 | if ((m_knownChanged & m_knownChangedOrientation) != 0) | 737 | if ((m_knownChanged & m_knownChangedOrientation) != 0) |
692 | Prim.ForceOrientation = m_knownOrientation; | 738 | ControllingPrim.ForceOrientation = m_knownOrientation; |
693 | 739 | ||
694 | if ((m_knownChanged & m_knownChangedVelocity) != 0) | 740 | if ((m_knownChanged & m_knownChangedVelocity) != 0) |
695 | { | 741 | { |
696 | Prim.ForceVelocity = m_knownVelocity; | 742 | ControllingPrim.ForceVelocity = m_knownVelocity; |
697 | // Fake out Bullet by making it think the velocity is the same as last time. | 743 | // Fake out Bullet by making it think the velocity is the same as last time. |
698 | // Bullet does a bunch of smoothing for changing parameters. | 744 | // Bullet does a bunch of smoothing for changing parameters. |
699 | // Since the vehicle is demanding this setting, we override Bullet's smoothing | 745 | // Since the vehicle is demanding this setting, we override Bullet's smoothing |
@@ -702,28 +748,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
702 | } | 748 | } |
703 | 749 | ||
704 | if ((m_knownChanged & m_knownChangedForce) != 0) | 750 | if ((m_knownChanged & m_knownChangedForce) != 0) |
705 | Prim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/); | 751 | ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/); |
706 | 752 | ||
707 | if ((m_knownChanged & m_knownChangedForceImpulse) != 0) | 753 | if ((m_knownChanged & m_knownChangedForceImpulse) != 0) |
708 | Prim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/); | 754 | ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/); |
709 | 755 | ||
710 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | 756 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) |
711 | { | 757 | { |
712 | Prim.ForceRotationalVelocity = m_knownRotationalVelocity; | 758 | ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity; |
713 | // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); | 759 | // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); |
714 | } | 760 | } |
715 | 761 | ||
716 | if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) | 762 | if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) |
717 | Prim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); | 763 | ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); |
718 | 764 | ||
719 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) | 765 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) |
720 | { | 766 | { |
721 | Prim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); | 767 | ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); |
722 | } | 768 | } |
723 | 769 | ||
724 | // If we set one of the values (ie, the physics engine didn't do it) we must force | 770 | // If we set one of the values (ie, the physics engine didn't do it) we must force |
725 | // an UpdateProperties event to send the changes up to the simulator. | 771 | // an UpdateProperties event to send the changes up to the simulator. |
726 | PhysicsScene.PE.PushUpdate(Prim.PhysBody); | 772 | m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody); |
727 | } | 773 | } |
728 | m_knownChanged = 0; | 774 | m_knownChanged = 0; |
729 | } | 775 | } |
@@ -736,7 +782,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
736 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) | 782 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) |
737 | { | 783 | { |
738 | lastRememberedHeightPos = pos; | 784 | lastRememberedHeightPos = pos; |
739 | m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | 785 | m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos); |
740 | m_knownHas |= m_knownChangedTerrainHeight; | 786 | m_knownHas |= m_knownChangedTerrainHeight; |
741 | } | 787 | } |
742 | return m_knownTerrainHeight; | 788 | return m_knownTerrainHeight; |
@@ -748,7 +794,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
748 | { | 794 | { |
749 | if ((m_knownHas & m_knownChangedWaterLevel) == 0) | 795 | if ((m_knownHas & m_knownChangedWaterLevel) == 0) |
750 | { | 796 | { |
751 | m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); | 797 | m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos); |
752 | m_knownHas |= m_knownChangedWaterLevel; | 798 | m_knownHas |= m_knownChangedWaterLevel; |
753 | } | 799 | } |
754 | return (float)m_knownWaterLevel; | 800 | return (float)m_knownWaterLevel; |
@@ -760,7 +806,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
760 | { | 806 | { |
761 | if ((m_knownHas & m_knownChangedPosition) == 0) | 807 | if ((m_knownHas & m_knownChangedPosition) == 0) |
762 | { | 808 | { |
763 | m_knownPosition = Prim.ForcePosition; | 809 | m_knownPosition = ControllingPrim.ForcePosition; |
764 | m_knownHas |= m_knownChangedPosition; | 810 | m_knownHas |= m_knownChangedPosition; |
765 | } | 811 | } |
766 | return m_knownPosition; | 812 | return m_knownPosition; |
@@ -779,7 +825,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
779 | { | 825 | { |
780 | if ((m_knownHas & m_knownChangedOrientation) == 0) | 826 | if ((m_knownHas & m_knownChangedOrientation) == 0) |
781 | { | 827 | { |
782 | m_knownOrientation = Prim.ForceOrientation; | 828 | m_knownOrientation = ControllingPrim.ForceOrientation; |
783 | m_knownHas |= m_knownChangedOrientation; | 829 | m_knownHas |= m_knownChangedOrientation; |
784 | } | 830 | } |
785 | return m_knownOrientation; | 831 | return m_knownOrientation; |
@@ -798,7 +844,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
798 | { | 844 | { |
799 | if ((m_knownHas & m_knownChangedVelocity) == 0) | 845 | if ((m_knownHas & m_knownChangedVelocity) == 0) |
800 | { | 846 | { |
801 | m_knownVelocity = Prim.ForceVelocity; | 847 | m_knownVelocity = ControllingPrim.ForceVelocity; |
802 | m_knownHas |= m_knownChangedVelocity; | 848 | m_knownHas |= m_knownChangedVelocity; |
803 | } | 849 | } |
804 | return m_knownVelocity; | 850 | return m_knownVelocity; |
@@ -839,7 +885,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
839 | { | 885 | { |
840 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) | 886 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) |
841 | { | 887 | { |
842 | m_knownRotationalVelocity = Prim.ForceRotationalVelocity; | 888 | m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity; |
843 | m_knownHas |= m_knownChangedRotationalVelocity; | 889 | m_knownHas |= m_knownChangedRotationalVelocity; |
844 | } | 890 | } |
845 | return (Vector3)m_knownRotationalVelocity; | 891 | return (Vector3)m_knownRotationalVelocity; |
@@ -914,11 +960,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
914 | // for the physics engine to note the changes so an UpdateProperties event will happen. | 960 | // for the physics engine to note the changes so an UpdateProperties event will happen. |
915 | PushKnownChanged(); | 961 | PushKnownChanged(); |
916 | 962 | ||
917 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) | 963 | if (m_physicsScene.VehiclePhysicalLoggingEnabled) |
918 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); | 964 | m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); |
919 | 965 | ||
920 | VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}", | 966 | VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}", |
921 | Prim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity); | 967 | ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity); |
922 | } | 968 | } |
923 | 969 | ||
924 | // Called after the simulation step | 970 | // Called after the simulation step |
@@ -926,8 +972,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
926 | { | 972 | { |
927 | if (!IsActive) return; | 973 | if (!IsActive) return; |
928 | 974 | ||
929 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) | 975 | if (m_physicsScene.VehiclePhysicalLoggingEnabled) |
930 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); | 976 | m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); |
931 | } | 977 | } |
932 | 978 | ||
933 | // Apply the effect of the linear motor and other linear motions (like hover and float). | 979 | // Apply the effect of the linear motor and other linear motions (like hover and float). |
@@ -966,13 +1012,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
966 | Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG | 1012 | Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG |
967 | VehicleVelocity /= VehicleVelocity.Length(); | 1013 | VehicleVelocity /= VehicleVelocity.Length(); |
968 | VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; | 1014 | VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; |
969 | VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", | 1015 | VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", |
970 | Prim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); | 1016 | ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); |
971 | } | 1017 | } |
972 | else if (newVelocityLengthSq < 0.001f) | 1018 | else if (newVelocityLengthSq < 0.001f) |
973 | VehicleVelocity = Vector3.Zero; | 1019 | VehicleVelocity = Vector3.Zero; |
974 | 1020 | ||
975 | VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", Prim.LocalID, Prim.IsColliding, VehicleVelocity ); | 1021 | VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.IsColliding, VehicleVelocity ); |
976 | 1022 | ||
977 | } // end MoveLinear() | 1023 | } // end MoveLinear() |
978 | 1024 | ||
@@ -983,6 +1029,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
983 | Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); | 1029 | Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); |
984 | Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); | 1030 | Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); |
985 | 1031 | ||
1032 | // Friction reduces vehicle motion | ||
1033 | Vector3 frictionFactorW = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); | ||
1034 | linearMotorCorrectionV -= (currentVelV * frictionFactorW); | ||
1035 | |||
986 | // Motor is vehicle coordinates. Rotate it to world coordinates | 1036 | // Motor is vehicle coordinates. Rotate it to world coordinates |
987 | Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; | 1037 | Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; |
988 | 1038 | ||
@@ -996,8 +1046,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
996 | // Add this correction to the velocity to make it faster/slower. | 1046 | // Add this correction to the velocity to make it faster/slower. |
997 | VehicleVelocity += linearMotorVelocityW; | 1047 | VehicleVelocity += linearMotorVelocityW; |
998 | 1048 | ||
999 | VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5}", | 1049 | |
1000 | Prim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, linearMotorVelocityW, VehicleVelocity); | 1050 | |
1051 | VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", | ||
1052 | ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, | ||
1053 | linearMotorVelocityW, VehicleVelocity, frictionFactorW); | ||
1001 | } | 1054 | } |
1002 | 1055 | ||
1003 | public void ComputeLinearTerrainHeightCorrection(float pTimestep) | 1056 | public void ComputeLinearTerrainHeightCorrection(float pTimestep) |
@@ -1011,7 +1064,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1011 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; | 1064 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; |
1012 | VehiclePosition = newPosition; | 1065 | VehiclePosition = newPosition; |
1013 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", | 1066 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", |
1014 | Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); | 1067 | ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); |
1015 | } | 1068 | } |
1016 | } | 1069 | } |
1017 | 1070 | ||
@@ -1041,7 +1094,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1041 | if (VehiclePosition.Z > m_VhoverTargetHeight) | 1094 | if (VehiclePosition.Z > m_VhoverTargetHeight) |
1042 | m_VhoverTargetHeight = VehiclePosition.Z; | 1095 | m_VhoverTargetHeight = VehiclePosition.Z; |
1043 | } | 1096 | } |
1044 | 1097 | ||
1045 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 1098 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
1046 | { | 1099 | { |
1047 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) | 1100 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) |
@@ -1050,7 +1103,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1050 | pos.Z = m_VhoverTargetHeight; | 1103 | pos.Z = m_VhoverTargetHeight; |
1051 | VehiclePosition = pos; | 1104 | VehiclePosition = pos; |
1052 | 1105 | ||
1053 | VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", Prim.LocalID, pos); | 1106 | VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos); |
1054 | } | 1107 | } |
1055 | } | 1108 | } |
1056 | else | 1109 | else |
@@ -1079,7 +1132,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1079 | */ | 1132 | */ |
1080 | 1133 | ||
1081 | VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", | 1134 | VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", |
1082 | Prim.LocalID, VehiclePosition, m_VhoverEfficiency, | 1135 | ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency, |
1083 | m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, | 1136 | m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, |
1084 | verticalError, verticalCorrection); | 1137 | verticalError, verticalCorrection); |
1085 | } | 1138 | } |
@@ -1124,7 +1177,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1124 | { | 1177 | { |
1125 | VehiclePosition = pos; | 1178 | VehiclePosition = pos; |
1126 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | 1179 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", |
1127 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | 1180 | ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos); |
1128 | } | 1181 | } |
1129 | } | 1182 | } |
1130 | return changed; | 1183 | return changed; |
@@ -1135,7 +1188,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1135 | // used with conjunction with banking: the strength of the banking will decay when the | 1188 | // used with conjunction with banking: the strength of the banking will decay when the |
1136 | // vehicle no longer experiences collisions. The decay timescale is the same as | 1189 | // vehicle no longer experiences collisions. The decay timescale is the same as |
1137 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | 1190 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering |
1138 | // when they are in mid jump. | 1191 | // when they are in mid jump. |
1139 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? | 1192 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? |
1140 | // This is just using the ground and a general collision check. Should really be using | 1193 | // This is just using the ground and a general collision check. Should really be using |
1141 | // a downward raycast to find what is below. | 1194 | // a downward raycast to find what is below. |
@@ -1164,7 +1217,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1164 | 1217 | ||
1165 | // Another approach is to measure if we're going up. If going up and not colliding, | 1218 | // Another approach is to measure if we're going up. If going up and not colliding, |
1166 | // the vehicle is in the air. Fix that by pushing down. | 1219 | // the vehicle is in the air. Fix that by pushing down. |
1167 | if (!Prim.IsColliding && VehicleVelocity.Z > 0.1) | 1220 | if (!ControllingPrim.IsColliding && VehicleVelocity.Z > 0.1) |
1168 | { | 1221 | { |
1169 | // Get rid of any of the velocity vector that is pushing us up. | 1222 | // Get rid of any of the velocity vector that is pushing us up. |
1170 | float upVelocity = VehicleVelocity.Z; | 1223 | float upVelocity = VehicleVelocity.Z; |
@@ -1186,7 +1239,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1186 | } | 1239 | } |
1187 | */ | 1240 | */ |
1188 | VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", | 1241 | VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", |
1189 | Prim.LocalID, Prim.IsColliding, upVelocity, VehicleVelocity); | 1242 | ControllingPrim.LocalID, ControllingPrim.IsColliding, upVelocity, VehicleVelocity); |
1190 | } | 1243 | } |
1191 | } | 1244 | } |
1192 | } | 1245 | } |
@@ -1196,14 +1249,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1196 | Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; | 1249 | Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; |
1197 | 1250 | ||
1198 | // Hack to reduce downward force if the vehicle is probably sitting on the ground | 1251 | // Hack to reduce downward force if the vehicle is probably sitting on the ground |
1199 | if (Prim.IsColliding && IsGroundVehicle) | 1252 | if (ControllingPrim.IsColliding && IsGroundVehicle) |
1200 | appliedGravity *= BSParam.VehicleGroundGravityFudge; | 1253 | appliedGravity *= BSParam.VehicleGroundGravityFudge; |
1201 | 1254 | ||
1202 | VehicleAddForce(appliedGravity); | 1255 | VehicleAddForce(appliedGravity); |
1203 | 1256 | ||
1204 | VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", | 1257 | VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", |
1205 | Prim.LocalID, m_VehicleGravity, | 1258 | ControllingPrim.LocalID, m_VehicleGravity, |
1206 | Prim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); | 1259 | ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); |
1207 | } | 1260 | } |
1208 | 1261 | ||
1209 | // ======================================================================= | 1262 | // ======================================================================= |
@@ -1227,11 +1280,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1227 | { | 1280 | { |
1228 | // The vehicle is not adding anything angular wise. | 1281 | // The vehicle is not adding anything angular wise. |
1229 | VehicleRotationalVelocity = Vector3.Zero; | 1282 | VehicleRotationalVelocity = Vector3.Zero; |
1230 | VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); | 1283 | VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID); |
1231 | } | 1284 | } |
1232 | else | 1285 | else |
1233 | { | 1286 | { |
1234 | VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", Prim.LocalID, VehicleRotationalVelocity); | 1287 | VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity); |
1235 | } | 1288 | } |
1236 | 1289 | ||
1237 | // ================================================================== | 1290 | // ================================================================== |
@@ -1262,7 +1315,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1262 | torqueFromOffset.Z = 0; | 1315 | torqueFromOffset.Z = 0; |
1263 | 1316 | ||
1264 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); | 1317 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); |
1265 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | 1318 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset); |
1266 | } | 1319 | } |
1267 | 1320 | ||
1268 | } | 1321 | } |
@@ -1277,7 +1330,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1277 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : | 1330 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
1278 | // This flag prevents linear deflection parallel to world z-axis. This is useful | 1331 | // This flag prevents linear deflection parallel to world z-axis. This is useful |
1279 | // for preventing ground vehicles with large linear deflection, like bumper cars, | 1332 | // for preventing ground vehicles with large linear deflection, like bumper cars, |
1280 | // from climbing their linear deflection into the sky. | 1333 | // from climbing their linear deflection into the sky. |
1281 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement | 1334 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement |
1282 | // TODO: This is here because this is where ODE put it but documentation says it | 1335 | // TODO: This is here because this is where ODE put it but documentation says it |
1283 | // is a linear effect. Where should this check go? | 1336 | // is a linear effect. Where should this check go? |
@@ -1287,8 +1340,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1287 | // angularMotorContributionV.Y = 0f; | 1340 | // angularMotorContributionV.Y = 0f; |
1288 | // } | 1341 | // } |
1289 | 1342 | ||
1343 | // Reduce any velocity by friction. | ||
1344 | Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep); | ||
1345 | angularMotorContributionV -= (currentAngularV * frictionFactorW); | ||
1346 | |||
1290 | VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; | 1347 | VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; |
1291 | VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV); | 1348 | |
1349 | |||
1350 | |||
1351 | VDetailLog("{0}, MoveAngular,angularTurning,angContribV={1}", ControllingPrim.LocalID, angularMotorContributionV); | ||
1292 | } | 1352 | } |
1293 | 1353 | ||
1294 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | 1354 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: |
@@ -1305,6 +1365,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1305 | // If vertical attaction timescale is reasonable | 1365 | // If vertical attaction timescale is reasonable |
1306 | if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | 1366 | if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) |
1307 | { | 1367 | { |
1368 | //Another formula to try got from : | ||
1369 | //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html | ||
1370 | |||
1371 | Vector3 VehicleUpAxis = Vector3.UnitZ * VehicleOrientation; | ||
1372 | |||
1373 | // Flipping what was originally a timescale into a speed variable and then multiplying it by 2 | ||
1374 | // since only computing half the distance between the angles. | ||
1375 | float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; | ||
1376 | |||
1377 | // Make a prediction of where the up axis will be when this is applied rather then where it is now as | ||
1378 | // this makes for a smoother adjustment and less fighting between the various forces. | ||
1379 | Vector3 predictedUp = VehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); | ||
1380 | |||
1381 | // This is only half the distance to the target so it will take 2 seconds to complete the turn. | ||
1382 | Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); | ||
1383 | |||
1384 | // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared | ||
1385 | Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed; | ||
1386 | |||
1387 | VehicleRotationalVelocity += vertContributionV; | ||
1388 | |||
1389 | VDetailLog("{0}, MoveAngular,verticalAttraction,UpAxis={1},PredictedUp={2},torqueVector={3},contrib={4}", | ||
1390 | ControllingPrim.LocalID, | ||
1391 | VehicleUpAxis, | ||
1392 | predictedUp, | ||
1393 | torqueVector, | ||
1394 | vertContributionV); | ||
1395 | //===================================================================== | ||
1396 | /* | ||
1308 | // Possible solution derived from a discussion at: | 1397 | // Possible solution derived from a discussion at: |
1309 | // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no | 1398 | // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no |
1310 | 1399 | ||
@@ -1334,11 +1423,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1334 | VehicleRotationalVelocity += vertContributionV; | 1423 | VehicleRotationalVelocity += vertContributionV; |
1335 | 1424 | ||
1336 | VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}", | 1425 | VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}", |
1337 | Prim.LocalID, | 1426 | ControllingPrim.LocalID, |
1338 | differenceAxis, | 1427 | differenceAxis, |
1339 | differenceAngle, | 1428 | differenceAngle, |
1340 | correctionRotation, | 1429 | correctionRotation, |
1341 | vertContributionV); | 1430 | vertContributionV); |
1431 | */ | ||
1342 | 1432 | ||
1343 | // =================================================================== | 1433 | // =================================================================== |
1344 | /* | 1434 | /* |
@@ -1380,7 +1470,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1380 | VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); | 1470 | VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); |
1381 | 1471 | ||
1382 | VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", | 1472 | VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", |
1383 | Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, | 1473 | Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, |
1384 | m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); | 1474 | m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); |
1385 | */ | 1475 | */ |
1386 | } | 1476 | } |
@@ -1433,9 +1523,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1433 | VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; | 1523 | VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; |
1434 | 1524 | ||
1435 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | 1525 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", |
1436 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); | 1526 | ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); |
1437 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", | 1527 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", |
1438 | Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); | 1528 | ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); |
1439 | } | 1529 | } |
1440 | } | 1530 | } |
1441 | 1531 | ||
@@ -1447,13 +1537,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1447 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude | 1537 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude |
1448 | // of the yaw effect will be proportional to the | 1538 | // of the yaw effect will be proportional to the |
1449 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's | 1539 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's |
1450 | // velocity along its preferred axis of motion. | 1540 | // velocity along its preferred axis of motion. |
1451 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any | 1541 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any |
1452 | // positive rotation (by the right-hand rule) about the roll-axis will effect a | 1542 | // positive rotation (by the right-hand rule) about the roll-axis will effect a |
1453 | // (negative) torque around the yaw-axis, making it turn to the right--that is the | 1543 | // (negative) torque around the yaw-axis, making it turn to the right--that is the |
1454 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. | 1544 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. |
1455 | // Negating the banking coefficient will make it so that the vehicle leans to the | 1545 | // Negating the banking coefficient will make it so that the vehicle leans to the |
1456 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). | 1546 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). |
1457 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making | 1547 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making |
1458 | // banking vehicles do what you want rather than what the laws of physics allow. | 1548 | // banking vehicles do what you want rather than what the laws of physics allow. |
1459 | // For example, consider a real motorcycle...it must be moving forward in order for | 1549 | // For example, consider a real motorcycle...it must be moving forward in order for |
@@ -1465,11 +1555,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1465 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the | 1555 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the |
1466 | // banking effect depends only on the vehicle's rotation about its roll-axis compared | 1556 | // banking effect depends only on the vehicle's rotation about its roll-axis compared |
1467 | // to "dynamic" where the banking is also proportional to its velocity along its | 1557 | // to "dynamic" where the banking is also proportional to its velocity along its |
1468 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. | 1558 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. |
1469 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the | 1559 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the |
1470 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to | 1560 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to |
1471 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can | 1561 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can |
1472 | // make a sluggish vehicle by giving it a timescale of several seconds. | 1562 | // make a sluggish vehicle by giving it a timescale of several seconds. |
1473 | public void ComputeAngularBanking() | 1563 | public void ComputeAngularBanking() |
1474 | { | 1564 | { |
1475 | if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | 1565 | if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) |
@@ -1498,10 +1588,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1498 | 1588 | ||
1499 | //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; | 1589 | //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; |
1500 | VehicleRotationalVelocity += bankingContributionV; | 1590 | VehicleRotationalVelocity += bankingContributionV; |
1501 | 1591 | ||
1502 | 1592 | ||
1503 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", | 1593 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", |
1504 | Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); | 1594 | ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); |
1505 | } | 1595 | } |
1506 | } | 1596 | } |
1507 | 1597 | ||
@@ -1540,11 +1630,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1540 | if (rotq != m_rot) | 1630 | if (rotq != m_rot) |
1541 | { | 1631 | { |
1542 | VehicleOrientation = m_rot; | 1632 | VehicleOrientation = m_rot; |
1543 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 1633 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot); |
1544 | } | 1634 | } |
1545 | 1635 | ||
1546 | } | 1636 | } |
1547 | 1637 | ||
1638 | // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce | ||
1639 | // some value by to apply this friction. | ||
1640 | private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep) | ||
1641 | { | ||
1642 | Vector3 frictionFactor = Vector3.Zero; | ||
1643 | if (friction != BSMotor.InfiniteVector) | ||
1644 | { | ||
1645 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
1646 | // Individual friction components can be 'infinite' so compute each separately. | ||
1647 | frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X); | ||
1648 | frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y); | ||
1649 | frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z); | ||
1650 | frictionFactor *= pTimestep; | ||
1651 | } | ||
1652 | return frictionFactor; | ||
1653 | } | ||
1654 | |||
1548 | private float ClampInRange(float low, float val, float high) | 1655 | private float ClampInRange(float low, float val, float high) |
1549 | { | 1656 | { |
1550 | return Math.Max(low, Math.Min(val, high)); | 1657 | return Math.Max(low, Math.Min(val, high)); |
@@ -1554,8 +1661,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1554 | // Invoke the detailed logger and output something if it's enabled. | 1661 | // Invoke the detailed logger and output something if it's enabled. |
1555 | private void VDetailLog(string msg, params Object[] args) | 1662 | private void VDetailLog(string msg, params Object[] args) |
1556 | { | 1663 | { |
1557 | if (Prim.PhysicsScene.VehicleLoggingEnabled) | 1664 | if (ControllingPrim.PhysScene.VehicleLoggingEnabled) |
1558 | Prim.PhysicsScene.DetailLog(msg, args); | 1665 | ControllingPrim.PhysScene.DetailLog(msg, args); |
1559 | } | 1666 | } |
1560 | } | 1667 | } |
1561 | } | 1668 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 4ece1eb..76c2187 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -80,7 +80,7 @@ public abstract class BSLinkset | |||
80 | 80 | ||
81 | public BSPrimLinkable LinksetRoot { get; protected set; } | 81 | public BSPrimLinkable LinksetRoot { get; protected set; } |
82 | 82 | ||
83 | public BSScene PhysicsScene { get; private set; } | 83 | protected BSScene m_physicsScene { get; private set; } |
84 | 84 | ||
85 | static int m_nextLinksetID = 1; | 85 | static int m_nextLinksetID = 1; |
86 | public int LinksetID { get; private set; } | 86 | public int LinksetID { get; private set; } |
@@ -93,13 +93,6 @@ public abstract class BSLinkset | |||
93 | // to the physical representation is done via the tainting mechenism. | 93 | // to the physical representation is done via the tainting mechenism. |
94 | protected object m_linksetActivityLock = new Object(); | 94 | protected object m_linksetActivityLock = new Object(); |
95 | 95 | ||
96 | // Some linksets have a preferred physical shape. | ||
97 | // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. | ||
98 | public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor) | ||
99 | { | ||
100 | return BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
101 | } | ||
102 | |||
103 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | 96 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims |
104 | public float LinksetMass { get; protected set; } | 97 | public float LinksetMass { get; protected set; } |
105 | 98 | ||
@@ -122,7 +115,7 @@ public abstract class BSLinkset | |||
122 | // We create LOTS of linksets. | 115 | // We create LOTS of linksets. |
123 | if (m_nextLinksetID <= 0) | 116 | if (m_nextLinksetID <= 0) |
124 | m_nextLinksetID = 1; | 117 | m_nextLinksetID = 1; |
125 | PhysicsScene = scene; | 118 | m_physicsScene = scene; |
126 | LinksetRoot = parent; | 119 | LinksetRoot = parent; |
127 | m_children = new HashSet<BSPrimLinkable>(); | 120 | m_children = new HashSet<BSPrimLinkable>(); |
128 | LinksetMass = parent.RawMass; | 121 | LinksetMass = parent.RawMass; |
@@ -165,7 +158,7 @@ public abstract class BSLinkset | |||
165 | } | 158 | } |
166 | 159 | ||
167 | // The child is down to a linkset of just itself | 160 | // The child is down to a linkset of just itself |
168 | return BSLinkset.Factory(PhysicsScene, child); | 161 | return BSLinkset.Factory(m_physicsScene, child); |
169 | } | 162 | } |
170 | 163 | ||
171 | // Return 'true' if the passed object is the root object of this linkset | 164 | // Return 'true' if the passed object is the root object of this linkset |
@@ -221,7 +214,7 @@ public abstract class BSLinkset | |||
221 | // I am the root of a linkset and a new child is being added | 214 | // I am the root of a linkset and a new child is being added |
222 | // Called while LinkActivity is locked. | 215 | // Called while LinkActivity is locked. |
223 | protected abstract void AddChildToLinkset(BSPrimLinkable child); | 216 | protected abstract void AddChildToLinkset(BSPrimLinkable child); |
224 | 217 | ||
225 | // I am the root of a linkset and one of my children is being removed. | 218 | // I am the root of a linkset and one of my children is being removed. |
226 | // Safe to call even if the child is not really in my linkset. | 219 | // Safe to call even if the child is not really in my linkset. |
227 | protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); | 220 | protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); |
@@ -263,7 +256,7 @@ public abstract class BSLinkset | |||
263 | // This is called when the root body is changing. | 256 | // This is called when the root body is changing. |
264 | // Returns 'true' of something was actually removed and would need restoring | 257 | // Returns 'true' of something was actually removed and would need restoring |
265 | // Called at taint-time!! | 258 | // Called at taint-time!! |
266 | public abstract bool RemoveBodyDependencies(BSPrimLinkable child); | 259 | public abstract bool RemoveDependencies(BSPrimLinkable child); |
267 | 260 | ||
268 | // ================================================================ | 261 | // ================================================================ |
269 | protected virtual float ComputeLinksetMass() | 262 | protected virtual float ComputeLinksetMass() |
@@ -323,8 +316,8 @@ public abstract class BSLinkset | |||
323 | // Invoke the detailed logger and output something if it's enabled. | 316 | // Invoke the detailed logger and output something if it's enabled. |
324 | protected void DetailLog(string msg, params Object[] args) | 317 | protected void DetailLog(string msg, params Object[] args) |
325 | { | 318 | { |
326 | if (PhysicsScene.PhysicsLogging.Enabled) | 319 | if (m_physicsScene.PhysicsLogging.Enabled) |
327 | PhysicsScene.DetailLog(msg, args); | 320 | m_physicsScene.DetailLog(msg, args); |
328 | } | 321 | } |
329 | 322 | ||
330 | } | 323 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index e05562a..350a5d1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -35,6 +35,7 @@ using OMV = OpenMetaverse; | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
36 | { | 36 | { |
37 | 37 | ||
38 | /* | ||
38 | // When a child is linked, the relationship position of the child to the parent | 39 | // When a child is linked, the relationship position of the child to the parent |
39 | // is remembered so the child's world position can be recomputed when it is | 40 | // is remembered so the child's world position can be recomputed when it is |
40 | // removed from the linkset. | 41 | // removed from the linkset. |
@@ -88,6 +89,7 @@ sealed class BSLinksetCompoundInfo : BSLinksetInfo | |||
88 | return buff.ToString(); | 89 | return buff.ToString(); |
89 | } | 90 | } |
90 | }; | 91 | }; |
92 | */ | ||
91 | 93 | ||
92 | public sealed class BSLinksetCompound : BSLinkset | 94 | public sealed class BSLinksetCompound : BSLinkset |
93 | { | 95 | { |
@@ -98,19 +100,6 @@ public sealed class BSLinksetCompound : BSLinkset | |||
98 | { | 100 | { |
99 | } | 101 | } |
100 | 102 | ||
101 | // For compound implimented linksets, if there are children, use compound shape for the root. | ||
102 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor) | ||
103 | { | ||
104 | // Returning 'unknown' means we don't have a preference. | ||
105 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
106 | if (IsRoot(requestor) && HasAnyChildren) | ||
107 | { | ||
108 | ret = BSPhysicsShapeType.SHAPE_COMPOUND; | ||
109 | } | ||
110 | // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); | ||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | // When physical properties are changed the linkset needs to recalculate | 103 | // When physical properties are changed the linkset needs to recalculate |
115 | // its internal properties. | 104 | // its internal properties. |
116 | public override void Refresh(BSPrimLinkable requestor) | 105 | public override void Refresh(BSPrimLinkable requestor) |
@@ -124,14 +113,14 @@ public sealed class BSLinksetCompound : BSLinkset | |||
124 | // Schedule a refresh to happen after all the other taint processing. | 113 | // Schedule a refresh to happen after all the other taint processing. |
125 | private void ScheduleRebuild(BSPrimLinkable requestor) | 114 | private void ScheduleRebuild(BSPrimLinkable requestor) |
126 | { | 115 | { |
127 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", | 116 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", |
128 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); | 117 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); |
129 | // When rebuilding, it is possible to set properties that would normally require a rebuild. | 118 | // When rebuilding, it is possible to set properties that would normally require a rebuild. |
130 | // If already rebuilding, don't request another rebuild. | 119 | // If already rebuilding, don't request another rebuild. |
131 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. | 120 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. |
132 | if (!Rebuilding && HasAnyChildren) | 121 | if (!Rebuilding && HasAnyChildren) |
133 | { | 122 | { |
134 | PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() | 123 | m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() |
135 | { | 124 | { |
136 | if (HasAnyChildren) | 125 | if (HasAnyChildren) |
137 | RecomputeLinksetCompound(); | 126 | RecomputeLinksetCompound(); |
@@ -153,26 +142,11 @@ public sealed class BSLinksetCompound : BSLinkset | |||
153 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | 142 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. |
154 | ScheduleRebuild(LinksetRoot); | 143 | ScheduleRebuild(LinksetRoot); |
155 | } | 144 | } |
156 | else | ||
157 | { | ||
158 | // The origional prims are removed from the world as the shape of the root compound | ||
159 | // shape takes over. | ||
160 | PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
161 | PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); | ||
162 | // We don't want collisions from the old linkset children. | ||
163 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
164 | |||
165 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
166 | |||
167 | ret = true; | ||
168 | } | ||
169 | return ret; | 145 | return ret; |
170 | } | 146 | } |
171 | 147 | ||
172 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | 148 | // The object is going static (non-physical). We do not do anything for static linksets. |
173 | // Return 'true' if any properties updated on the passed object. | 149 | // Return 'true' if any properties updated on the passed object. |
174 | // This doesn't normally happen -- OpenSim removes the objects from the physical | ||
175 | // world if it is a static linkset. | ||
176 | // Called at taint-time! | 150 | // Called at taint-time! |
177 | public override bool MakeStatic(BSPrimLinkable child) | 151 | public override bool MakeStatic(BSPrimLinkable child) |
178 | { | 152 | { |
@@ -180,19 +154,9 @@ public sealed class BSLinksetCompound : BSLinkset | |||
180 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 154 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
181 | if (IsRoot(child)) | 155 | if (IsRoot(child)) |
182 | { | 156 | { |
157 | // Schedule a rebuild to verify that the root shape is set to the real shape. | ||
183 | ScheduleRebuild(LinksetRoot); | 158 | ScheduleRebuild(LinksetRoot); |
184 | } | 159 | } |
185 | else | ||
186 | { | ||
187 | // The non-physical children can come back to life. | ||
188 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
189 | |||
190 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
191 | |||
192 | // Don't force activation so setting of DISABLE_SIMULATION can stay if used. | ||
193 | PhysicsScene.PE.Activate(child.PhysBody, false); | ||
194 | ret = true; | ||
195 | } | ||
196 | return ret; | 160 | return ret; |
197 | } | 161 | } |
198 | 162 | ||
@@ -200,13 +164,20 @@ public sealed class BSLinksetCompound : BSLinkset | |||
200 | // Called at taint-time. | 164 | // Called at taint-time. |
201 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) | 165 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) |
202 | { | 166 | { |
167 | if (!LinksetRoot.IsPhysicallyActive) | ||
168 | { | ||
169 | // No reason to do this physical stuff for static linksets. | ||
170 | DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID); | ||
171 | return; | ||
172 | } | ||
173 | |||
203 | // The user moving a child around requires the rebuilding of the linkset compound shape | 174 | // The user moving a child around requires the rebuilding of the linkset compound shape |
204 | // One problem is this happens when a border is crossed -- the simulator implementation | 175 | // One problem is this happens when a border is crossed -- the simulator implementation |
205 | // stores the position into the group which causes the move of the object | 176 | // stores the position into the group which causes the move of the object |
206 | // but it also means all the child positions get updated. | 177 | // but it also means all the child positions get updated. |
207 | // What would cause an unnecessary rebuild so we make sure the linkset is in a | 178 | // What would cause an unnecessary rebuild so we make sure the linkset is in a |
208 | // region before bothering to do a rebuild. | 179 | // region before bothering to do a rebuild. |
209 | if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) | 180 | if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) |
210 | { | 181 | { |
211 | // If a child of the linkset is updating only the position or rotation, that can be done | 182 | // If a child of the linkset is updating only the position or rotation, that can be done |
212 | // without rebuilding the linkset. | 183 | // without rebuilding the linkset. |
@@ -218,22 +189,22 @@ public sealed class BSLinksetCompound : BSLinkset | |||
218 | // and that is caused by us updating the object. | 189 | // and that is caused by us updating the object. |
219 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) | 190 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) |
220 | { | 191 | { |
221 | // Find the physical instance of the child | 192 | // Find the physical instance of the child |
222 | if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) | 193 | if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) |
223 | { | 194 | { |
224 | // It is possible that the linkset is still under construction and the child is not yet | 195 | // It is possible that the linkset is still under construction and the child is not yet |
225 | // inserted into the compound shape. A rebuild of the linkset in a pre-step action will | 196 | // inserted into the compound shape. A rebuild of the linkset in a pre-step action will |
226 | // build the whole thing with the new position or rotation. | 197 | // build the whole thing with the new position or rotation. |
227 | // The index must be checked because Bullet references the child array but does no validity | 198 | // The index must be checked because Bullet references the child array but does no validity |
228 | // checking of the child index passed. | 199 | // checking of the child index passed. |
229 | int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); | 200 | int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); |
230 | if (updated.LinksetChildIndex < numLinksetChildren) | 201 | if (updated.LinksetChildIndex < numLinksetChildren) |
231 | { | 202 | { |
232 | BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex); | 203 | BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); |
233 | if (linksetChildShape.HasPhysicalShape) | 204 | if (linksetChildShape.HasPhysicalShape) |
234 | { | 205 | { |
235 | // Found the child shape within the compound shape | 206 | // Found the child shape within the compound shape |
236 | PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex, | 207 | m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, |
237 | updated.RawPosition - LinksetRoot.RawPosition, | 208 | updated.RawPosition - LinksetRoot.RawPosition, |
238 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), | 209 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), |
239 | true /* shouldRecalculateLocalAabb */); | 210 | true /* shouldRecalculateLocalAabb */); |
@@ -275,75 +246,22 @@ public sealed class BSLinksetCompound : BSLinkset | |||
275 | } | 246 | } |
276 | 247 | ||
277 | // Routine called when rebuilding the body of some member of the linkset. | 248 | // Routine called when rebuilding the body of some member of the linkset. |
278 | // Since we don't keep in world relationships, do nothing unless it's a child changing. | 249 | // If one of the bodies is being changed, the linkset needs rebuilding. |
250 | // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated. | ||
279 | // Returns 'true' of something was actually removed and would need restoring | 251 | // Returns 'true' of something was actually removed and would need restoring |
280 | // Called at taint-time!! | 252 | // Called at taint-time!! |
281 | public override bool RemoveBodyDependencies(BSPrimLinkable child) | 253 | public override bool RemoveDependencies(BSPrimLinkable child) |
282 | { | 254 | { |
283 | bool ret = false; | 255 | bool ret = false; |
284 | 256 | ||
285 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | 257 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", |
286 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); | 258 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); |
287 | 259 | ||
288 | if (!IsRoot(child)) | 260 | ScheduleRebuild(child); |
289 | { | ||
290 | // Because it is a convenient time, recompute child world position and rotation based on | ||
291 | // its position in the linkset. | ||
292 | RecomputeChildWorldPosition(child, true /* inTaintTime */); | ||
293 | child.LinksetInfo = null; | ||
294 | } | ||
295 | |||
296 | // Cannot schedule a refresh/rebuild here because this routine is called when | ||
297 | // the linkset is being rebuilt. | ||
298 | // InternalRefresh(LinksetRoot); | ||
299 | 261 | ||
300 | return ret; | 262 | return ret; |
301 | } | 263 | } |
302 | 264 | ||
303 | // When the linkset is built, the child shape is added to the compound shape relative to the | ||
304 | // root shape. The linkset then moves around but this does not move the actual child | ||
305 | // prim. The child prim's location must be recomputed based on the location of the root shape. | ||
306 | private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime) | ||
307 | { | ||
308 | // For the moment (20130201), disable this computation (converting the child physical addr back to | ||
309 | // a region address) until we have a good handle on center-of-mass offsets and what the physics | ||
310 | // engine moving a child actually means. | ||
311 | // The simulator keeps track of where children should be as the linkset moves. Setting | ||
312 | // the pos/rot here does not effect that knowledge as there is no good way for the | ||
313 | // physics engine to send the simulator an update for a child. | ||
314 | |||
315 | /* | ||
316 | BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; | ||
317 | if (lci != null) | ||
318 | { | ||
319 | if (inTaintTime) | ||
320 | { | ||
321 | OMV.Vector3 oldPos = child.RawPosition; | ||
322 | child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot; | ||
323 | child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
324 | DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", | ||
325 | child.LocalID, oldPos, lci, child.RawPosition); | ||
326 | } | ||
327 | else | ||
328 | { | ||
329 | // TaintedObject is not used here so the raw position is set now and not at taint-time. | ||
330 | child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot; | ||
331 | child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
332 | } | ||
333 | } | ||
334 | else | ||
335 | { | ||
336 | // This happens when children have been added to the linkset but the linkset | ||
337 | // has not been constructed yet. So like, at taint time, adding children to a linkset | ||
338 | // and then changing properties of the children (makePhysical, for instance) | ||
339 | // but the post-print action of actually rebuilding the linkset has not yet happened. | ||
340 | // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", | ||
341 | // LogHeader, child.LocalID); | ||
342 | DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); | ||
343 | } | ||
344 | */ | ||
345 | } | ||
346 | |||
347 | // ================================================================ | 265 | // ================================================================ |
348 | 266 | ||
349 | // Add a new child to the linkset. | 267 | // Add a new child to the linkset. |
@@ -376,7 +294,6 @@ public sealed class BSLinksetCompound : BSLinkset | |||
376 | child.LocalID, child.PhysBody.AddrString); | 294 | child.LocalID, child.PhysBody.AddrString); |
377 | 295 | ||
378 | // Cause the child's body to be rebuilt and thus restored to normal operation | 296 | // Cause the child's body to be rebuilt and thus restored to normal operation |
379 | RecomputeChildWorldPosition(child, false); | ||
380 | child.LinksetInfo = null; | 297 | child.LinksetInfo = null; |
381 | child.ForceBodyShapeRebuild(false); | 298 | child.ForceBodyShapeRebuild(false); |
382 | 299 | ||
@@ -399,108 +316,105 @@ public sealed class BSLinksetCompound : BSLinkset | |||
399 | // Constraint linksets are rebuilt every time. | 316 | // Constraint linksets are rebuilt every time. |
400 | // Note that this works for rebuilding just the root after a linkset is taken apart. | 317 | // Note that this works for rebuilding just the root after a linkset is taken apart. |
401 | // Called at taint time!! | 318 | // Called at taint time!! |
402 | private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged | 319 | private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape |
320 | private bool disableCOM = true; // For basic linkset debugging, turn off the center-of-mass setting | ||
403 | private void RecomputeLinksetCompound() | 321 | private void RecomputeLinksetCompound() |
404 | { | 322 | { |
405 | try | 323 | try |
406 | { | 324 | { |
407 | // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.) | ||
408 | Rebuilding = true; | 325 | Rebuilding = true; |
409 | 326 | ||
410 | // Cause the root shape to be rebuilt as a compound object with just the root in it | 327 | // No matter what is being done, force the root prim's PhysBody and PhysShape to get set |
411 | LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */); | 328 | // to what they should be as if the root was not in a linkset. |
329 | // Not that bad since we only get into this routine if there are children in the linkset and | ||
330 | // something has been updated/changed. | ||
331 | LinksetRoot.ForceBodyShapeRebuild(true); | ||
412 | 332 | ||
413 | // The center of mass for the linkset is the geometric center of the group. | 333 | // There is no reason to build all this physical stuff for a non-physical linkset. |
414 | // Compute a displacement for each component so it is relative to the center-of-mass. | 334 | if (!LinksetRoot.IsPhysicallyActive) |
415 | // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass | ||
416 | OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition; | ||
417 | if (!disableCOM) // DEBUG DEBUG | ||
418 | { | 335 | { |
419 | // Compute a center-of-mass in world coordinates. | 336 | // Clean up any old linkset shape and make sure the root shape is set to the root object. |
420 | centerOfMassW = ComputeLinksetCenterOfMass(); | 337 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); |
421 | } | ||
422 | 338 | ||
423 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | 339 | return; // Note the 'finally' clause at the botton which will get executed. |
424 | 340 | } | |
425 | // 'centerDisplacement' is the value to subtract from children to give physical offset position | ||
426 | OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; | ||
427 | LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement); | ||
428 | 341 | ||
429 | // This causes the physical position of the root prim to be offset to accomodate for the displacements | 342 | // Get a new compound shape to build the linkset shape in. |
430 | LinksetRoot.ForcePosition = LinksetRoot.RawPosition; | 343 | BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); |
431 | 344 | ||
432 | // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM | 345 | // The center of mass for the linkset is the geometric center of the group. |
433 | PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */, | 346 | // Compute a displacement for each component so it is relative to the center-of-mass. |
434 | -centerDisplacement, | 347 | // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass |
435 | OMV.Quaternion.Identity, // LinksetRoot.RawOrientation, | 348 | OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); |
436 | false /* shouldRecalculateLocalAabb (is done later after linkset built) */); | ||
437 | 349 | ||
438 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", | 350 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); |
439 | LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement); | ||
440 | 351 | ||
441 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | 352 | // 'centerDisplacement' is the value to subtract from children to give physical offset position |
442 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | 353 | OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; |
354 | if (UseBulletSimRootOffsetHack || disableCOM) | ||
355 | { | ||
356 | centerDisplacementV = OMV.Vector3.Zero; | ||
357 | LinksetRoot.ClearDisplacement(); | ||
358 | } | ||
359 | else | ||
360 | { | ||
361 | LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); | ||
362 | } | ||
363 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", | ||
364 | LinksetRoot.LocalID, LinksetRoot.RawPosition, centerOfMassW, centerDisplacementV); | ||
443 | 365 | ||
444 | // Add a shape for each of the other children in the linkset | 366 | // Add the shapes of all the components of the linkset |
445 | int memberIndex = 1; | 367 | int memberIndex = 1; |
446 | ForEachMember(delegate(BSPrimLinkable cPrim) | 368 | ForEachMember(delegate(BSPrimLinkable cPrim) |
447 | { | 369 | { |
448 | if (IsRoot(cPrim)) | 370 | // Root shape is always index zero. |
371 | cPrim.LinksetChildIndex = IsRoot(cPrim) ? 0 : memberIndex; | ||
372 | |||
373 | // Get a reference to the shape of the child and add that shape to the linkset compound shape | ||
374 | BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); | ||
375 | OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacementV; | ||
376 | OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation; | ||
377 | m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); | ||
378 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}", | ||
379 | LinksetRoot.LocalID, memberIndex, childShape, offsetPos, offsetRot); | ||
380 | |||
381 | // Since we are borrowing the shape of the child, disable the origional child body | ||
382 | if (!IsRoot(cPrim)) | ||
449 | { | 383 | { |
450 | cPrim.LinksetChildIndex = 0; | 384 | m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
385 | m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION); | ||
386 | // We don't want collisions from the old linkset children. | ||
387 | m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
388 | cPrim.PhysBody.collisionType = CollisionType.LinksetChild; | ||
451 | } | 389 | } |
452 | else | ||
453 | { | ||
454 | cPrim.LinksetChildIndex = memberIndex; | ||
455 | 390 | ||
456 | if (cPrim.PhysShape.isNativeShape) | 391 | memberIndex++; |
457 | { | ||
458 | // A native shape is turned into a hull collision shape because native | ||
459 | // shapes are not shared so we have to hullify it so it will be tracked | ||
460 | // and freed at the correct time. This also solves the scaling problem | ||
461 | // (native shapes scale but hull/meshes are assumed to not be). | ||
462 | // TODO: decide of the native shape can just be used in the compound shape. | ||
463 | // Use call to CreateGeomNonSpecial(). | ||
464 | BulletShape saveShape = cPrim.PhysShape; | ||
465 | cPrim.PhysShape.Clear(); // Don't let the create free the child's shape | ||
466 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
467 | BulletShape newShape = cPrim.PhysShape; | ||
468 | cPrim.PhysShape = saveShape; | ||
469 | |||
470 | OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; | ||
471 | OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; | ||
472 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot); | ||
473 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}", | ||
474 | LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot); | ||
475 | } | ||
476 | else | ||
477 | { | ||
478 | // For the shared shapes (meshes and hulls), just use the shape in the child. | ||
479 | // The reference count added here will be decremented when the compound shape | ||
480 | // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). | ||
481 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
482 | { | ||
483 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
484 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
485 | } | ||
486 | OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; | ||
487 | OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; | ||
488 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot); | ||
489 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}", | ||
490 | LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot); | ||
491 | 392 | ||
492 | } | ||
493 | memberIndex++; | ||
494 | } | ||
495 | return false; // 'false' says to move onto the next child in the list | 393 | return false; // 'false' says to move onto the next child in the list |
496 | }); | 394 | }); |
497 | 395 | ||
396 | // Replace the root shape with the built compound shape. | ||
397 | // Object removed and added to world to get collision cache rebuilt for new shape. | ||
398 | LinksetRoot.PhysShape.Dereference(m_physicsScene); | ||
399 | LinksetRoot.PhysShape = linksetShape; | ||
400 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
401 | m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo); | ||
402 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
403 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", | ||
404 | LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape); | ||
405 | |||
498 | // With all of the linkset packed into the root prim, it has the mass of everyone. | 406 | // With all of the linkset packed into the root prim, it has the mass of everyone. |
499 | LinksetMass = ComputeLinksetMass(); | 407 | LinksetMass = ComputeLinksetMass(); |
500 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); | 408 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); |
501 | 409 | ||
502 | // Enable the physical position updator to return the position and rotation of the root shape | 410 | if (UseBulletSimRootOffsetHack) |
503 | PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); | 411 | { |
412 | // Enable the physical position updator to return the position and rotation of the root shape. | ||
413 | // This enables a feature in the C++ code to return the world coordinates of the first shape in the | ||
414 | // compound shape. This eleviates the need to offset the returned physical position by the | ||
415 | // center-of-mass offset. | ||
416 | m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); | ||
417 | } | ||
504 | } | 418 | } |
505 | finally | 419 | finally |
506 | { | 420 | { |
@@ -508,7 +422,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
508 | } | 422 | } |
509 | 423 | ||
510 | // See that the Aabb surrounds the new shape | 424 | // See that the Aabb surrounds the new shape |
511 | PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); | 425 | m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); |
512 | } | 426 | } |
513 | } | 427 | } |
514 | } \ No newline at end of file | 428 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 6d252ca..a06a44d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | |||
@@ -51,7 +51,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
51 | if (HasAnyChildren && IsRoot(requestor)) | 51 | if (HasAnyChildren && IsRoot(requestor)) |
52 | { | 52 | { |
53 | // Queue to happen after all the other taint processing | 53 | // Queue to happen after all the other taint processing |
54 | PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() | 54 | m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() |
55 | { | 55 | { |
56 | if (HasAnyChildren && IsRoot(requestor)) | 56 | if (HasAnyChildren && IsRoot(requestor)) |
57 | RecomputeLinksetConstraints(); | 57 | RecomputeLinksetConstraints(); |
@@ -93,11 +93,11 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
93 | // up to rebuild the constraints before the next simulation step. | 93 | // up to rebuild the constraints before the next simulation step. |
94 | // Returns 'true' of something was actually removed and would need restoring | 94 | // Returns 'true' of something was actually removed and would need restoring |
95 | // Called at taint-time!! | 95 | // Called at taint-time!! |
96 | public override bool RemoveBodyDependencies(BSPrimLinkable child) | 96 | public override bool RemoveDependencies(BSPrimLinkable child) |
97 | { | 97 | { |
98 | bool ret = false; | 98 | bool ret = false; |
99 | 99 | ||
100 | DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", | 100 | DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}", |
101 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); | 101 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); |
102 | 102 | ||
103 | lock (m_linksetActivityLock) | 103 | lock (m_linksetActivityLock) |
@@ -142,7 +142,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
142 | rootx.LocalID, rootx.PhysBody.AddrString, | 142 | rootx.LocalID, rootx.PhysBody.AddrString, |
143 | childx.LocalID, childx.PhysBody.AddrString); | 143 | childx.LocalID, childx.PhysBody.AddrString); |
144 | 144 | ||
145 | PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() | 145 | m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() |
146 | { | 146 | { |
147 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | 147 | PhysicallyUnlinkAChildFromRoot(rootx, childx); |
148 | }); | 148 | }); |
@@ -187,7 +187,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
187 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 187 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 |
188 | 188 | ||
189 | BSConstraint6Dof constrain = new BSConstraint6Dof( | 189 | BSConstraint6Dof constrain = new BSConstraint6Dof( |
190 | PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); | 190 | m_physicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); |
191 | // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); | 191 | // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); |
192 | 192 | ||
193 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. | 193 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. |
@@ -216,7 +216,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
216 | // ================================================================================== | 216 | // ================================================================================== |
217 | */ | 217 | */ |
218 | 218 | ||
219 | PhysicsScene.Constraints.AddConstraint(constrain); | 219 | m_physicsScene.Constraints.AddConstraint(constrain); |
220 | 220 | ||
221 | // zero linear and angular limits makes the objects unable to move in relation to each other | 221 | // zero linear and angular limits makes the objects unable to move in relation to each other |
222 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | 222 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); |
@@ -248,10 +248,10 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
248 | childPrim.LocalID, childPrim.PhysBody.AddrString); | 248 | childPrim.LocalID, childPrim.PhysBody.AddrString); |
249 | 249 | ||
250 | // Find the constraint for this link and get rid of it from the overall collection and from my list | 250 | // Find the constraint for this link and get rid of it from the overall collection and from my list |
251 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) | 251 | if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) |
252 | { | 252 | { |
253 | // Make the child refresh its location | 253 | // Make the child refresh its location |
254 | PhysicsScene.PE.PushUpdate(childPrim.PhysBody); | 254 | m_physicsScene.PE.PushUpdate(childPrim.PhysBody); |
255 | ret = true; | 255 | ret = true; |
256 | } | 256 | } |
257 | 257 | ||
@@ -265,7 +265,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
265 | { | 265 | { |
266 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | 266 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); |
267 | 267 | ||
268 | return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); | 268 | return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); |
269 | } | 269 | } |
270 | 270 | ||
271 | // Call each of the constraints that make up this linkset and recompute the | 271 | // Call each of the constraints that make up this linkset and recompute the |
@@ -289,7 +289,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
289 | child.UpdatePhysicalMassProperties(linksetMass, true); | 289 | child.UpdatePhysicalMassProperties(linksetMass, true); |
290 | 290 | ||
291 | BSConstraint constrain; | 291 | BSConstraint constrain; |
292 | if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) | 292 | if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) |
293 | { | 293 | { |
294 | // If constraint doesn't exist yet, create it. | 294 | // If constraint doesn't exist yet, create it. |
295 | constrain = BuildConstraint(LinksetRoot, child); | 295 | constrain = BuildConstraint(LinksetRoot, child); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index 9501e2d..ef662b5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | |||
@@ -65,13 +65,11 @@ public abstract class BSMotor | |||
65 | } | 65 | } |
66 | 66 | ||
67 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. | 67 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. |
68 | // The TargetValue decays in TargetValueDecayTimeScale and | 68 | // The TargetValue decays in TargetValueDecayTimeScale. |
69 | // the CurrentValue will be held back by FrictionTimeScale. | ||
70 | // This motor will "zero itself" over time in that the targetValue will | 69 | // This motor will "zero itself" over time in that the targetValue will |
71 | // decay to zero and the currentValue will follow it to that zero. | 70 | // decay to zero and the currentValue will follow it to that zero. |
72 | // The overall effect is for the returned correction value to go from large | 71 | // The overall effect is for the returned correction value to go from large |
73 | // values (the total difference between current and target minus friction) | 72 | // values to small and eventually zero values. |
74 | // to small and eventually zero values. | ||
75 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. | 73 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. |
76 | 74 | ||
77 | // For instance, if something is moving at speed X and the desired speed is Y, | 75 | // For instance, if something is moving at speed X and the desired speed is Y, |
@@ -88,7 +86,6 @@ public class BSVMotor : BSMotor | |||
88 | 86 | ||
89 | public virtual float TimeScale { get; set; } | 87 | public virtual float TimeScale { get; set; } |
90 | public virtual float TargetValueDecayTimeScale { get; set; } | 88 | public virtual float TargetValueDecayTimeScale { get; set; } |
91 | public virtual Vector3 FrictionTimescale { get; set; } | ||
92 | public virtual float Efficiency { get; set; } | 89 | public virtual float Efficiency { get; set; } |
93 | 90 | ||
94 | public virtual float ErrorZeroThreshold { get; set; } | 91 | public virtual float ErrorZeroThreshold { get; set; } |
@@ -102,7 +99,7 @@ public class BSVMotor : BSMotor | |||
102 | return ErrorIsZero(LastError); | 99 | return ErrorIsZero(LastError); |
103 | } | 100 | } |
104 | public virtual bool ErrorIsZero(Vector3 err) | 101 | public virtual bool ErrorIsZero(Vector3 err) |
105 | { | 102 | { |
106 | return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); | 103 | return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); |
107 | } | 104 | } |
108 | 105 | ||
@@ -111,16 +108,14 @@ public class BSVMotor : BSMotor | |||
111 | { | 108 | { |
112 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; | 109 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; |
113 | Efficiency = 1f; | 110 | Efficiency = 1f; |
114 | FrictionTimescale = BSMotor.InfiniteVector; | ||
115 | CurrentValue = TargetValue = Vector3.Zero; | 111 | CurrentValue = TargetValue = Vector3.Zero; |
116 | ErrorZeroThreshold = 0.001f; | 112 | ErrorZeroThreshold = 0.001f; |
117 | } | 113 | } |
118 | public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) | 114 | public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency) |
119 | : this(useName) | 115 | : this(useName) |
120 | { | 116 | { |
121 | TimeScale = timeScale; | 117 | TimeScale = timeScale; |
122 | TargetValueDecayTimeScale = decayTimeScale; | 118 | TargetValueDecayTimeScale = decayTimeScale; |
123 | FrictionTimescale = frictionTimeScale; | ||
124 | Efficiency = efficiency; | 119 | Efficiency = efficiency; |
125 | CurrentValue = TargetValue = Vector3.Zero; | 120 | CurrentValue = TargetValue = Vector3.Zero; |
126 | } | 121 | } |
@@ -165,26 +160,11 @@ public class BSVMotor : BSMotor | |||
165 | TargetValue *= (1f - decayFactor); | 160 | TargetValue *= (1f - decayFactor); |
166 | } | 161 | } |
167 | 162 | ||
168 | // The amount we can correct the error is reduced by the friction | ||
169 | Vector3 frictionFactor = Vector3.Zero; | ||
170 | if (FrictionTimescale != BSMotor.InfiniteVector) | ||
171 | { | ||
172 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
173 | // Individual friction components can be 'infinite' so compute each separately. | ||
174 | frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X); | ||
175 | frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y); | ||
176 | frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z); | ||
177 | frictionFactor *= timeStep; | ||
178 | CurrentValue *= (Vector3.One - frictionFactor); | ||
179 | } | ||
180 | |||
181 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", | 163 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", |
182 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | 164 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, |
183 | timeStep, error, correction); | 165 | timeStep, error, correction); |
184 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", | 166 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", |
185 | BSScene.DetailLogZero, UseName, | 167 | BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); |
186 | TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, | ||
187 | TargetValue, CurrentValue); | ||
188 | } | 168 | } |
189 | else | 169 | else |
190 | { | 170 | { |
@@ -235,9 +215,9 @@ public class BSVMotor : BSMotor | |||
235 | // maximum number of outputs to generate. | 215 | // maximum number of outputs to generate. |
236 | int maxOutput = 50; | 216 | int maxOutput = 50; |
237 | MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); | 217 | MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); |
238 | MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", | 218 | MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}", |
239 | BSScene.DetailLogZero, UseName, | 219 | BSScene.DetailLogZero, UseName, |
240 | TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, | 220 | TimeScale, TargetValueDecayTimeScale, Efficiency, |
241 | CurrentValue, TargetValue); | 221 | CurrentValue, TargetValue); |
242 | 222 | ||
243 | LastError = BSMotor.InfiniteVector; | 223 | LastError = BSMotor.InfiniteVector; |
@@ -248,14 +228,14 @@ public class BSVMotor : BSMotor | |||
248 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); | 228 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); |
249 | } | 229 | } |
250 | MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); | 230 | MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); |
251 | 231 | ||
252 | 232 | ||
253 | } | 233 | } |
254 | 234 | ||
255 | public override string ToString() | 235 | public override string ToString() |
256 | { | 236 | { |
257 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", | 237 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", |
258 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); | 238 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); |
259 | } | 239 | } |
260 | } | 240 | } |
261 | 241 | ||
@@ -265,7 +245,6 @@ public class BSFMotor : BSMotor | |||
265 | { | 245 | { |
266 | public virtual float TimeScale { get; set; } | 246 | public virtual float TimeScale { get; set; } |
267 | public virtual float TargetValueDecayTimeScale { get; set; } | 247 | public virtual float TargetValueDecayTimeScale { get; set; } |
268 | public virtual float FrictionTimescale { get; set; } | ||
269 | public virtual float Efficiency { get; set; } | 248 | public virtual float Efficiency { get; set; } |
270 | 249 | ||
271 | public virtual float ErrorZeroThreshold { get; set; } | 250 | public virtual float ErrorZeroThreshold { get; set; } |
@@ -279,16 +258,15 @@ public class BSFMotor : BSMotor | |||
279 | return ErrorIsZero(LastError); | 258 | return ErrorIsZero(LastError); |
280 | } | 259 | } |
281 | public virtual bool ErrorIsZero(float err) | 260 | public virtual bool ErrorIsZero(float err) |
282 | { | 261 | { |
283 | return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); | 262 | return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); |
284 | } | 263 | } |
285 | 264 | ||
286 | public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) | 265 | public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency) |
287 | : base(useName) | 266 | : base(useName) |
288 | { | 267 | { |
289 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; | 268 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; |
290 | Efficiency = 1f; | 269 | Efficiency = 1f; |
291 | FrictionTimescale = BSMotor.Infinite; | ||
292 | CurrentValue = TargetValue = 0f; | 270 | CurrentValue = TargetValue = 0f; |
293 | ErrorZeroThreshold = 0.01f; | 271 | ErrorZeroThreshold = 0.01f; |
294 | } | 272 | } |
@@ -331,24 +309,11 @@ public class BSFMotor : BSMotor | |||
331 | TargetValue *= (1f - decayFactor); | 309 | TargetValue *= (1f - decayFactor); |
332 | } | 310 | } |
333 | 311 | ||
334 | // The amount we can correct the error is reduced by the friction | ||
335 | float frictionFactor = 0f; | ||
336 | if (FrictionTimescale != BSMotor.Infinite) | ||
337 | { | ||
338 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
339 | // Individual friction components can be 'infinite' so compute each separately. | ||
340 | frictionFactor = 1f / FrictionTimescale; | ||
341 | frictionFactor *= timeStep; | ||
342 | CurrentValue *= (1f - frictionFactor); | ||
343 | } | ||
344 | |||
345 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", | 312 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", |
346 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | 313 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, |
347 | timeStep, error, correction); | 314 | timeStep, error, correction); |
348 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", | 315 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", |
349 | BSScene.DetailLogZero, UseName, | 316 | BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); |
350 | TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, | ||
351 | TargetValue, CurrentValue); | ||
352 | } | 317 | } |
353 | else | 318 | else |
354 | { | 319 | { |
@@ -390,8 +355,8 @@ public class BSFMotor : BSMotor | |||
390 | 355 | ||
391 | public override string ToString() | 356 | public override string ToString() |
392 | { | 357 | { |
393 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", | 358 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", |
394 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); | 359 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); |
395 | } | 360 | } |
396 | 361 | ||
397 | } | 362 | } |
@@ -410,7 +375,7 @@ public class BSPIDVMotor : BSVMotor | |||
410 | // The factors are vectors for the three dimensions. This is the proportional of each | 375 | // The factors are vectors for the three dimensions. This is the proportional of each |
411 | // that is applied. This could be multiplied through the actual factors but it | 376 | // that is applied. This could be multiplied through the actual factors but it |
412 | // is sometimes easier to manipulate the factors and their mix separately. | 377 | // is sometimes easier to manipulate the factors and their mix separately. |
413 | // to | 378 | // to |
414 | public Vector3 FactorMix; | 379 | public Vector3 FactorMix; |
415 | 380 | ||
416 | // Arbritrary factor range. | 381 | // Arbritrary factor range. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 385ed9e..aad1108 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Reflection; | ||
29 | using System.Text; | 30 | using System.Text; |
30 | 31 | ||
31 | using OpenSim.Region.Physics.Manager; | 32 | using OpenSim.Region.Physics.Manager; |
@@ -37,7 +38,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
37 | { | 38 | { |
38 | public static class BSParam | 39 | public static class BSParam |
39 | { | 40 | { |
40 | private static string LogHeader = "[BULLETSIM PARAMETERS]"; | 41 | private static string LogHeader = "[BULLETSIM PARAMETERS]"; |
41 | 42 | ||
42 | // Tuning notes: | 43 | // Tuning notes: |
43 | // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 | 44 | // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 |
@@ -51,7 +52,10 @@ public static class BSParam | |||
51 | // This is separate/independent from the collision margin. The collision margin increases the object a bit | 52 | // This is separate/independent from the collision margin. The collision margin increases the object a bit |
52 | // to improve collision detection performance and accuracy. | 53 | // to improve collision detection performance and accuracy. |
53 | // =================== | 54 | // =================== |
54 | // From: | 55 | // From: |
56 | |||
57 | public static bool UseSeparatePhysicsThread { get; private set; } | ||
58 | public static float PhysicsTimeStep { get; private set; } | ||
55 | 59 | ||
56 | // Level of Detail values kept as float because that's what the Meshmerizer wants | 60 | // Level of Detail values kept as float because that's what the Meshmerizer wants |
57 | public static float MeshLOD { get; private set; } | 61 | public static float MeshLOD { get; private set; } |
@@ -86,8 +90,12 @@ public static class BSParam | |||
86 | public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | 90 | public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes |
87 | public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | 91 | public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects |
88 | public static bool ShouldRemoveZeroWidthTriangles { get; private set; } | 92 | public static bool ShouldRemoveZeroWidthTriangles { get; private set; } |
93 | public static bool ShouldUseBulletHACD { get; set; } | ||
94 | public static bool ShouldUseSingleConvexHullForPrims { get; set; } | ||
95 | public static bool ShouldUseGImpactShapeForPrims { get; set; } | ||
96 | public static bool ShouldUseAssetHulls { get; set; } | ||
89 | 97 | ||
90 | public static float TerrainImplementation { get; private set; } | 98 | public static float TerrainImplementation { get; set; } |
91 | public static int TerrainMeshMagnification { get; private set; } | 99 | public static int TerrainMeshMagnification { get; private set; } |
92 | public static float TerrainFriction { get; private set; } | 100 | public static float TerrainFriction { get; private set; } |
93 | public static float TerrainHitFraction { get; private set; } | 101 | public static float TerrainHitFraction { get; private set; } |
@@ -122,11 +130,16 @@ public static class BSParam | |||
122 | public static float AvatarCapsuleWidth { get; private set; } | 130 | public static float AvatarCapsuleWidth { get; private set; } |
123 | public static float AvatarCapsuleDepth { get; private set; } | 131 | public static float AvatarCapsuleDepth { get; private set; } |
124 | public static float AvatarCapsuleHeight { get; private set; } | 132 | public static float AvatarCapsuleHeight { get; private set; } |
133 | public static float AvatarHeightLowFudge { get; private set; } | ||
134 | public static float AvatarHeightMidFudge { get; private set; } | ||
135 | public static float AvatarHeightHighFudge { get; private set; } | ||
125 | public static float AvatarContactProcessingThreshold { get; private set; } | 136 | public static float AvatarContactProcessingThreshold { get; private set; } |
126 | public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } | 137 | public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } |
127 | public static float AvatarStepHeight { get; private set; } | 138 | public static float AvatarStepHeight { get; private set; } |
128 | public static float AvatarStepApproachFactor { get; private set; } | 139 | public static float AvatarStepApproachFactor { get; private set; } |
129 | public static float AvatarStepForceFactor { get; private set; } | 140 | public static float AvatarStepForceFactor { get; private set; } |
141 | public static float AvatarStepUpCorrectionFactor { get; private set; } | ||
142 | public static int AvatarStepSmoothingSteps { get; private set; } | ||
130 | 143 | ||
131 | // Vehicle parameters | 144 | // Vehicle parameters |
132 | public static float VehicleMaxLinearVelocity { get; private set; } | 145 | public static float VehicleMaxLinearVelocity { get; private set; } |
@@ -138,9 +151,10 @@ public static class BSParam | |||
138 | public static float VehicleRestitution { get; private set; } | 151 | public static float VehicleRestitution { get; private set; } |
139 | public static Vector3 VehicleLinearFactor { get; private set; } | 152 | public static Vector3 VehicleLinearFactor { get; private set; } |
140 | public static Vector3 VehicleAngularFactor { get; private set; } | 153 | public static Vector3 VehicleAngularFactor { get; private set; } |
154 | public static Vector3 VehicleInertiaFactor { get; private set; } | ||
141 | public static float VehicleGroundGravityFudge { get; private set; } | 155 | public static float VehicleGroundGravityFudge { get; private set; } |
142 | public static float VehicleAngularBankingTimescaleFudge { get; private set; } | 156 | public static float VehicleAngularBankingTimescaleFudge { get; private set; } |
143 | public static bool VehicleDebuggingEnabled { get; private set; } | 157 | public static bool VehicleDebuggingEnable { get; private set; } |
144 | 158 | ||
145 | // Convex Hulls | 159 | // Convex Hulls |
146 | public static int CSHullMaxDepthSplit { get; private set; } | 160 | public static int CSHullMaxDepthSplit { get; private set; } |
@@ -149,6 +163,15 @@ public static class BSParam | |||
149 | public static float CSHullVolumeConservationThresholdPercent { get; private set; } | 163 | public static float CSHullVolumeConservationThresholdPercent { get; private set; } |
150 | public static int CSHullMaxVertices { get; private set; } | 164 | public static int CSHullMaxVertices { get; private set; } |
151 | public static float CSHullMaxSkinWidth { get; private set; } | 165 | public static float CSHullMaxSkinWidth { get; private set; } |
166 | public static float BHullMaxVerticesPerHull { get; private set; } // 100 | ||
167 | public static float BHullMinClusters { get; private set; } // 2 | ||
168 | public static float BHullCompacityWeight { get; private set; } // 0.1 | ||
169 | public static float BHullVolumeWeight { get; private set; } // 0.0 | ||
170 | public static float BHullConcavity { get; private set; } // 100 | ||
171 | public static bool BHullAddExtraDistPoints { get; private set; } // false | ||
172 | public static bool BHullAddNeighboursDistPoints { get; private set; } // false | ||
173 | public static bool BHullAddFacesPoints { get; private set; } // false | ||
174 | public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false | ||
152 | 175 | ||
153 | // Linkset implementation parameters | 176 | // Linkset implementation parameters |
154 | public static float LinksetImplementation { get; private set; } | 177 | public static float LinksetImplementation { get; private set; } |
@@ -223,16 +246,41 @@ public static class BSParam | |||
223 | getter = pGetter; | 246 | getter = pGetter; |
224 | objectSet = pObjSetter; | 247 | objectSet = pObjSetter; |
225 | } | 248 | } |
226 | /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work | 249 | // Simple parameter variable where property name is the same as the INI file name |
227 | public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc) | 250 | // and the value is only a simple get and set. |
251 | public ParameterDefn(string pName, string pDesc, T pDefault) | ||
228 | : base(pName, pDesc) | 252 | : base(pName, pDesc) |
229 | { | 253 | { |
230 | defaultValue = pDefault; | 254 | defaultValue = pDefault; |
231 | setter = (s, v) => { loc = v; }; | 255 | setter = (s, v) => { SetValueByName(s, name, v); }; |
232 | getter = (s) => { return loc; }; | 256 | getter = (s) => { return GetValueByName(s, name); }; |
233 | objectSet = null; | 257 | objectSet = null; |
234 | } | 258 | } |
235 | */ | 259 | // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same. |
260 | private void SetValueByName(BSScene s, string pName, T val) | ||
261 | { | ||
262 | PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); | ||
263 | if (prop == null) | ||
264 | { | ||
265 | // This should only be output when someone adds a new INI parameter and misspells the name. | ||
266 | s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName); | ||
267 | } | ||
268 | else | ||
269 | { | ||
270 | prop.SetValue(null, val, null); | ||
271 | } | ||
272 | } | ||
273 | // Use reflection to find the property named 'pName' in BSParam and return the value in same. | ||
274 | private T GetValueByName(BSScene s, string pName) | ||
275 | { | ||
276 | PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); | ||
277 | if (prop == null) | ||
278 | { | ||
279 | // This should only be output when someone adds a new INI parameter and misspells the name. | ||
280 | s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName); | ||
281 | } | ||
282 | return (T)prop.GetValue(null, null); | ||
283 | } | ||
236 | public override void AssignDefault(BSScene s) | 284 | public override void AssignDefault(BSScene s) |
237 | { | 285 | { |
238 | setter(s, defaultValue); | 286 | setter(s, defaultValue); |
@@ -309,6 +357,11 @@ public static class BSParam | |||
309 | // v = value (appropriate type) | 357 | // v = value (appropriate type) |
310 | private static ParameterDefnBase[] ParameterDefinitions = | 358 | private static ParameterDefnBase[] ParameterDefinitions = |
311 | { | 359 | { |
360 | new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat", | ||
361 | false ), | ||
362 | new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval", | ||
363 | 0.089f ), | ||
364 | |||
312 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", | 365 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", |
313 | true, | 366 | true, |
314 | (s) => { return ShouldMeshSculptedPrim; }, | 367 | (s) => { return ShouldMeshSculptedPrim; }, |
@@ -322,18 +375,20 @@ public static class BSParam | |||
322 | (s) => { return ShouldUseHullsForPhysicalObjects; }, | 375 | (s) => { return ShouldUseHullsForPhysicalObjects; }, |
323 | (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), | 376 | (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), |
324 | new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", | 377 | new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", |
325 | true, | 378 | true ), |
326 | (s) => { return ShouldRemoveZeroWidthTriangles; }, | 379 | new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD", |
327 | (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ), | 380 | false ), |
381 | new ParameterDefn<bool>("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", | ||
382 | true ), | ||
383 | new ParameterDefn<bool>("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", | ||
384 | false ), | ||
385 | new ParameterDefn<bool>("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info", | ||
386 | true ), | ||
328 | 387 | ||
329 | new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", | 388 | new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", |
330 | 5, | 389 | 5 ), |
331 | (s) => { return CrossingFailuresBeforeOutOfBounds; }, | ||
332 | (s,v) => { CrossingFailuresBeforeOutOfBounds = v; } ), | ||
333 | new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", | 390 | new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", |
334 | 0.1f, | 391 | 0.1f ), |
335 | (s) => { return UpdateVelocityChangeThreshold; }, | ||
336 | (s,v) => { UpdateVelocityChangeThreshold = v; } ), | ||
337 | 392 | ||
338 | new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | 393 | new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", |
339 | 32f, | 394 | 32f, |
@@ -400,18 +455,12 @@ public static class BSParam | |||
400 | (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), | 455 | (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), |
401 | // Density is passed around as 100kg/m3. This scales that to 1kg/m3. | 456 | // Density is passed around as 100kg/m3. This scales that to 1kg/m3. |
402 | new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", | 457 | new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", |
403 | 0.01f, | 458 | 0.01f ), |
404 | (s) => { return DensityScaleFactor; }, | ||
405 | (s,v) => { DensityScaleFactor = v; } ), | ||
406 | 459 | ||
407 | new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", | 460 | new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", |
408 | 2200f, | 461 | 2200f ), |
409 | (s) => { return (float)PID_D; }, | ||
410 | (s,v) => { PID_D = v; } ), | ||
411 | new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing", | 462 | new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing", |
412 | 900f, | 463 | 900f ), |
413 | (s) => { return (float)PID_P; }, | ||
414 | (s,v) => { PID_P = v; } ), | ||
415 | 464 | ||
416 | new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects", | 465 | new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects", |
417 | 0.2f, | 466 | 0.2f, |
@@ -478,86 +527,56 @@ public static class BSParam | |||
478 | (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), | 527 | (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), |
479 | 528 | ||
480 | new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | 529 | new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", |
481 | (float)BSTerrainPhys.TerrainImplementation.Mesh, | 530 | (float)BSTerrainPhys.TerrainImplementation.Mesh ), |
482 | (s) => { return TerrainImplementation; }, | ||
483 | (s,v) => { TerrainImplementation = v; } ), | ||
484 | new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , | 531 | new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , |
485 | 2, | 532 | 2 ), |
486 | (s) => { return TerrainMeshMagnification; }, | ||
487 | (s,v) => { TerrainMeshMagnification = v; } ), | ||
488 | new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , | 533 | new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , |
489 | 0.3f, | 534 | 0.3f ), |
490 | (s) => { return TerrainFriction; }, | ||
491 | (s,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ), | ||
492 | new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" , | 535 | new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" , |
493 | 0.8f, | 536 | 0.8f ), |
494 | (s) => { return TerrainHitFraction; }, | ||
495 | (s,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ), | ||
496 | new ParameterDefn<float>("TerrainRestitution", "Bouncyness" , | 537 | new ParameterDefn<float>("TerrainRestitution", "Bouncyness" , |
497 | 0f, | 538 | 0f ), |
498 | (s) => { return TerrainRestitution; }, | ||
499 | (s,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ), | ||
500 | new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , | 539 | new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , |
501 | 0.0f, | 540 | 0.0f ), |
502 | (s) => { return TerrainContactProcessingThreshold; }, | ||
503 | (s,v) => { TerrainContactProcessingThreshold = v; /* TODO: set on real terrain */ } ), | ||
504 | new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" , | 541 | new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" , |
505 | 0.08f, | 542 | 0.08f ), |
506 | (s) => { return TerrainCollisionMargin; }, | ||
507 | (s,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ), | ||
508 | 543 | ||
509 | new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | 544 | new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |
510 | 0.2f, | 545 | 0.2f ), |
511 | (s) => { return AvatarFriction; }, | ||
512 | (s,v) => { AvatarFriction = v; } ), | ||
513 | new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | 546 | new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", |
514 | 0.95f, | 547 | 0.95f ), |
515 | (s) => { return AvatarStandingFriction; }, | ||
516 | (s,v) => { AvatarStandingFriction = v; } ), | ||
517 | new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", | 548 | new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", |
518 | 1.3f, | 549 | 1.3f ), |
519 | (s) => { return AvatarAlwaysRunFactor; }, | ||
520 | (s,v) => { AvatarAlwaysRunFactor = v; } ), | ||
521 | new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | 550 | new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", |
522 | 3.5f, | 551 | 3.5f) , |
523 | (s) => { return AvatarDensity; }, | ||
524 | (s,v) => { AvatarDensity = v; } ), | ||
525 | new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | 552 | new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", |
526 | 0f, | 553 | 0f ), |
527 | (s) => { return AvatarRestitution; }, | ||
528 | (s,v) => { AvatarRestitution = v; } ), | ||
529 | new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | 554 | new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", |
530 | 0.6f, | 555 | 0.6f ) , |
531 | (s) => { return AvatarCapsuleWidth; }, | ||
532 | (s,v) => { AvatarCapsuleWidth = v; } ), | ||
533 | new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | 556 | new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", |
534 | 0.45f, | 557 | 0.45f ), |
535 | (s) => { return AvatarCapsuleDepth; }, | ||
536 | (s,v) => { AvatarCapsuleDepth = v; } ), | ||
537 | new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar", | 558 | new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar", |
538 | 1.5f, | 559 | 1.5f ), |
539 | (s) => { return AvatarCapsuleHeight; }, | 560 | new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", |
540 | (s,v) => { AvatarCapsuleHeight = v; } ), | 561 | -0.2f ), |
562 | new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", | ||
563 | 0.1f ), | ||
564 | new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", | ||
565 | 0.1f ), | ||
541 | new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | 566 | new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", |
542 | 0.1f, | 567 | 0.1f ), |
543 | (s) => { return AvatarContactProcessingThreshold; }, | ||
544 | (s,v) => { AvatarContactProcessingThreshold = v; } ), | ||
545 | new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", | 568 | new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", |
546 | 1.0f, | 569 | 1.0f ), |
547 | (s) => { return AvatarBelowGroundUpCorrectionMeters; }, | ||
548 | (s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ), | ||
549 | new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction", | 570 | new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction", |
550 | 0.3f, | 571 | 0.6f ) , |
551 | (s) => { return AvatarStepHeight; }, | ||
552 | (s,v) => { AvatarStepHeight = v; } ), | ||
553 | new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", | 572 | new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", |
554 | 0.6f, | 573 | 0.6f ), |
555 | (s) => { return AvatarStepApproachFactor; }, | ||
556 | (s,v) => { AvatarStepApproachFactor = v; } ), | ||
557 | new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", | 574 | new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", |
558 | 2.0f, | 575 | 1.0f ), |
559 | (s) => { return AvatarStepForceFactor; }, | 576 | new ParameterDefn<float>("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step", |
560 | (s,v) => { AvatarStepForceFactor = v; } ), | 577 | 1.0f ), |
578 | new ParameterDefn<int>("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs", | ||
579 | 2 ), | ||
561 | 580 | ||
562 | new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", | 581 | new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", |
563 | 1000.0f, | 582 | 1000.0f, |
@@ -568,37 +587,23 @@ public static class BSParam | |||
568 | (s) => { return (float)VehicleMaxAngularVelocity; }, | 587 | (s) => { return (float)VehicleMaxAngularVelocity; }, |
569 | (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), | 588 | (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), |
570 | new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | 589 | new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", |
571 | 0.0f, | 590 | 0.0f ), |
572 | (s) => { return VehicleAngularDamping; }, | ||
573 | (s,v) => { VehicleAngularDamping = v; } ), | ||
574 | new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)", | 591 | new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)", |
575 | new Vector3(1f, 1f, 1f), | 592 | new Vector3(1f, 1f, 1f) ), |
576 | (s) => { return VehicleLinearFactor; }, | ||
577 | (s,v) => { VehicleLinearFactor = v; } ), | ||
578 | new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", | 593 | new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", |
579 | new Vector3(1f, 1f, 1f), | 594 | new Vector3(1f, 1f, 1f) ), |
580 | (s) => { return VehicleAngularFactor; }, | 595 | new ParameterDefn<Vector3>("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)", |
581 | (s,v) => { VehicleAngularFactor = v; } ), | 596 | new Vector3(1f, 1f, 1f) ), |
582 | new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", | 597 | new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", |
583 | 0.0f, | 598 | 0.0f ), |
584 | (s) => { return VehicleFriction; }, | ||
585 | (s,v) => { VehicleFriction = v; } ), | ||
586 | new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", | 599 | new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", |
587 | 0.0f, | 600 | 0.0f ), |
588 | (s) => { return VehicleRestitution; }, | ||
589 | (s,v) => { VehicleRestitution = v; } ), | ||
590 | new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", | 601 | new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", |
591 | 0.2f, | 602 | 0.2f ), |
592 | (s) => { return VehicleGroundGravityFudge; }, | ||
593 | (s,v) => { VehicleGroundGravityFudge = v; } ), | ||
594 | new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", | 603 | new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", |
595 | 60.0f, | 604 | 60.0f ), |
596 | (s) => { return VehicleAngularBankingTimescaleFudge; }, | ||
597 | (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ), | ||
598 | new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging", | 605 | new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging", |
599 | false, | 606 | false ), |
600 | (s) => { return VehicleDebuggingEnabled; }, | ||
601 | (s,v) => { VehicleDebuggingEnabled = v; } ), | ||
602 | 607 | ||
603 | new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | 608 | new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", |
604 | 0f, | 609 | 0f, |
@@ -611,7 +616,7 @@ public static class BSParam | |||
611 | new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | 616 | new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", |
612 | false, | 617 | false, |
613 | (s) => { return ShouldDisableContactPoolDynamicAllocation; }, | 618 | (s) => { return ShouldDisableContactPoolDynamicAllocation; }, |
614 | (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; | 619 | (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; |
615 | s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), | 620 | s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), |
616 | new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | 621 | new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", |
617 | false, | 622 | false, |
@@ -643,62 +648,53 @@ public static class BSParam | |||
643 | (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), | 648 | (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), |
644 | 649 | ||
645 | new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", | 650 | new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", |
646 | 7, | 651 | 7 ), |
647 | (s) => { return CSHullMaxDepthSplit; }, | ||
648 | (s,v) => { CSHullMaxDepthSplit = v; } ), | ||
649 | new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", | 652 | new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", |
650 | 2, | 653 | 2 ), |
651 | (s) => { return CSHullMaxDepthSplitForSimpleShapes; }, | ||
652 | (s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ), | ||
653 | new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", | 654 | new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", |
654 | 5f, | 655 | 5f ), |
655 | (s) => { return CSHullConcavityThresholdPercent; }, | ||
656 | (s,v) => { CSHullConcavityThresholdPercent = v; } ), | ||
657 | new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", | 656 | new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", |
658 | 5f, | 657 | 5f ), |
659 | (s) => { return CSHullVolumeConservationThresholdPercent; }, | ||
660 | (s,v) => { CSHullVolumeConservationThresholdPercent = v; } ), | ||
661 | new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", | 658 | new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", |
662 | 32, | 659 | 32 ), |
663 | (s) => { return CSHullMaxVertices; }, | ||
664 | (s,v) => { CSHullMaxVertices = v; } ), | ||
665 | new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", | 660 | new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", |
666 | 0, | 661 | 0f ), |
667 | (s) => { return CSHullMaxSkinWidth; }, | 662 | |
668 | (s,v) => { CSHullMaxSkinWidth = v; } ), | 663 | new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", |
664 | 100f ), | ||
665 | new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", | ||
666 | 2f ), | ||
667 | new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", | ||
668 | 0.1f ), | ||
669 | new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", | ||
670 | 0f ), | ||
671 | new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", | ||
672 | 100f ), | ||
673 | new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", | ||
674 | false ), | ||
675 | new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", | ||
676 | false ), | ||
677 | new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", | ||
678 | false ), | ||
679 | new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", | ||
680 | false ), | ||
669 | 681 | ||
670 | new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | 682 | new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", |
671 | (float)BSLinkset.LinksetImplementation.Compound, | 683 | (float)BSLinkset.LinksetImplementation.Compound ), |
672 | (s) => { return LinksetImplementation; }, | ||
673 | (s,v) => { LinksetImplementation = v; } ), | ||
674 | new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | 684 | new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", |
675 | false, | 685 | false ), |
676 | (s) => { return LinkConstraintUseFrameOffset; }, | ||
677 | (s,v) => { LinkConstraintUseFrameOffset = v; } ), | ||
678 | new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | 686 | new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", |
679 | true, | 687 | true ), |
680 | (s) => { return LinkConstraintEnableTransMotor; }, | ||
681 | (s,v) => { LinkConstraintEnableTransMotor = v; } ), | ||
682 | new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", | 688 | new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", |
683 | 5.0f, | 689 | 5.0f ), |
684 | (s) => { return LinkConstraintTransMotorMaxVel; }, | ||
685 | (s,v) => { LinkConstraintTransMotorMaxVel = v; } ), | ||
686 | new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", | 690 | new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", |
687 | 0.1f, | 691 | 0.1f ), |
688 | (s) => { return LinkConstraintTransMotorMaxForce; }, | ||
689 | (s,v) => { LinkConstraintTransMotorMaxForce = v; } ), | ||
690 | new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | 692 | new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", |
691 | 0.1f, | 693 | 0.1f ), |
692 | (s) => { return LinkConstraintCFM; }, | ||
693 | (s,v) => { LinkConstraintCFM = v; } ), | ||
694 | new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | 694 | new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", |
695 | 0.1f, | 695 | 0.1f ), |
696 | (s) => { return LinkConstraintERP; }, | ||
697 | (s,v) => { LinkConstraintERP = v; } ), | ||
698 | new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | 696 | new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", |
699 | 40, | 697 | 40 ), |
700 | (s) => { return LinkConstraintSolverIterations; }, | ||
701 | (s,v) => { LinkConstraintSolverIterations = v; } ), | ||
702 | 698 | ||
703 | new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", | 699 | new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", |
704 | 0, | 700 | 0, |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 6bb88c7..a4c5e08 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | |||
@@ -38,12 +38,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
38 | * Class to wrap all objects. | 38 | * Class to wrap all objects. |
39 | * The rest of BulletSim doesn't need to keep checking for avatars or prims | 39 | * The rest of BulletSim doesn't need to keep checking for avatars or prims |
40 | * unless the difference is significant. | 40 | * unless the difference is significant. |
41 | * | 41 | * |
42 | * Variables in the physicsl objects are in three forms: | 42 | * Variables in the physicsl objects are in three forms: |
43 | * VariableName: used by the simulator and performs taint operations, etc | 43 | * VariableName: used by the simulator and performs taint operations, etc |
44 | * RawVariableName: direct reference to the BulletSim storage for the variable value | 44 | * RawVariableName: direct reference to the BulletSim storage for the variable value |
45 | * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. | 45 | * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. |
46 | * The last two (and certainly the last one) should be referenced only in taint-time. | 46 | * The last one should only be referenced in taint-time. |
47 | */ | 47 | */ |
48 | 48 | ||
49 | /* | 49 | /* |
@@ -52,7 +52,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
52 | * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce | 52 | * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce |
53 | * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse | 53 | * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse |
54 | * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v | 54 | * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v |
55 | * BS.ApplyCentralForce BS.ApplyTorque | 55 | * BS.ApplyCentralForce BS.ApplyTorque |
56 | */ | 56 | */ |
57 | 57 | ||
58 | // Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc. | 58 | // Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc. |
@@ -72,19 +72,23 @@ public abstract class BSPhysObject : PhysicsActor | |||
72 | } | 72 | } |
73 | protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) | 73 | protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) |
74 | { | 74 | { |
75 | PhysicsScene = parentScene; | 75 | PhysScene = parentScene; |
76 | LocalID = localID; | 76 | LocalID = localID; |
77 | PhysObjectName = name; | 77 | PhysObjectName = name; |
78 | Name = name; // PhysicsActor also has the name of the object. Someday consolidate. | 78 | Name = name; // PhysicsActor also has the name of the object. Someday consolidate. |
79 | TypeName = typeName; | 79 | TypeName = typeName; |
80 | 80 | ||
81 | // The collection of things that push me around | ||
82 | PhysicalActors = new BSActorCollection(PhysScene); | ||
83 | |||
81 | // Initialize variables kept in base. | 84 | // Initialize variables kept in base. |
82 | GravModifier = 1.0f; | 85 | GravModifier = 1.0f; |
83 | Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); | 86 | Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); |
87 | HoverActive = false; | ||
84 | 88 | ||
85 | // We don't have any physical representation yet. | 89 | // We don't have any physical representation yet. |
86 | PhysBody = new BulletBody(localID); | 90 | PhysBody = new BulletBody(localID); |
87 | PhysShape = new BulletShape(); | 91 | PhysShape = new BSShapeNull(); |
88 | 92 | ||
89 | PrimAssetState = PrimAssetCondition.Unknown; | 93 | PrimAssetState = PrimAssetCondition.Unknown; |
90 | 94 | ||
@@ -92,7 +96,10 @@ public abstract class BSPhysObject : PhysicsActor | |||
92 | SetMaterial((int)MaterialAttributes.Material.Wood); | 96 | SetMaterial((int)MaterialAttributes.Material.Wood); |
93 | 97 | ||
94 | CollisionCollection = new CollisionEventUpdate(); | 98 | CollisionCollection = new CollisionEventUpdate(); |
95 | CollisionsLastTick = CollisionCollection; | 99 | CollisionsLastReported = CollisionCollection; |
100 | CollisionsLastTick = new CollisionEventUpdate(); | ||
101 | CollisionsLastTickStep = -1; | ||
102 | |||
96 | SubscribedEventsMs = 0; | 103 | SubscribedEventsMs = 0; |
97 | CollidingStep = 0; | 104 | CollidingStep = 0; |
98 | CollidingGroundStep = 0; | 105 | CollidingGroundStep = 0; |
@@ -101,17 +108,21 @@ public abstract class BSPhysObject : PhysicsActor | |||
101 | CollisionScore = 0; | 108 | CollisionScore = 0; |
102 | 109 | ||
103 | // All axis free. | 110 | // All axis free. |
104 | LockedAxis = LockedAxisFree; | 111 | LockedLinearAxis = LockedAxisFree; |
112 | LockedAngularAxis = LockedAxisFree; | ||
105 | } | 113 | } |
106 | 114 | ||
107 | // Tell the object to clean up. | 115 | // Tell the object to clean up. |
108 | public virtual void Destroy() | 116 | public virtual void Destroy() |
109 | { | 117 | { |
110 | UnRegisterAllPreStepActions(); | 118 | PhysicalActors.Enable(false); |
111 | UnRegisterAllPostStepActions(); | 119 | PhysScene.TaintedObject("BSPhysObject.Destroy", delegate() |
120 | { | ||
121 | PhysicalActors.Dispose(); | ||
122 | }); | ||
112 | } | 123 | } |
113 | 124 | ||
114 | public BSScene PhysicsScene { get; protected set; } | 125 | public BSScene PhysScene { get; protected set; } |
115 | // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor | 126 | // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor |
116 | public string PhysObjectName { get; protected set; } | 127 | public string PhysObjectName { get; protected set; } |
117 | public string TypeName { get; protected set; } | 128 | public string TypeName { get; protected set; } |
@@ -131,26 +142,19 @@ public abstract class BSPhysObject : PhysicsActor | |||
131 | // Reference to the physical body (btCollisionObject) of this object | 142 | // Reference to the physical body (btCollisionObject) of this object |
132 | public BulletBody PhysBody; | 143 | public BulletBody PhysBody; |
133 | // Reference to the physical shape (btCollisionShape) of this object | 144 | // Reference to the physical shape (btCollisionShape) of this object |
134 | public BulletShape PhysShape; | 145 | public BSShape PhysShape; |
135 | 146 | ||
136 | // The physical representation of the prim might require an asset fetch. | 147 | // The physical representation of the prim might require an asset fetch. |
137 | // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. | 148 | // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. |
138 | public enum PrimAssetCondition | 149 | public enum PrimAssetCondition |
139 | { | 150 | { |
140 | Unknown, Waiting, Failed, Fetched | 151 | Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched |
141 | } | 152 | } |
142 | public PrimAssetCondition PrimAssetState { get; set; } | 153 | public PrimAssetCondition PrimAssetState { get; set; } |
143 | 154 | ||
144 | // The objects base shape information. Null if not a prim type shape. | 155 | // The objects base shape information. Null if not a prim type shape. |
145 | public PrimitiveBaseShape BaseShape { get; protected set; } | 156 | public PrimitiveBaseShape BaseShape { get; protected set; } |
146 | 157 | ||
147 | // Some types of objects have preferred physical representations. | ||
148 | // Returns SHAPE_UNKNOWN if there is no preference. | ||
149 | public virtual BSPhysicsShapeType PreferredPhysicalShape | ||
150 | { | ||
151 | get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } | ||
152 | } | ||
153 | |||
154 | // When the physical properties are updated, an EntityProperty holds the update values. | 158 | // When the physical properties are updated, an EntityProperty holds the update values. |
155 | // Keep the current and last EntityProperties to enable computation of differences | 159 | // Keep the current and last EntityProperties to enable computation of differences |
156 | // between the current update and the previous values. | 160 | // between the current update and the previous values. |
@@ -180,7 +184,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
180 | Friction = matAttrib.friction; | 184 | Friction = matAttrib.friction; |
181 | Restitution = matAttrib.restitution; | 185 | Restitution = matAttrib.restitution; |
182 | Density = matAttrib.density / BSParam.DensityScaleFactor; | 186 | Density = matAttrib.density / BSParam.DensityScaleFactor; |
183 | DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); | 187 | // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); |
184 | } | 188 | } |
185 | 189 | ||
186 | // Stop all physical motion. | 190 | // Stop all physical motion. |
@@ -196,15 +200,48 @@ public abstract class BSPhysObject : PhysicsActor | |||
196 | public abstract OMV.Quaternion RawOrientation { get; set; } | 200 | public abstract OMV.Quaternion RawOrientation { get; set; } |
197 | public abstract OMV.Quaternion ForceOrientation { get; set; } | 201 | public abstract OMV.Quaternion ForceOrientation { get; set; } |
198 | 202 | ||
199 | public abstract OMV.Vector3 RawVelocity { get; set; } | 203 | public OMV.Vector3 RawVelocity { get; set; } |
200 | public abstract OMV.Vector3 ForceVelocity { get; set; } | 204 | public abstract OMV.Vector3 ForceVelocity { get; set; } |
201 | 205 | ||
206 | public OMV.Vector3 RawForce { get; set; } | ||
207 | public OMV.Vector3 RawTorque { get; set; } | ||
208 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) | ||
209 | { | ||
210 | AddAngularForce(force, pushforce, false); | ||
211 | } | ||
212 | public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime); | ||
213 | |||
202 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | 214 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } |
203 | 215 | ||
204 | public abstract float ForceBuoyancy { get; set; } | 216 | public abstract float ForceBuoyancy { get; set; } |
205 | 217 | ||
206 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } | 218 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } |
207 | 219 | ||
220 | public override bool PIDActive { set { MoveToTargetActive = value; } } | ||
221 | public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } } | ||
222 | public override float PIDTau { set { MoveToTargetTau = value; } } | ||
223 | |||
224 | public bool MoveToTargetActive { get; set; } | ||
225 | public OMV.Vector3 MoveToTargetTarget { get; set; } | ||
226 | public float MoveToTargetTau { get; set; } | ||
227 | |||
228 | // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z | ||
229 | public override bool PIDHoverActive { set { HoverActive = value; } } | ||
230 | public override float PIDHoverHeight { set { HoverHeight = value; } } | ||
231 | public override PIDHoverType PIDHoverType { set { HoverType = value; } } | ||
232 | public override float PIDHoverTau { set { HoverTau = value; } } | ||
233 | |||
234 | public bool HoverActive { get; set; } | ||
235 | public float HoverHeight { get; set; } | ||
236 | public PIDHoverType HoverType { get; set; } | ||
237 | public float HoverTau { get; set; } | ||
238 | |||
239 | // For RotLookAt | ||
240 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
241 | public override bool APIDActive { set { return; } } | ||
242 | public override float APIDStrength { set { return; } } | ||
243 | public override float APIDDamping { set { return; } } | ||
244 | |||
208 | // The current velocity forward | 245 | // The current velocity forward |
209 | public virtual float ForwardSpeed | 246 | public virtual float ForwardSpeed |
210 | { | 247 | { |
@@ -226,10 +263,58 @@ public abstract class BSPhysObject : PhysicsActor | |||
226 | 263 | ||
227 | // The user can optionally set the center of mass. The user's setting will override any | 264 | // The user can optionally set the center of mass. The user's setting will override any |
228 | // computed center-of-mass (like in linksets). | 265 | // computed center-of-mass (like in linksets). |
229 | public OMV.Vector3? UserSetCenterOfMass { get; set; } | 266 | // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass. |
267 | public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; } | ||
268 | |||
269 | public OMV.Vector3 LockedLinearAxis { get; set; } // zero means locked. one means free. | ||
270 | public OMV.Vector3 LockedAngularAxis { get; set; } // zero means locked. one means free. | ||
271 | public const float FreeAxis = 1f; | ||
272 | public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free | ||
273 | |||
274 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | ||
275 | // they need waking up when parameters are changed. | ||
276 | // Called in taint-time!! | ||
277 | public void ActivateIfPhysical(bool forceIt) | ||
278 | { | ||
279 | if (IsPhysical && PhysBody.HasPhysicalBody) | ||
280 | PhysScene.PE.Activate(PhysBody, forceIt); | ||
281 | } | ||
230 | 282 | ||
231 | public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. | 283 | // 'actors' act on the physical object to change or constrain its motion. These can range from |
232 | public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free | 284 | // hovering to complex vehicle motion. |
285 | // May be called at non-taint time as this just adds the actor to the action list and the real | ||
286 | // work is done during the simulation step. | ||
287 | // Note that, if the actor is already in the list and we are disabling same, the actor is just left | ||
288 | // in the list disabled. | ||
289 | public delegate BSActor CreateActor(); | ||
290 | public void EnableActor(bool enableActor, string actorName, CreateActor creator) | ||
291 | { | ||
292 | lock (PhysicalActors) | ||
293 | { | ||
294 | BSActor theActor; | ||
295 | if (PhysicalActors.TryGetActor(actorName, out theActor)) | ||
296 | { | ||
297 | // The actor already exists so just turn it on or off | ||
298 | DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor); | ||
299 | theActor.Enabled = enableActor; | ||
300 | } | ||
301 | else | ||
302 | { | ||
303 | // The actor does not exist. If it should, create it. | ||
304 | if (enableActor) | ||
305 | { | ||
306 | DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName); | ||
307 | theActor = creator(); | ||
308 | PhysicalActors.Add(actorName, theActor); | ||
309 | theActor.Enabled = true; | ||
310 | } | ||
311 | else | ||
312 | { | ||
313 | DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName); | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | } | ||
233 | 318 | ||
234 | #region Collisions | 319 | #region Collisions |
235 | 320 | ||
@@ -247,45 +332,50 @@ public abstract class BSPhysObject : PhysicsActor | |||
247 | protected CollisionFlags CurrentCollisionFlags { get; set; } | 332 | protected CollisionFlags CurrentCollisionFlags { get; set; } |
248 | // On a collision, check the collider and remember if the last collider was moving | 333 | // On a collision, check the collider and remember if the last collider was moving |
249 | // Used to modify the standing of avatars (avatars on stationary things stand still) | 334 | // Used to modify the standing of avatars (avatars on stationary things stand still) |
250 | protected bool ColliderIsMoving; | 335 | public bool ColliderIsMoving; |
336 | // Used by BSCharacter to manage standing (and not slipping) | ||
337 | public bool IsStationary; | ||
251 | 338 | ||
252 | // Count of collisions for this object | 339 | // Count of collisions for this object |
253 | protected long CollisionAccumulation { get; set; } | 340 | protected long CollisionAccumulation { get; set; } |
254 | 341 | ||
255 | public override bool IsColliding { | 342 | public override bool IsColliding { |
256 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | 343 | get { return (CollidingStep == PhysScene.SimulationStep); } |
257 | set { | 344 | set { |
258 | if (value) | 345 | if (value) |
259 | CollidingStep = PhysicsScene.SimulationStep; | 346 | CollidingStep = PhysScene.SimulationStep; |
260 | else | 347 | else |
261 | CollidingStep = 0; | 348 | CollidingStep = 0; |
262 | } | 349 | } |
263 | } | 350 | } |
264 | public override bool CollidingGround { | 351 | public override bool CollidingGround { |
265 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | 352 | get { return (CollidingGroundStep == PhysScene.SimulationStep); } |
266 | set | 353 | set |
267 | { | 354 | { |
268 | if (value) | 355 | if (value) |
269 | CollidingGroundStep = PhysicsScene.SimulationStep; | 356 | CollidingGroundStep = PhysScene.SimulationStep; |
270 | else | 357 | else |
271 | CollidingGroundStep = 0; | 358 | CollidingGroundStep = 0; |
272 | } | 359 | } |
273 | } | 360 | } |
274 | public override bool CollidingObj { | 361 | public override bool CollidingObj { |
275 | get { return (CollidingObjectStep == PhysicsScene.SimulationStep); } | 362 | get { return (CollidingObjectStep == PhysScene.SimulationStep); } |
276 | set { | 363 | set { |
277 | if (value) | 364 | if (value) |
278 | CollidingObjectStep = PhysicsScene.SimulationStep; | 365 | CollidingObjectStep = PhysScene.SimulationStep; |
279 | else | 366 | else |
280 | CollidingObjectStep = 0; | 367 | CollidingObjectStep = 0; |
281 | } | 368 | } |
282 | } | 369 | } |
283 | 370 | ||
284 | // The collisions that have been collected this tick | 371 | // The collisions that have been collected for the next collision reporting (throttled by subscription) |
285 | protected CollisionEventUpdate CollisionCollection; | 372 | protected CollisionEventUpdate CollisionCollection; |
286 | // Remember collisions from last tick for fancy collision based actions | 373 | // This is the collision collection last reported to the Simulator. |
374 | public CollisionEventUpdate CollisionsLastReported; | ||
375 | // Remember the collisions recorded in the last tick for fancy collision checking | ||
287 | // (like a BSCharacter walking up stairs). | 376 | // (like a BSCharacter walking up stairs). |
288 | protected CollisionEventUpdate CollisionsLastTick; | 377 | public CollisionEventUpdate CollisionsLastTick; |
378 | private long CollisionsLastTickStep = -1; | ||
289 | 379 | ||
290 | // The simulation step is telling this object about a collision. | 380 | // The simulation step is telling this object about a collision. |
291 | // Return 'true' if a collision was processed and should be sent up. | 381 | // Return 'true' if a collision was processed and should be sent up. |
@@ -297,14 +387,14 @@ public abstract class BSPhysObject : PhysicsActor | |||
297 | bool ret = false; | 387 | bool ret = false; |
298 | 388 | ||
299 | // The following lines make IsColliding(), CollidingGround() and CollidingObj work | 389 | // The following lines make IsColliding(), CollidingGround() and CollidingObj work |
300 | CollidingStep = PhysicsScene.SimulationStep; | 390 | CollidingStep = PhysScene.SimulationStep; |
301 | if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) | 391 | if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID) |
302 | { | 392 | { |
303 | CollidingGroundStep = PhysicsScene.SimulationStep; | 393 | CollidingGroundStep = PhysScene.SimulationStep; |
304 | } | 394 | } |
305 | else | 395 | else |
306 | { | 396 | { |
307 | CollidingObjectStep = PhysicsScene.SimulationStep; | 397 | CollidingObjectStep = PhysScene.SimulationStep; |
308 | } | 398 | } |
309 | 399 | ||
310 | CollisionAccumulation++; | 400 | CollisionAccumulation++; |
@@ -312,6 +402,15 @@ public abstract class BSPhysObject : PhysicsActor | |||
312 | // For movement tests, remember if we are colliding with an object that is moving. | 402 | // For movement tests, remember if we are colliding with an object that is moving. |
313 | ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; | 403 | ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; |
314 | 404 | ||
405 | // Make a collection of the collisions that happened the last simulation tick. | ||
406 | // This is different than the collection created for sending up to the simulator as it is cleared every tick. | ||
407 | if (CollisionsLastTickStep != PhysScene.SimulationStep) | ||
408 | { | ||
409 | CollisionsLastTick = new CollisionEventUpdate(); | ||
410 | CollisionsLastTickStep = PhysScene.SimulationStep; | ||
411 | } | ||
412 | CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
413 | |||
315 | // If someone has subscribed for collision events log the collision so it will be reported up | 414 | // If someone has subscribed for collision events log the collision so it will be reported up |
316 | if (SubscribedEvents()) { | 415 | if (SubscribedEvents()) { |
317 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | 416 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); |
@@ -332,12 +431,12 @@ public abstract class BSPhysObject : PhysicsActor | |||
332 | bool ret = true; | 431 | bool ret = true; |
333 | 432 | ||
334 | // If the 'no collision' call, force it to happen right now so quick collision_end | 433 | // If the 'no collision' call, force it to happen right now so quick collision_end |
335 | bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0); | 434 | bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0); |
336 | 435 | ||
337 | // throttle the collisions to the number of milliseconds specified in the subscription | 436 | // throttle the collisions to the number of milliseconds specified in the subscription |
338 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) | 437 | if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime)) |
339 | { | 438 | { |
340 | NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; | 439 | NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs; |
341 | 440 | ||
342 | // We are called if we previously had collisions. If there are no collisions | 441 | // We are called if we previously had collisions. If there are no collisions |
343 | // this time, send up one last empty event so OpenSim can sense collision end. | 442 | // this time, send up one last empty event so OpenSim can sense collision end. |
@@ -351,11 +450,11 @@ public abstract class BSPhysObject : PhysicsActor | |||
351 | base.SendCollisionUpdate(CollisionCollection); | 450 | base.SendCollisionUpdate(CollisionCollection); |
352 | 451 | ||
353 | // Remember the collisions from this tick for some collision specific processing. | 452 | // Remember the collisions from this tick for some collision specific processing. |
354 | CollisionsLastTick = CollisionCollection; | 453 | CollisionsLastReported = CollisionCollection; |
355 | 454 | ||
356 | // The CollisionCollection instance is passed around in the simulator. | 455 | // The CollisionCollection instance is passed around in the simulator. |
357 | // Make sure we don't have a handle to that one and that a new one is used for next time. | 456 | // Make sure we don't have a handle to that one and that a new one is used for next time. |
358 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, | 457 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, |
359 | // a race condition is created for the other users of this instance. | 458 | // a race condition is created for the other users of this instance. |
360 | CollisionCollection = new CollisionEventUpdate(); | 459 | CollisionCollection = new CollisionEventUpdate(); |
361 | } | 460 | } |
@@ -372,10 +471,10 @@ public abstract class BSPhysObject : PhysicsActor | |||
372 | // make sure first collision happens | 471 | // make sure first collision happens |
373 | NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); | 472 | NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); |
374 | 473 | ||
375 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() | 474 | PhysScene.TaintedObject(TypeName+".SubscribeEvents", delegate() |
376 | { | 475 | { |
377 | if (PhysBody.HasPhysicalBody) | 476 | if (PhysBody.HasPhysicalBody) |
378 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 477 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
379 | }); | 478 | }); |
380 | } | 479 | } |
381 | else | 480 | else |
@@ -387,11 +486,11 @@ public abstract class BSPhysObject : PhysicsActor | |||
387 | public override void UnSubscribeEvents() { | 486 | public override void UnSubscribeEvents() { |
388 | // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); | 487 | // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); |
389 | SubscribedEventsMs = 0; | 488 | SubscribedEventsMs = 0; |
390 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() | 489 | PhysScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() |
391 | { | 490 | { |
392 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. | 491 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. |
393 | if (PhysBody.HasPhysicalBody) | 492 | if (PhysBody.HasPhysicalBody) |
394 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 493 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
395 | }); | 494 | }); |
396 | } | 495 | } |
397 | // Return 'true' if the simulator wants collision events | 496 | // Return 'true' if the simulator wants collision events |
@@ -405,7 +504,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
405 | { | 504 | { |
406 | // Scale the collision count by the time since the last collision. | 505 | // Scale the collision count by the time since the last collision. |
407 | // The "+1" prevents dividing by zero. | 506 | // The "+1" prevents dividing by zero. |
408 | long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1; | 507 | long timeAgo = PhysScene.SimulationStep - CollidingStep + 1; |
409 | CollisionScore = CollisionAccumulation / timeAgo; | 508 | CollisionScore = CollisionAccumulation / timeAgo; |
410 | } | 509 | } |
411 | public override float CollisionScore { get; set; } | 510 | public override float CollisionScore { get; set; } |
@@ -413,103 +512,8 @@ public abstract class BSPhysObject : PhysicsActor | |||
413 | #endregion // Collisions | 512 | #endregion // Collisions |
414 | 513 | ||
415 | #region Per Simulation Step actions | 514 | #region Per Simulation Step actions |
416 | // There are some actions that must be performed for a physical object before each simulation step. | ||
417 | // These actions are optional so, rather than scanning all the physical objects and asking them | ||
418 | // if they have anything to do, a physical object registers for an event call before the step is performed. | ||
419 | // This bookkeeping makes it easy to add, remove and clean up after all these registrations. | ||
420 | private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>(); | ||
421 | private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>(); | ||
422 | protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) | ||
423 | { | ||
424 | string identifier = op + "-" + id.ToString(); | ||
425 | 515 | ||
426 | lock (RegisteredPrestepActions) | 516 | public BSActorCollection PhysicalActors; |
427 | { | ||
428 | // Clean out any existing action | ||
429 | UnRegisterPreStepAction(op, id); | ||
430 | RegisteredPrestepActions[identifier] = actn; | ||
431 | PhysicsScene.BeforeStep += actn; | ||
432 | } | ||
433 | DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); | ||
434 | } | ||
435 | |||
436 | // Unregister a pre step action. Safe to call if the action has not been registered. | ||
437 | // Returns 'true' if an action was actually removed | ||
438 | protected bool UnRegisterPreStepAction(string op, uint id) | ||
439 | { | ||
440 | string identifier = op + "-" + id.ToString(); | ||
441 | bool removed = false; | ||
442 | lock (RegisteredPrestepActions) | ||
443 | { | ||
444 | if (RegisteredPrestepActions.ContainsKey(identifier)) | ||
445 | { | ||
446 | PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier]; | ||
447 | RegisteredPrestepActions.Remove(identifier); | ||
448 | removed = true; | ||
449 | } | ||
450 | } | ||
451 | DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||
452 | return removed; | ||
453 | } | ||
454 | |||
455 | protected void UnRegisterAllPreStepActions() | ||
456 | { | ||
457 | lock (RegisteredPrestepActions) | ||
458 | { | ||
459 | foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions) | ||
460 | { | ||
461 | PhysicsScene.BeforeStep -= kvp.Value; | ||
462 | } | ||
463 | RegisteredPrestepActions.Clear(); | ||
464 | } | ||
465 | DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); | ||
466 | } | ||
467 | |||
468 | protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn) | ||
469 | { | ||
470 | string identifier = op + "-" + id.ToString(); | ||
471 | |||
472 | lock (RegisteredPoststepActions) | ||
473 | { | ||
474 | // Clean out any existing action | ||
475 | UnRegisterPostStepAction(op, id); | ||
476 | RegisteredPoststepActions[identifier] = actn; | ||
477 | PhysicsScene.AfterStep += actn; | ||
478 | } | ||
479 | DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier); | ||
480 | } | ||
481 | |||
482 | // Unregister a pre step action. Safe to call if the action has not been registered. | ||
483 | // Returns 'true' if an action was actually removed. | ||
484 | protected bool UnRegisterPostStepAction(string op, uint id) | ||
485 | { | ||
486 | string identifier = op + "-" + id.ToString(); | ||
487 | bool removed = false; | ||
488 | lock (RegisteredPoststepActions) | ||
489 | { | ||
490 | if (RegisteredPoststepActions.ContainsKey(identifier)) | ||
491 | { | ||
492 | PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier]; | ||
493 | RegisteredPoststepActions.Remove(identifier); | ||
494 | removed = true; | ||
495 | } | ||
496 | } | ||
497 | DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||
498 | return removed; | ||
499 | } | ||
500 | |||
501 | protected void UnRegisterAllPostStepActions() | ||
502 | { | ||
503 | lock (RegisteredPoststepActions) | ||
504 | { | ||
505 | foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions) | ||
506 | { | ||
507 | PhysicsScene.AfterStep -= kvp.Value; | ||
508 | } | ||
509 | RegisteredPoststepActions.Clear(); | ||
510 | } | ||
511 | DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID); | ||
512 | } | ||
513 | 517 | ||
514 | // When an update to the physical properties happens, this event is fired to let | 518 | // When an update to the physical properties happens, this event is fired to let |
515 | // different actors to modify the update before it is passed around | 519 | // different actors to modify the update before it is passed around |
@@ -522,53 +526,13 @@ public abstract class BSPhysObject : PhysicsActor | |||
522 | actions(ref entprop); | 526 | actions(ref entprop); |
523 | } | 527 | } |
524 | 528 | ||
525 | private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>(); | ||
526 | public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn) | ||
527 | { | ||
528 | lock (RegisteredPreUpdatePropertyActions) | ||
529 | { | ||
530 | // Clean out any existing action | ||
531 | UnRegisterPreUpdatePropertyAction(identifier); | ||
532 | RegisteredPreUpdatePropertyActions[identifier] = actn; | ||
533 | OnPreUpdateProperty += actn; | ||
534 | } | ||
535 | DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier); | ||
536 | } | ||
537 | public bool UnRegisterPreUpdatePropertyAction(string identifier) | ||
538 | { | ||
539 | bool removed = false; | ||
540 | lock (RegisteredPreUpdatePropertyActions) | ||
541 | { | ||
542 | if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier)) | ||
543 | { | ||
544 | OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier]; | ||
545 | RegisteredPreUpdatePropertyActions.Remove(identifier); | ||
546 | removed = true; | ||
547 | } | ||
548 | } | ||
549 | DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed); | ||
550 | return removed; | ||
551 | } | ||
552 | public void UnRegisterAllPreUpdatePropertyActions() | ||
553 | { | ||
554 | lock (RegisteredPreUpdatePropertyActions) | ||
555 | { | ||
556 | foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions) | ||
557 | { | ||
558 | OnPreUpdateProperty -= kvp.Value; | ||
559 | } | ||
560 | RegisteredPreUpdatePropertyActions.Clear(); | ||
561 | } | ||
562 | DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID); | ||
563 | } | ||
564 | |||
565 | #endregion // Per Simulation Step actions | 529 | #endregion // Per Simulation Step actions |
566 | 530 | ||
567 | // High performance detailed logging routine used by the physical objects. | 531 | // High performance detailed logging routine used by the physical objects. |
568 | protected void DetailLog(string msg, params Object[] args) | 532 | protected void DetailLog(string msg, params Object[] args) |
569 | { | 533 | { |
570 | if (PhysicsScene.PhysicsLogging.Enabled) | 534 | if (PhysScene.PhysicsLogging.Enabled) |
571 | PhysicsScene.DetailLog(msg, args); | 535 | PhysScene.DetailLog(msg, args); |
572 | } | 536 | } |
573 | 537 | ||
574 | } | 538 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 6a5461a..95bdc7b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -55,9 +55,6 @@ public class BSPrim : BSPhysObject | |||
55 | private OMV.Vector3 _position; | 55 | private OMV.Vector3 _position; |
56 | 56 | ||
57 | private float _mass; // the mass of this object | 57 | private float _mass; // the mass of this object |
58 | private OMV.Vector3 _force; | ||
59 | private OMV.Vector3 _velocity; | ||
60 | private OMV.Vector3 _torque; | ||
61 | private OMV.Vector3 _acceleration; | 58 | private OMV.Vector3 _acceleration; |
62 | private OMV.Quaternion _orientation; | 59 | private OMV.Quaternion _orientation; |
63 | private int _physicsActorType; | 60 | private int _physicsActorType; |
@@ -72,16 +69,19 @@ public class BSPrim : BSPhysObject | |||
72 | 69 | ||
73 | private int CrossingFailures { get; set; } | 70 | private int CrossingFailures { get; set; } |
74 | 71 | ||
75 | public BSDynamics VehicleController { get; private set; } | 72 | // Keep a handle to the vehicle actor so it is easy to set parameters on same. |
73 | public BSDynamics VehicleActor; | ||
74 | public const string VehicleActorName = "BasicVehicle"; | ||
76 | 75 | ||
77 | private BSVMotor _targetMotor; | 76 | // Parameters for the hover actor |
78 | private OMV.Vector3 _PIDTarget; | 77 | public const string HoverActorName = "HoverActor"; |
79 | private float _PIDTau; | 78 | // Parameters for the axis lock actor |
80 | 79 | public const String LockedAxisActorName = "BSPrim.LockedAxis"; | |
81 | private BSFMotor _hoverMotor; | 80 | // Parameters for the move to target actor |
82 | private float _PIDHoverHeight; | 81 | public const string MoveToTargetActorName = "MoveToTargetActor"; |
83 | private PIDHoverType _PIDHoverType; | 82 | // Parameters for the setForce and setTorque actors |
84 | private float _PIDHoverTau; | 83 | public const string SetForceActorName = "SetForceActor"; |
84 | public const string SetTorqueActorName = "SetTorqueActor"; | ||
85 | 85 | ||
86 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | 86 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, |
87 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 87 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
@@ -94,26 +94,28 @@ public class BSPrim : BSPhysObject | |||
94 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). | 94 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). |
95 | _orientation = rotation; | 95 | _orientation = rotation; |
96 | _buoyancy = 0f; | 96 | _buoyancy = 0f; |
97 | _velocity = OMV.Vector3.Zero; | 97 | RawVelocity = OMV.Vector3.Zero; |
98 | _rotationalVelocity = OMV.Vector3.Zero; | 98 | _rotationalVelocity = OMV.Vector3.Zero; |
99 | BaseShape = pbs; | 99 | BaseShape = pbs; |
100 | _isPhysical = pisPhysical; | 100 | _isPhysical = pisPhysical; |
101 | _isVolumeDetect = false; | 101 | _isVolumeDetect = false; |
102 | 102 | ||
103 | VehicleController = new BSDynamics(PhysicsScene, this); // add vehicleness | 103 | // We keep a handle to the vehicle actor so we can set vehicle parameters later. |
104 | VehicleActor = new BSDynamics(PhysScene, this, VehicleActorName); | ||
105 | PhysicalActors.Add(VehicleActorName, VehicleActor); | ||
104 | 106 | ||
105 | _mass = CalculateMass(); | 107 | _mass = CalculateMass(); |
106 | 108 | ||
107 | DetailLog("{0},BSPrim.constructor,call", LocalID); | 109 | // DetailLog("{0},BSPrim.constructor,call", LocalID); |
108 | // do the actual object creation at taint time | 110 | // do the actual object creation at taint time |
109 | PhysicsScene.TaintedObject("BSPrim.create", delegate() | 111 | PhysScene.TaintedObject("BSPrim.create", delegate() |
110 | { | 112 | { |
111 | // Make sure the object is being created with some sanity. | 113 | // Make sure the object is being created with some sanity. |
112 | ExtremeSanityCheck(true /* inTaintTime */); | 114 | ExtremeSanityCheck(true /* inTaintTime */); |
113 | 115 | ||
114 | CreateGeomAndObject(true); | 116 | CreateGeomAndObject(true); |
115 | 117 | ||
116 | CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); | 118 | CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody); |
117 | }); | 119 | }); |
118 | } | 120 | } |
119 | 121 | ||
@@ -126,14 +128,14 @@ public class BSPrim : BSPhysObject | |||
126 | // Undo any vehicle properties | 128 | // Undo any vehicle properties |
127 | this.VehicleType = (int)Vehicle.TYPE_NONE; | 129 | this.VehicleType = (int)Vehicle.TYPE_NONE; |
128 | 130 | ||
129 | PhysicsScene.TaintedObject("BSPrim.destroy", delegate() | 131 | PhysScene.TaintedObject("BSPrim.Destroy", delegate() |
130 | { | 132 | { |
131 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 133 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
132 | // If there are physical body and shape, release my use of same. | 134 | // If there are physical body and shape, release my use of same. |
133 | PhysicsScene.Shapes.DereferenceBody(PhysBody, null); | 135 | PhysScene.Shapes.DereferenceBody(PhysBody, null); |
134 | PhysBody.Clear(); | 136 | PhysBody.Clear(); |
135 | PhysicsScene.Shapes.DereferenceShape(PhysShape, null); | 137 | PhysShape.Dereference(PhysScene); |
136 | PhysShape.Clear(); | 138 | PhysShape = new BSShapeNull(); |
137 | }); | 139 | }); |
138 | } | 140 | } |
139 | 141 | ||
@@ -159,25 +161,13 @@ public class BSPrim : BSPhysObject | |||
159 | ForceBodyShapeRebuild(false); | 161 | ForceBodyShapeRebuild(false); |
160 | } | 162 | } |
161 | } | 163 | } |
162 | // 'unknown' says to choose the best type | ||
163 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
164 | { get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } } | ||
165 | |||
166 | public override bool ForceBodyShapeRebuild(bool inTaintTime) | 164 | public override bool ForceBodyShapeRebuild(bool inTaintTime) |
167 | { | 165 | { |
168 | if (inTaintTime) | 166 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() |
169 | { | 167 | { |
170 | _mass = CalculateMass(); // changing the shape changes the mass | 168 | _mass = CalculateMass(); // changing the shape changes the mass |
171 | CreateGeomAndObject(true); | 169 | CreateGeomAndObject(true); |
172 | } | 170 | }); |
173 | else | ||
174 | { | ||
175 | PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate() | ||
176 | { | ||
177 | _mass = CalculateMass(); // changing the shape changes the mass | ||
178 | CreateGeomAndObject(true); | ||
179 | }); | ||
180 | } | ||
181 | return true; | 171 | return true; |
182 | } | 172 | } |
183 | public override bool Grabbed { | 173 | public override bool Grabbed { |
@@ -190,7 +180,7 @@ public class BSPrim : BSPhysObject | |||
190 | if (value != _isSelected) | 180 | if (value != _isSelected) |
191 | { | 181 | { |
192 | _isSelected = value; | 182 | _isSelected = value; |
193 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() | 183 | PhysScene.TaintedObject("BSPrim.setSelected", delegate() |
194 | { | 184 | { |
195 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | 185 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); |
196 | SetObjectDynamic(false); | 186 | SetObjectDynamic(false); |
@@ -231,124 +221,56 @@ public class BSPrim : BSPhysObject | |||
231 | // Called at taint time! | 221 | // Called at taint time! |
232 | public override void ZeroMotion(bool inTaintTime) | 222 | public override void ZeroMotion(bool inTaintTime) |
233 | { | 223 | { |
234 | _velocity = OMV.Vector3.Zero; | 224 | RawVelocity = OMV.Vector3.Zero; |
235 | _acceleration = OMV.Vector3.Zero; | 225 | _acceleration = OMV.Vector3.Zero; |
236 | _rotationalVelocity = OMV.Vector3.Zero; | 226 | _rotationalVelocity = OMV.Vector3.Zero; |
237 | 227 | ||
238 | // Zero some other properties in the physics engine | 228 | // Zero some other properties in the physics engine |
239 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 229 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
240 | { | 230 | { |
241 | if (PhysBody.HasPhysicalBody) | 231 | if (PhysBody.HasPhysicalBody) |
242 | PhysicsScene.PE.ClearAllForces(PhysBody); | 232 | PhysScene.PE.ClearAllForces(PhysBody); |
243 | }); | 233 | }); |
244 | } | 234 | } |
245 | public override void ZeroAngularMotion(bool inTaintTime) | 235 | public override void ZeroAngularMotion(bool inTaintTime) |
246 | { | 236 | { |
247 | _rotationalVelocity = OMV.Vector3.Zero; | 237 | _rotationalVelocity = OMV.Vector3.Zero; |
248 | // Zero some other properties in the physics engine | 238 | // Zero some other properties in the physics engine |
249 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 239 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
250 | { | 240 | { |
251 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); | 241 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); |
252 | if (PhysBody.HasPhysicalBody) | 242 | if (PhysBody.HasPhysicalBody) |
253 | { | 243 | { |
254 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | 244 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); |
255 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | 245 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); |
256 | } | 246 | } |
257 | }); | 247 | }); |
258 | } | 248 | } |
259 | 249 | ||
260 | bool TryExperimentalLockAxisCode = false; | ||
261 | BSConstraint LockAxisConstraint = null; | ||
262 | public override void LockAngularMotion(OMV.Vector3 axis) | 250 | public override void LockAngularMotion(OMV.Vector3 axis) |
263 | { | 251 | { |
264 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); | 252 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); |
265 | 253 | ||
266 | // "1" means free, "0" means locked | 254 | // "1" means free, "0" means locked |
267 | OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f); | 255 | OMV.Vector3 locking = LockedAxisFree; |
268 | if (axis.X != 1) locking.X = 0f; | 256 | if (axis.X != 1) locking.X = 0f; |
269 | if (axis.Y != 1) locking.Y = 0f; | 257 | if (axis.Y != 1) locking.Y = 0f; |
270 | if (axis.Z != 1) locking.Z = 0f; | 258 | if (axis.Z != 1) locking.Z = 0f; |
271 | LockedAxis = locking; | 259 | LockedAngularAxis = locking; |
272 | 260 | ||
273 | if (TryExperimentalLockAxisCode && LockedAxis != LockedAxisFree) | 261 | EnableActor(LockedAngularAxis != LockedAxisFree, LockedAxisActorName, delegate() |
274 | { | 262 | { |
275 | // Lock that axis by creating a 6DOF constraint that has one end in the world and | 263 | return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); |
276 | // the other in the object. | 264 | }); |
277 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 | ||
278 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 | ||
279 | |||
280 | PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() | ||
281 | { | ||
282 | CleanUpLockAxisPhysicals(true /* inTaintTime */); | ||
283 | |||
284 | BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(PhysicsScene.World, PhysBody, | ||
285 | OMV.Vector3.Zero, OMV.Quaternion.Inverse(RawOrientation), | ||
286 | true /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); | ||
287 | LockAxisConstraint = axisConstrainer; | ||
288 | PhysicsScene.Constraints.AddConstraint(LockAxisConstraint); | ||
289 | |||
290 | // The constraint is tied to the world and oriented to the prim. | ||
291 | |||
292 | // Free to move linearly | ||
293 | OMV.Vector3 linearLow = OMV.Vector3.Zero; | ||
294 | OMV.Vector3 linearHigh = PhysicsScene.TerrainManager.DefaultRegionSize; | ||
295 | axisConstrainer.SetLinearLimits(linearLow, linearHigh); | ||
296 | |||
297 | // Angular with some axis locked | ||
298 | float f2PI = (float)Math.PI * 2f; | ||
299 | OMV.Vector3 angularLow = new OMV.Vector3(-f2PI, -f2PI, -f2PI); | ||
300 | OMV.Vector3 angularHigh = new OMV.Vector3(f2PI, f2PI, f2PI); | ||
301 | if (LockedAxis.X != 1f) | ||
302 | { | ||
303 | angularLow.X = 0f; | ||
304 | angularHigh.X = 0f; | ||
305 | } | ||
306 | if (LockedAxis.Y != 1f) | ||
307 | { | ||
308 | angularLow.Y = 0f; | ||
309 | angularHigh.Y = 0f; | ||
310 | } | ||
311 | if (LockedAxis.Z != 1f) | ||
312 | { | ||
313 | angularLow.Z = 0f; | ||
314 | angularHigh.Z = 0f; | ||
315 | } | ||
316 | axisConstrainer.SetAngularLimits(angularLow, angularHigh); | ||
317 | |||
318 | DetailLog("{0},BSPrim.LockAngularMotion,create,linLow={1},linHi={2},angLow={3},angHi={4}", | ||
319 | LocalID, linearLow, linearHigh, angularLow, angularHigh); | ||
320 | |||
321 | // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. | ||
322 | axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); | ||
323 | 265 | ||
324 | axisConstrainer.RecomputeConstraintVariables(RawMass); | 266 | // Update parameters so the new actor's Refresh() action is called at the right time. |
325 | }); | 267 | PhysScene.TaintedObject("BSPrim.LockAngularMotion", delegate() |
326 | } | ||
327 | else | ||
328 | { | 268 | { |
329 | // Everything seems unlocked | 269 | UpdatePhysicalParameters(); |
330 | CleanUpLockAxisPhysicals(false /* inTaintTime */); | 270 | }); |
331 | } | ||
332 | 271 | ||
333 | return; | 272 | return; |
334 | } | 273 | } |
335 | // Get rid of any constraint built for LockAxis | ||
336 | // Most often the constraint is removed when the constraint collection is cleaned for this prim. | ||
337 | private void CleanUpLockAxisPhysicals(bool inTaintTime) | ||
338 | { | ||
339 | if (LockAxisConstraint != null) | ||
340 | { | ||
341 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CleanUpLockAxisPhysicals", delegate() | ||
342 | { | ||
343 | if (LockAxisConstraint != null) | ||
344 | { | ||
345 | PhysicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint); | ||
346 | LockAxisConstraint = null; | ||
347 | DetailLog("{0},BSPrim.CleanUpLockAxisPhysicals,destroyingConstraint", LocalID); | ||
348 | } | ||
349 | }); | ||
350 | } | ||
351 | } | ||
352 | 274 | ||
353 | public override OMV.Vector3 RawPosition | 275 | public override OMV.Vector3 RawPosition |
354 | { | 276 | { |
@@ -372,7 +294,7 @@ public class BSPrim : BSPhysObject | |||
372 | _position = value; | 294 | _position = value; |
373 | PositionSanityCheck(false); | 295 | PositionSanityCheck(false); |
374 | 296 | ||
375 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | 297 | PhysScene.TaintedObject("BSPrim.setPosition", delegate() |
376 | { | 298 | { |
377 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 299 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
378 | ForcePosition = _position; | 300 | ForcePosition = _position; |
@@ -382,14 +304,14 @@ public class BSPrim : BSPhysObject | |||
382 | 304 | ||
383 | public override OMV.Vector3 ForcePosition { | 305 | public override OMV.Vector3 ForcePosition { |
384 | get { | 306 | get { |
385 | _position = PhysicsScene.PE.GetPosition(PhysBody); | 307 | _position = PhysScene.PE.GetPosition(PhysBody); |
386 | return _position; | 308 | return _position; |
387 | } | 309 | } |
388 | set { | 310 | set { |
389 | _position = value; | 311 | _position = value; |
390 | if (PhysBody.HasPhysicalBody) | 312 | if (PhysBody.HasPhysicalBody) |
391 | { | 313 | { |
392 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 314 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); |
393 | ActivateIfPhysical(false); | 315 | ActivateIfPhysical(false); |
394 | } | 316 | } |
395 | } | 317 | } |
@@ -406,7 +328,7 @@ public class BSPrim : BSPhysObject | |||
406 | if (!IsPhysicallyActive) | 328 | if (!IsPhysicallyActive) |
407 | return ret; | 329 | return ret; |
408 | 330 | ||
409 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) | 331 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) |
410 | { | 332 | { |
411 | // The physical object is out of the known/simulated area. | 333 | // The physical object is out of the known/simulated area. |
412 | // Upper levels of code will handle the transition to other areas so, for | 334 | // Upper levels of code will handle the transition to other areas so, for |
@@ -414,7 +336,7 @@ public class BSPrim : BSPhysObject | |||
414 | return ret; | 336 | return ret; |
415 | } | 337 | } |
416 | 338 | ||
417 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | 339 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); |
418 | OMV.Vector3 upForce = OMV.Vector3.Zero; | 340 | OMV.Vector3 upForce = OMV.Vector3.Zero; |
419 | float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); | 341 | float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); |
420 | if ((RawPosition.Z + approxSize / 2f) < terrainHeight) | 342 | if ((RawPosition.Z + approxSize / 2f) < terrainHeight) |
@@ -435,7 +357,7 @@ public class BSPrim : BSPhysObject | |||
435 | 357 | ||
436 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 358 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
437 | { | 359 | { |
438 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | 360 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
439 | // TODO: a floating motor so object will bob in the water | 361 | // TODO: a floating motor so object will bob in the water |
440 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) | 362 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) |
441 | { | 363 | { |
@@ -443,7 +365,7 @@ public class BSPrim : BSPhysObject | |||
443 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; | 365 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; |
444 | 366 | ||
445 | // Apply upforce and overcome gravity. | 367 | // Apply upforce and overcome gravity. |
446 | OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; | 368 | OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity; |
447 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); | 369 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); |
448 | AddForce(correctionForce, false, inTaintTime); | 370 | AddForce(correctionForce, false, inTaintTime); |
449 | ret = true; | 371 | ret = true; |
@@ -471,9 +393,9 @@ public class BSPrim : BSPhysObject | |||
471 | ZeroMotion(inTaintTime); | 393 | ZeroMotion(inTaintTime); |
472 | ret = true; | 394 | ret = true; |
473 | } | 395 | } |
474 | if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity) | 396 | if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity) |
475 | { | 397 | { |
476 | _velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity); | 398 | RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity); |
477 | ret = true; | 399 | ret = true; |
478 | } | 400 | } |
479 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) | 401 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) |
@@ -498,7 +420,7 @@ public class BSPrim : BSPhysObject | |||
498 | get { return _mass; } | 420 | get { return _mass; } |
499 | } | 421 | } |
500 | // used when we only want this prim's mass and not the linkset thing | 422 | // used when we only want this prim's mass and not the linkset thing |
501 | public override float RawMass { | 423 | public override float RawMass { |
502 | get { return _mass; } | 424 | get { return _mass; } |
503 | } | 425 | } |
504 | // Set the physical mass to the passed mass. | 426 | // Set the physical mass to the passed mass. |
@@ -509,10 +431,10 @@ public class BSPrim : BSPhysObject | |||
509 | { | 431 | { |
510 | if (IsStatic) | 432 | if (IsStatic) |
511 | { | 433 | { |
512 | PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); | 434 | PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity); |
513 | Inertia = OMV.Vector3.Zero; | 435 | Inertia = OMV.Vector3.Zero; |
514 | PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); | 436 | PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia); |
515 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); | 437 | PhysScene.PE.UpdateInertiaTensor(PhysBody); |
516 | } | 438 | } |
517 | else | 439 | else |
518 | { | 440 | { |
@@ -521,16 +443,16 @@ public class BSPrim : BSPhysObject | |||
521 | // Changing interesting properties doesn't change proxy and collision cache | 443 | // Changing interesting properties doesn't change proxy and collision cache |
522 | // information. The Bullet solution is to re-add the object to the world | 444 | // information. The Bullet solution is to re-add the object to the world |
523 | // after parameters are changed. | 445 | // after parameters are changed. |
524 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 446 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
525 | } | 447 | } |
526 | 448 | ||
527 | // The computation of mass props requires gravity to be set on the object. | 449 | // The computation of mass props requires gravity to be set on the object. |
528 | Gravity = ComputeGravity(Buoyancy); | 450 | Gravity = ComputeGravity(Buoyancy); |
529 | PhysicsScene.PE.SetGravity(PhysBody, Gravity); | 451 | PhysScene.PE.SetGravity(PhysBody, Gravity); |
530 | 452 | ||
531 | Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | 453 | Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); |
532 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); | 454 | PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); |
533 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); | 455 | PhysScene.PE.UpdateInertiaTensor(PhysBody); |
534 | 456 | ||
535 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", | 457 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", |
536 | LocalID, physMass, Inertia, Gravity, inWorld); | 458 | LocalID, physMass, Inertia, Gravity, inWorld); |
@@ -546,7 +468,7 @@ public class BSPrim : BSPhysObject | |||
546 | // Return what gravity should be set to this very moment | 468 | // Return what gravity should be set to this very moment |
547 | public OMV.Vector3 ComputeGravity(float buoyancy) | 469 | public OMV.Vector3 ComputeGravity(float buoyancy) |
548 | { | 470 | { |
549 | OMV.Vector3 ret = PhysicsScene.DefaultGravity; | 471 | OMV.Vector3 ret = PhysScene.DefaultGravity; |
550 | 472 | ||
551 | if (!IsStatic) | 473 | if (!IsStatic) |
552 | { | 474 | { |
@@ -570,95 +492,63 @@ public class BSPrim : BSPhysObject | |||
570 | } | 492 | } |
571 | 493 | ||
572 | public override OMV.Vector3 Force { | 494 | public override OMV.Vector3 Force { |
573 | get { return _force; } | 495 | get { return RawForce; } |
574 | set { | 496 | set { |
575 | _force = value; | 497 | RawForce = value; |
576 | if (_force != OMV.Vector3.Zero) | 498 | EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() |
577 | { | 499 | { |
578 | // If the force is non-zero, it must be reapplied each tick because | 500 | return new BSActorSetForce(PhysScene, this, SetForceActorName); |
579 | // Bullet clears the forces applied last frame. | 501 | }); |
580 | RegisterPreStepAction("BSPrim.setForce", LocalID, | ||
581 | delegate(float timeStep) | ||
582 | { | ||
583 | if (!IsPhysicallyActive || _force == OMV.Vector3.Zero) | ||
584 | { | ||
585 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
586 | return; | ||
587 | } | ||
588 | |||
589 | DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); | ||
590 | if (PhysBody.HasPhysicalBody) | ||
591 | { | ||
592 | PhysicsScene.PE.ApplyCentralForce(PhysBody, _force); | ||
593 | ActivateIfPhysical(false); | ||
594 | } | ||
595 | } | ||
596 | ); | ||
597 | } | ||
598 | else | ||
599 | { | ||
600 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
601 | } | ||
602 | } | 502 | } |
603 | } | 503 | } |
604 | 504 | ||
605 | public override int VehicleType { | 505 | public override int VehicleType { |
606 | get { | 506 | get { |
607 | return (int)VehicleController.Type; // if we are a vehicle, return that type | 507 | return (int)VehicleActor.Type; |
608 | } | 508 | } |
609 | set { | 509 | set { |
610 | Vehicle type = (Vehicle)value; | 510 | Vehicle type = (Vehicle)value; |
611 | 511 | ||
612 | PhysicsScene.TaintedObject("setVehicleType", delegate() | 512 | PhysScene.TaintedObject("setVehicleType", delegate() |
613 | { | 513 | { |
614 | // Done at taint time so we're sure the physics engine is not using the variables | 514 | // Some vehicle scripts change vehicle type on the fly as an easy way to |
615 | // Vehicle code changes the parameters for this vehicle type. | 515 | // change all the parameters. Like a plane changing to CAR when on the |
616 | VehicleController.ProcessTypeChange(type); | 516 | // ground. In this case, don't want to zero motion. |
517 | // ZeroMotion(true /* inTaintTime */); | ||
518 | VehicleActor.ProcessTypeChange(type); | ||
617 | ActivateIfPhysical(false); | 519 | ActivateIfPhysical(false); |
618 | |||
619 | // If an active vehicle, register the vehicle code to be called before each step | ||
620 | if (VehicleController.Type == Vehicle.TYPE_NONE) | ||
621 | { | ||
622 | UnRegisterPreStepAction("BSPrim.Vehicle", LocalID); | ||
623 | UnRegisterPostStepAction("BSPrim.Vehicle", LocalID); | ||
624 | } | ||
625 | else | ||
626 | { | ||
627 | RegisterPreStepAction("BSPrim.Vehicle", LocalID, VehicleController.Step); | ||
628 | RegisterPostStepAction("BSPrim.Vehicle", LocalID, VehicleController.PostStep); | ||
629 | } | ||
630 | }); | 520 | }); |
631 | } | 521 | } |
632 | } | 522 | } |
633 | public override void VehicleFloatParam(int param, float value) | 523 | public override void VehicleFloatParam(int param, float value) |
634 | { | 524 | { |
635 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() | 525 | PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() |
636 | { | 526 | { |
637 | VehicleController.ProcessFloatVehicleParam((Vehicle)param, value); | 527 | VehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); |
638 | ActivateIfPhysical(false); | 528 | ActivateIfPhysical(false); |
639 | }); | 529 | }); |
640 | } | 530 | } |
641 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | 531 | public override void VehicleVectorParam(int param, OMV.Vector3 value) |
642 | { | 532 | { |
643 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() | 533 | PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() |
644 | { | 534 | { |
645 | VehicleController.ProcessVectorVehicleParam((Vehicle)param, value); | 535 | VehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); |
646 | ActivateIfPhysical(false); | 536 | ActivateIfPhysical(false); |
647 | }); | 537 | }); |
648 | } | 538 | } |
649 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | 539 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) |
650 | { | 540 | { |
651 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() | 541 | PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() |
652 | { | 542 | { |
653 | VehicleController.ProcessRotationVehicleParam((Vehicle)param, rotation); | 543 | VehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); |
654 | ActivateIfPhysical(false); | 544 | ActivateIfPhysical(false); |
655 | }); | 545 | }); |
656 | } | 546 | } |
657 | public override void VehicleFlags(int param, bool remove) | 547 | public override void VehicleFlags(int param, bool remove) |
658 | { | 548 | { |
659 | PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() | 549 | PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() |
660 | { | 550 | { |
661 | VehicleController.ProcessVehicleFlags(param, remove); | 551 | VehicleActor.ProcessVehicleFlags(param, remove); |
662 | }); | 552 | }); |
663 | } | 553 | } |
664 | 554 | ||
@@ -668,7 +558,7 @@ public class BSPrim : BSPhysObject | |||
668 | if (_isVolumeDetect != newValue) | 558 | if (_isVolumeDetect != newValue) |
669 | { | 559 | { |
670 | _isVolumeDetect = newValue; | 560 | _isVolumeDetect = newValue; |
671 | PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() | 561 | PhysScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() |
672 | { | 562 | { |
673 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); | 563 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); |
674 | SetObjectDynamic(true); | 564 | SetObjectDynamic(true); |
@@ -679,7 +569,7 @@ public class BSPrim : BSPhysObject | |||
679 | public override void SetMaterial(int material) | 569 | public override void SetMaterial(int material) |
680 | { | 570 | { |
681 | base.SetMaterial(material); | 571 | base.SetMaterial(material); |
682 | PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() | 572 | PhysScene.TaintedObject("BSPrim.SetMaterial", delegate() |
683 | { | 573 | { |
684 | UpdatePhysicalParameters(); | 574 | UpdatePhysicalParameters(); |
685 | }); | 575 | }); |
@@ -692,7 +582,7 @@ public class BSPrim : BSPhysObject | |||
692 | if (base.Friction != value) | 582 | if (base.Friction != value) |
693 | { | 583 | { |
694 | base.Friction = value; | 584 | base.Friction = value; |
695 | PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() | 585 | PhysScene.TaintedObject("BSPrim.setFriction", delegate() |
696 | { | 586 | { |
697 | UpdatePhysicalParameters(); | 587 | UpdatePhysicalParameters(); |
698 | }); | 588 | }); |
@@ -707,7 +597,7 @@ public class BSPrim : BSPhysObject | |||
707 | if (base.Restitution != value) | 597 | if (base.Restitution != value) |
708 | { | 598 | { |
709 | base.Restitution = value; | 599 | base.Restitution = value; |
710 | PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() | 600 | PhysScene.TaintedObject("BSPrim.setRestitution", delegate() |
711 | { | 601 | { |
712 | UpdatePhysicalParameters(); | 602 | UpdatePhysicalParameters(); |
713 | }); | 603 | }); |
@@ -724,7 +614,7 @@ public class BSPrim : BSPhysObject | |||
724 | if (base.Density != value) | 614 | if (base.Density != value) |
725 | { | 615 | { |
726 | base.Density = value; | 616 | base.Density = value; |
727 | PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() | 617 | PhysScene.TaintedObject("BSPrim.setDensity", delegate() |
728 | { | 618 | { |
729 | UpdatePhysicalParameters(); | 619 | UpdatePhysicalParameters(); |
730 | }); | 620 | }); |
@@ -739,70 +629,47 @@ public class BSPrim : BSPhysObject | |||
739 | if (base.GravModifier != value) | 629 | if (base.GravModifier != value) |
740 | { | 630 | { |
741 | base.GravModifier = value; | 631 | base.GravModifier = value; |
742 | PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() | 632 | PhysScene.TaintedObject("BSPrim.setGravityModifier", delegate() |
743 | { | 633 | { |
744 | UpdatePhysicalParameters(); | 634 | UpdatePhysicalParameters(); |
745 | }); | 635 | }); |
746 | } | 636 | } |
747 | } | 637 | } |
748 | } | 638 | } |
749 | public override OMV.Vector3 RawVelocity | ||
750 | { | ||
751 | get { return _velocity; } | ||
752 | set { _velocity = value; } | ||
753 | } | ||
754 | public override OMV.Vector3 Velocity { | 639 | public override OMV.Vector3 Velocity { |
755 | get { return _velocity; } | 640 | get { return RawVelocity; } |
756 | set { | 641 | set { |
757 | _velocity = value; | 642 | RawVelocity = value; |
758 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | 643 | PhysScene.TaintedObject("BSPrim.setVelocity", delegate() |
759 | { | 644 | { |
760 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 645 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); |
761 | ForceVelocity = _velocity; | 646 | ForceVelocity = RawVelocity; |
762 | }); | 647 | }); |
763 | } | 648 | } |
764 | } | 649 | } |
765 | public override OMV.Vector3 ForceVelocity { | 650 | public override OMV.Vector3 ForceVelocity { |
766 | get { return _velocity; } | 651 | get { return RawVelocity; } |
767 | set { | 652 | set { |
768 | PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); | 653 | PhysScene.AssertInTaintTime("BSPrim.ForceVelocity"); |
769 | 654 | ||
770 | _velocity = Util.ClampV(value, BSParam.MaxLinearVelocity); | 655 | RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); |
771 | if (PhysBody.HasPhysicalBody) | 656 | if (PhysBody.HasPhysicalBody) |
772 | { | 657 | { |
773 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity); | 658 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); |
774 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | 659 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); |
775 | ActivateIfPhysical(false); | 660 | ActivateIfPhysical(false); |
776 | } | 661 | } |
777 | } | 662 | } |
778 | } | 663 | } |
779 | public override OMV.Vector3 Torque { | 664 | public override OMV.Vector3 Torque { |
780 | get { return _torque; } | 665 | get { return RawTorque; } |
781 | set { | 666 | set { |
782 | _torque = value; | 667 | RawTorque = value; |
783 | if (_torque != OMV.Vector3.Zero) | 668 | EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() |
784 | { | ||
785 | // If the torque is non-zero, it must be reapplied each tick because | ||
786 | // Bullet clears the forces applied last frame. | ||
787 | RegisterPreStepAction("BSPrim.setTorque", LocalID, | ||
788 | delegate(float timeStep) | ||
789 | { | ||
790 | if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero) | ||
791 | { | ||
792 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | ||
793 | return; | ||
794 | } | ||
795 | |||
796 | if (PhysBody.HasPhysicalBody) | ||
797 | AddAngularForce(_torque, false, true); | ||
798 | } | ||
799 | ); | ||
800 | } | ||
801 | else | ||
802 | { | 669 | { |
803 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | 670 | return new BSActorSetTorque(PhysScene, this, SetTorqueActorName); |
804 | } | 671 | }); |
805 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | 672 | DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); |
806 | } | 673 | } |
807 | } | 674 | } |
808 | public override OMV.Vector3 Acceleration { | 675 | public override OMV.Vector3 Acceleration { |
@@ -823,7 +690,7 @@ public class BSPrim : BSPhysObject | |||
823 | return; | 690 | return; |
824 | _orientation = value; | 691 | _orientation = value; |
825 | 692 | ||
826 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() | 693 | PhysScene.TaintedObject("BSPrim.setOrientation", delegate() |
827 | { | 694 | { |
828 | ForceOrientation = _orientation; | 695 | ForceOrientation = _orientation; |
829 | }); | 696 | }); |
@@ -834,14 +701,14 @@ public class BSPrim : BSPhysObject | |||
834 | { | 701 | { |
835 | get | 702 | get |
836 | { | 703 | { |
837 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); | 704 | _orientation = PhysScene.PE.GetOrientation(PhysBody); |
838 | return _orientation; | 705 | return _orientation; |
839 | } | 706 | } |
840 | set | 707 | set |
841 | { | 708 | { |
842 | _orientation = value; | 709 | _orientation = value; |
843 | if (PhysBody.HasPhysicalBody) | 710 | if (PhysBody.HasPhysicalBody) |
844 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 711 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); |
845 | } | 712 | } |
846 | } | 713 | } |
847 | public override int PhysicsActorType { | 714 | public override int PhysicsActorType { |
@@ -854,7 +721,7 @@ public class BSPrim : BSPhysObject | |||
854 | if (_isPhysical != value) | 721 | if (_isPhysical != value) |
855 | { | 722 | { |
856 | _isPhysical = value; | 723 | _isPhysical = value; |
857 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() | 724 | PhysScene.TaintedObject("BSPrim.setIsPhysical", delegate() |
858 | { | 725 | { |
859 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | 726 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); |
860 | SetObjectDynamic(true); | 727 | SetObjectDynamic(true); |
@@ -903,19 +770,19 @@ public class BSPrim : BSPhysObject | |||
903 | if (!PhysBody.HasPhysicalBody) | 770 | if (!PhysBody.HasPhysicalBody) |
904 | { | 771 | { |
905 | // This would only happen if updates are called for during initialization when the body is not set up yet. | 772 | // This would only happen if updates are called for during initialization when the body is not set up yet. |
906 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); | 773 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); |
907 | return; | 774 | return; |
908 | } | 775 | } |
909 | 776 | ||
910 | // Mangling all the physical properties requires the object not be in the physical world. | 777 | // Mangling all the physical properties requires the object not be in the physical world. |
911 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). | 778 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). |
912 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 779 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
913 | 780 | ||
914 | // Set up the object physicalness (does gravity and collisions move this object) | 781 | // Set up the object physicalness (does gravity and collisions move this object) |
915 | MakeDynamic(IsStatic); | 782 | MakeDynamic(IsStatic); |
916 | 783 | ||
917 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) | 784 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) |
918 | VehicleController.Refresh(); | 785 | PhysicalActors.Refresh(); |
919 | 786 | ||
920 | // Arrange for collision events if the simulator wants them | 787 | // Arrange for collision events if the simulator wants them |
921 | EnableCollisions(SubscribedEvents()); | 788 | EnableCollisions(SubscribedEvents()); |
@@ -926,10 +793,11 @@ public class BSPrim : BSPhysObject | |||
926 | AddObjectToPhysicalWorld(); | 793 | AddObjectToPhysicalWorld(); |
927 | 794 | ||
928 | // Rebuild its shape | 795 | // Rebuild its shape |
929 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); | 796 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); |
930 | 797 | ||
931 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", | 798 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", |
932 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); | 799 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), |
800 | CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); | ||
933 | } | 801 | } |
934 | 802 | ||
935 | // "Making dynamic" means changing to and from static. | 803 | // "Making dynamic" means changing to and from static. |
@@ -942,28 +810,28 @@ public class BSPrim : BSPhysObject | |||
942 | if (makeStatic) | 810 | if (makeStatic) |
943 | { | 811 | { |
944 | // Become a Bullet 'static' object type | 812 | // Become a Bullet 'static' object type |
945 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); | 813 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
946 | // Stop all movement | 814 | // Stop all movement |
947 | ZeroMotion(true); | 815 | ZeroMotion(true); |
948 | 816 | ||
949 | // Set various physical properties so other object interact properly | 817 | // Set various physical properties so other object interact properly |
950 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | 818 | PhysScene.PE.SetFriction(PhysBody, Friction); |
951 | PhysicsScene.PE.SetRestitution(PhysBody, Restitution); | 819 | PhysScene.PE.SetRestitution(PhysBody, Restitution); |
952 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 820 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
953 | 821 | ||
954 | // Mass is zero which disables a bunch of physics stuff in Bullet | 822 | // Mass is zero which disables a bunch of physics stuff in Bullet |
955 | UpdatePhysicalMassProperties(0f, false); | 823 | UpdatePhysicalMassProperties(0f, false); |
956 | // Set collision detection parameters | 824 | // Set collision detection parameters |
957 | if (BSParam.CcdMotionThreshold > 0f) | 825 | if (BSParam.CcdMotionThreshold > 0f) |
958 | { | 826 | { |
959 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 827 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
960 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 828 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
961 | } | 829 | } |
962 | 830 | ||
963 | // The activation state is 'disabled' so Bullet will not try to act on it. | 831 | // The activation state is 'disabled' so Bullet will not try to act on it. |
964 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); | 832 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); |
965 | // Start it out sleeping and physical actions could wake it up. | 833 | // Start it out sleeping and physical actions could wake it up. |
966 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); | 834 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); |
967 | 835 | ||
968 | // This collides like a static object | 836 | // This collides like a static object |
969 | PhysBody.collisionType = CollisionType.Static; | 837 | PhysBody.collisionType = CollisionType.Static; |
@@ -971,11 +839,11 @@ public class BSPrim : BSPhysObject | |||
971 | else | 839 | else |
972 | { | 840 | { |
973 | // Not a Bullet static object | 841 | // Not a Bullet static object |
974 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); | 842 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
975 | 843 | ||
976 | // Set various physical properties so other object interact properly | 844 | // Set various physical properties so other object interact properly |
977 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | 845 | PhysScene.PE.SetFriction(PhysBody, Friction); |
978 | PhysicsScene.PE.SetRestitution(PhysBody, Restitution); | 846 | PhysScene.PE.SetRestitution(PhysBody, Restitution); |
979 | // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); | 847 | // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); |
980 | 848 | ||
981 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | 849 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
@@ -984,7 +852,7 @@ public class BSPrim : BSPhysObject | |||
984 | 852 | ||
985 | // For good measure, make sure the transform is set through to the motion state | 853 | // For good measure, make sure the transform is set through to the motion state |
986 | ForcePosition = _position; | 854 | ForcePosition = _position; |
987 | ForceVelocity = _velocity; | 855 | ForceVelocity = RawVelocity; |
988 | ForceRotationalVelocity = _rotationalVelocity; | 856 | ForceRotationalVelocity = _rotationalVelocity; |
989 | 857 | ||
990 | // A dynamic object has mass | 858 | // A dynamic object has mass |
@@ -993,22 +861,22 @@ public class BSPrim : BSPhysObject | |||
993 | // Set collision detection parameters | 861 | // Set collision detection parameters |
994 | if (BSParam.CcdMotionThreshold > 0f) | 862 | if (BSParam.CcdMotionThreshold > 0f) |
995 | { | 863 | { |
996 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 864 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
997 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 865 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
998 | } | 866 | } |
999 | 867 | ||
1000 | // Various values for simulation limits | 868 | // Various values for simulation limits |
1001 | PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); | 869 | PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); |
1002 | PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); | 870 | PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); |
1003 | PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); | 871 | PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); |
1004 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 872 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
1005 | 873 | ||
1006 | // This collides like an object. | 874 | // This collides like an object. |
1007 | PhysBody.collisionType = CollisionType.Dynamic; | 875 | PhysBody.collisionType = CollisionType.Dynamic; |
1008 | 876 | ||
1009 | // Force activation of the object so Bullet will act on it. | 877 | // Force activation of the object so Bullet will act on it. |
1010 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | 878 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. |
1011 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | 879 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
1012 | } | 880 | } |
1013 | } | 881 | } |
1014 | 882 | ||
@@ -1018,7 +886,7 @@ public class BSPrim : BSPhysObject | |||
1018 | // the functions after this one set up the state of a possibly newly created collision body. | 886 | // the functions after this one set up the state of a possibly newly created collision body. |
1019 | private void MakeSolid(bool makeSolid) | 887 | private void MakeSolid(bool makeSolid) |
1020 | { | 888 | { |
1021 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); | 889 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody); |
1022 | if (makeSolid) | 890 | if (makeSolid) |
1023 | { | 891 | { |
1024 | // Verify the previous code created the correct shape for this type of thing. | 892 | // Verify the previous code created the correct shape for this type of thing. |
@@ -1026,7 +894,7 @@ public class BSPrim : BSPhysObject | |||
1026 | { | 894 | { |
1027 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); | 895 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); |
1028 | } | 896 | } |
1029 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 897 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
1030 | } | 898 | } |
1031 | else | 899 | else |
1032 | { | 900 | { |
@@ -1034,32 +902,23 @@ public class BSPrim : BSPhysObject | |||
1034 | { | 902 | { |
1035 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | 903 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); |
1036 | } | 904 | } |
1037 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 905 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
1038 | 906 | ||
1039 | // Change collision info from a static object to a ghosty collision object | 907 | // Change collision info from a static object to a ghosty collision object |
1040 | PhysBody.collisionType = CollisionType.VolumeDetect; | 908 | PhysBody.collisionType = CollisionType.VolumeDetect; |
1041 | } | 909 | } |
1042 | } | 910 | } |
1043 | 911 | ||
1044 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | ||
1045 | // they need waking up when parameters are changed. | ||
1046 | // Called in taint-time!! | ||
1047 | private void ActivateIfPhysical(bool forceIt) | ||
1048 | { | ||
1049 | if (IsPhysical && PhysBody.HasPhysicalBody) | ||
1050 | PhysicsScene.PE.Activate(PhysBody, forceIt); | ||
1051 | } | ||
1052 | |||
1053 | // Turn on or off the flag controlling whether collision events are returned to the simulator. | 912 | // Turn on or off the flag controlling whether collision events are returned to the simulator. |
1054 | private void EnableCollisions(bool wantsCollisionEvents) | 913 | private void EnableCollisions(bool wantsCollisionEvents) |
1055 | { | 914 | { |
1056 | if (wantsCollisionEvents) | 915 | if (wantsCollisionEvents) |
1057 | { | 916 | { |
1058 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 917 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
1059 | } | 918 | } |
1060 | else | 919 | else |
1061 | { | 920 | { |
1062 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 921 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
1063 | } | 922 | } |
1064 | } | 923 | } |
1065 | 924 | ||
@@ -1070,7 +929,7 @@ public class BSPrim : BSPhysObject | |||
1070 | { | 929 | { |
1071 | if (PhysBody.HasPhysicalBody) | 930 | if (PhysBody.HasPhysicalBody) |
1072 | { | 931 | { |
1073 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | 932 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); |
1074 | } | 933 | } |
1075 | else | 934 | else |
1076 | { | 935 | { |
@@ -1105,12 +964,12 @@ public class BSPrim : BSPhysObject | |||
1105 | public override bool FloatOnWater { | 964 | public override bool FloatOnWater { |
1106 | set { | 965 | set { |
1107 | _floatOnWater = value; | 966 | _floatOnWater = value; |
1108 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() | 967 | PhysScene.TaintedObject("BSPrim.setFloatOnWater", delegate() |
1109 | { | 968 | { |
1110 | if (_floatOnWater) | 969 | if (_floatOnWater) |
1111 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 970 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
1112 | else | 971 | else |
1113 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 972 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
1114 | }); | 973 | }); |
1115 | } | 974 | } |
1116 | } | 975 | } |
@@ -1122,7 +981,7 @@ public class BSPrim : BSPhysObject | |||
1122 | _rotationalVelocity = value; | 981 | _rotationalVelocity = value; |
1123 | Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); | 982 | Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); |
1124 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | 983 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
1125 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 984 | PhysScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
1126 | { | 985 | { |
1127 | ForceRotationalVelocity = _rotationalVelocity; | 986 | ForceRotationalVelocity = _rotationalVelocity; |
1128 | }); | 987 | }); |
@@ -1137,7 +996,7 @@ public class BSPrim : BSPhysObject | |||
1137 | if (PhysBody.HasPhysicalBody) | 996 | if (PhysBody.HasPhysicalBody) |
1138 | { | 997 | { |
1139 | DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | 998 | DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
1140 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | 999 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); |
1141 | // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | 1000 | // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); |
1142 | ActivateIfPhysical(false); | 1001 | ActivateIfPhysical(false); |
1143 | } | 1002 | } |
@@ -1153,7 +1012,7 @@ public class BSPrim : BSPhysObject | |||
1153 | get { return _buoyancy; } | 1012 | get { return _buoyancy; } |
1154 | set { | 1013 | set { |
1155 | _buoyancy = value; | 1014 | _buoyancy = value; |
1156 | PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() | 1015 | PhysScene.TaintedObject("BSPrim.setBuoyancy", delegate() |
1157 | { | 1016 | { |
1158 | ForceBuoyancy = _buoyancy; | 1017 | ForceBuoyancy = _buoyancy; |
1159 | }); | 1018 | }); |
@@ -1171,78 +1030,13 @@ public class BSPrim : BSPhysObject | |||
1171 | } | 1030 | } |
1172 | } | 1031 | } |
1173 | 1032 | ||
1174 | // Used for MoveTo | ||
1175 | public override OMV.Vector3 PIDTarget { | ||
1176 | set | ||
1177 | { | ||
1178 | // TODO: add a sanity check -- don't move more than a region or something like that. | ||
1179 | _PIDTarget = value; | ||
1180 | } | ||
1181 | } | ||
1182 | public override float PIDTau { | ||
1183 | set { _PIDTau = value; } | ||
1184 | } | ||
1185 | public override bool PIDActive { | 1033 | public override bool PIDActive { |
1186 | set { | 1034 | set { |
1187 | if (value) | 1035 | base.MoveToTargetActive = value; |
1188 | { | 1036 | EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() |
1189 | // We're taking over after this. | ||
1190 | ZeroMotion(true); | ||
1191 | |||
1192 | _targetMotor = new BSVMotor("BSPrim.PIDTarget", | ||
1193 | _PIDTau, // timeScale | ||
1194 | BSMotor.Infinite, // decay time scale | ||
1195 | BSMotor.InfiniteVector, // friction timescale | ||
1196 | 1f // efficiency | ||
1197 | ); | ||
1198 | _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1199 | _targetMotor.SetTarget(_PIDTarget); | ||
1200 | _targetMotor.SetCurrent(RawPosition); | ||
1201 | /* | ||
1202 | _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget"); | ||
1203 | _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1204 | |||
1205 | _targetMotor.SetTarget(_PIDTarget); | ||
1206 | _targetMotor.SetCurrent(RawPosition); | ||
1207 | _targetMotor.TimeScale = _PIDTau; | ||
1208 | _targetMotor.Efficiency = 1f; | ||
1209 | */ | ||
1210 | |||
1211 | RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep) | ||
1212 | { | ||
1213 | if (!IsPhysicallyActive) | ||
1214 | { | ||
1215 | UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); | ||
1216 | return; | ||
1217 | } | ||
1218 | |||
1219 | OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below) | ||
1220 | |||
1221 | // 'movePosition' is where we'd like the prim to be at this moment. | ||
1222 | OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep); | ||
1223 | |||
1224 | // If we are very close to our target, turn off the movement motor. | ||
1225 | if (_targetMotor.ErrorIsZero()) | ||
1226 | { | ||
1227 | DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", | ||
1228 | LocalID, movePosition, RawPosition, Mass); | ||
1229 | ForcePosition = _targetMotor.TargetValue; | ||
1230 | _targetMotor.Enabled = false; | ||
1231 | } | ||
1232 | else | ||
1233 | { | ||
1234 | _position = movePosition; | ||
1235 | PositionSanityCheck(true /* intaintTime */); | ||
1236 | ForcePosition = _position; | ||
1237 | } | ||
1238 | DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition); | ||
1239 | }); | ||
1240 | } | ||
1241 | else | ||
1242 | { | 1037 | { |
1243 | // Stop any targetting | 1038 | return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName); |
1244 | UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); | 1039 | }); |
1245 | } | ||
1246 | } | 1040 | } |
1247 | } | 1041 | } |
1248 | 1042 | ||
@@ -1250,94 +1044,20 @@ public class BSPrim : BSPhysObject | |||
1250 | // Hover Height will override MoveTo target's Z | 1044 | // Hover Height will override MoveTo target's Z |
1251 | public override bool PIDHoverActive { | 1045 | public override bool PIDHoverActive { |
1252 | set { | 1046 | set { |
1253 | if (value) | 1047 | base.HoverActive = value; |
1254 | { | 1048 | EnableActor(HoverActive, HoverActorName, delegate() |
1255 | // Turning the target on | ||
1256 | _hoverMotor = new BSFMotor("BSPrim.Hover", | ||
1257 | _PIDHoverTau, // timeScale | ||
1258 | BSMotor.Infinite, // decay time scale | ||
1259 | BSMotor.Infinite, // friction timescale | ||
1260 | 1f // efficiency | ||
1261 | ); | ||
1262 | _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); | ||
1263 | _hoverMotor.SetCurrent(RawPosition.Z); | ||
1264 | _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1265 | |||
1266 | RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep) | ||
1267 | { | ||
1268 | // Don't do hovering while the object is selected. | ||
1269 | if (!IsPhysicallyActive) | ||
1270 | return; | ||
1271 | |||
1272 | _hoverMotor.SetCurrent(RawPosition.Z); | ||
1273 | _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); | ||
1274 | float targetHeight = _hoverMotor.Step(timeStep); | ||
1275 | |||
1276 | // 'targetHeight' is where we'd like the Z of the prim to be at this moment. | ||
1277 | // Compute the amount of force to push us there. | ||
1278 | float moveForce = (targetHeight - RawPosition.Z) * Mass; | ||
1279 | // Undo anything the object thinks it's doing at the moment | ||
1280 | moveForce = -RawVelocity.Z * Mass; | ||
1281 | |||
1282 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce)); | ||
1283 | DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass); | ||
1284 | }); | ||
1285 | } | ||
1286 | else | ||
1287 | { | 1049 | { |
1288 | UnRegisterPreStepAction("BSPrim.Hover", LocalID); | 1050 | return new BSActorHover(PhysScene, this, HoverActorName); |
1289 | } | 1051 | }); |
1290 | } | ||
1291 | } | ||
1292 | public override float PIDHoverHeight { | ||
1293 | set { _PIDHoverHeight = value; } | ||
1294 | } | ||
1295 | public override PIDHoverType PIDHoverType { | ||
1296 | set { _PIDHoverType = value; } | ||
1297 | } | ||
1298 | public override float PIDHoverTau { | ||
1299 | set { _PIDHoverTau = value; } | ||
1300 | } | ||
1301 | // Based on current position, determine what we should be hovering at now. | ||
1302 | // Must recompute often. What if we walked offa cliff> | ||
1303 | private float ComputeCurrentPIDHoverHeight() | ||
1304 | { | ||
1305 | float ret = _PIDHoverHeight; | ||
1306 | float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | ||
1307 | |||
1308 | switch (_PIDHoverType) | ||
1309 | { | ||
1310 | case PIDHoverType.Ground: | ||
1311 | ret = groundHeight + _PIDHoverHeight; | ||
1312 | break; | ||
1313 | case PIDHoverType.GroundAndWater: | ||
1314 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); | ||
1315 | if (groundHeight > waterHeight) | ||
1316 | { | ||
1317 | ret = groundHeight + _PIDHoverHeight; | ||
1318 | } | ||
1319 | else | ||
1320 | { | ||
1321 | ret = waterHeight + _PIDHoverHeight; | ||
1322 | } | ||
1323 | break; | ||
1324 | } | 1052 | } |
1325 | return ret; | ||
1326 | } | 1053 | } |
1327 | 1054 | ||
1328 | |||
1329 | // For RotLookAt | ||
1330 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
1331 | public override bool APIDActive { set { return; } } | ||
1332 | public override float APIDStrength { set { return; } } | ||
1333 | public override float APIDDamping { set { return; } } | ||
1334 | |||
1335 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 1055 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
1336 | // Per documentation, max force is limited. | 1056 | // Per documentation, max force is limited. |
1337 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); | 1057 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); |
1338 | 1058 | ||
1339 | // Since this force is being applied in only one step, make this a force per second. | 1059 | // Since this force is being applied in only one step, make this a force per second. |
1340 | addForce /= PhysicsScene.LastTimeStep; | 1060 | addForce /= PhysScene.LastTimeStep; |
1341 | AddForce(addForce, pushforce, false /* inTaintTime */); | 1061 | AddForce(addForce, pushforce, false /* inTaintTime */); |
1342 | } | 1062 | } |
1343 | 1063 | ||
@@ -1352,13 +1072,13 @@ public class BSPrim : BSPhysObject | |||
1352 | // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); | 1072 | // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); |
1353 | 1073 | ||
1354 | OMV.Vector3 addForce = force; | 1074 | OMV.Vector3 addForce = force; |
1355 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() | 1075 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() |
1356 | { | 1076 | { |
1357 | // Bullet adds this central force to the total force for this tick | 1077 | // Bullet adds this central force to the total force for this tick |
1358 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); | 1078 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); |
1359 | if (PhysBody.HasPhysicalBody) | 1079 | if (PhysBody.HasPhysicalBody) |
1360 | { | 1080 | { |
1361 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | 1081 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); |
1362 | ActivateIfPhysical(false); | 1082 | ActivateIfPhysical(false); |
1363 | } | 1083 | } |
1364 | }); | 1084 | }); |
@@ -1380,13 +1100,13 @@ public class BSPrim : BSPhysObject | |||
1380 | OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); | 1100 | OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); |
1381 | // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); | 1101 | // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); |
1382 | 1102 | ||
1383 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() | 1103 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() |
1384 | { | 1104 | { |
1385 | // Bullet adds this impulse immediately to the velocity | 1105 | // Bullet adds this impulse immediately to the velocity |
1386 | DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); | 1106 | DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); |
1387 | if (PhysBody.HasPhysicalBody) | 1107 | if (PhysBody.HasPhysicalBody) |
1388 | { | 1108 | { |
1389 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); | 1109 | PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); |
1390 | ActivateIfPhysical(false); | 1110 | ActivateIfPhysical(false); |
1391 | } | 1111 | } |
1392 | }); | 1112 | }); |
@@ -1399,20 +1119,18 @@ public class BSPrim : BSPhysObject | |||
1399 | } | 1119 | } |
1400 | } | 1120 | } |
1401 | 1121 | ||
1402 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 1122 | // BSPhysObject.AddAngularForce() |
1403 | AddAngularForce(force, pushforce, false); | 1123 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) |
1404 | } | ||
1405 | public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) | ||
1406 | { | 1124 | { |
1407 | if (force.IsFinite()) | 1125 | if (force.IsFinite()) |
1408 | { | 1126 | { |
1409 | OMV.Vector3 angForce = force; | 1127 | OMV.Vector3 angForce = force; |
1410 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() | 1128 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() |
1411 | { | 1129 | { |
1412 | if (PhysBody.HasPhysicalBody) | 1130 | if (PhysBody.HasPhysicalBody) |
1413 | { | 1131 | { |
1414 | DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); | 1132 | DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); |
1415 | PhysicsScene.PE.ApplyTorque(PhysBody, angForce); | 1133 | PhysScene.PE.ApplyTorque(PhysBody, angForce); |
1416 | ActivateIfPhysical(false); | 1134 | ActivateIfPhysical(false); |
1417 | } | 1135 | } |
1418 | }); | 1136 | }); |
@@ -1431,11 +1149,11 @@ public class BSPrim : BSPhysObject | |||
1431 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | 1149 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) |
1432 | { | 1150 | { |
1433 | OMV.Vector3 applyImpulse = impulse; | 1151 | OMV.Vector3 applyImpulse = impulse; |
1434 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | 1152 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() |
1435 | { | 1153 | { |
1436 | if (PhysBody.HasPhysicalBody) | 1154 | if (PhysBody.HasPhysicalBody) |
1437 | { | 1155 | { |
1438 | PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); | 1156 | PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); |
1439 | ActivateIfPhysical(false); | 1157 | ActivateIfPhysical(false); |
1440 | } | 1158 | } |
1441 | }); | 1159 | }); |
@@ -1721,9 +1439,9 @@ public class BSPrim : BSPhysObject | |||
1721 | volume *= (profileEnd - profileBegin); | 1439 | volume *= (profileEnd - profileBegin); |
1722 | 1440 | ||
1723 | returnMass = Density * BSParam.DensityScaleFactor * volume; | 1441 | returnMass = Density * BSParam.DensityScaleFactor * volume; |
1724 | DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); | ||
1725 | 1442 | ||
1726 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); | 1443 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); |
1444 | // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); | ||
1727 | 1445 | ||
1728 | return returnMass; | 1446 | return returnMass; |
1729 | }// end CalculateMass | 1447 | }// end CalculateMass |
@@ -1736,13 +1454,14 @@ public class BSPrim : BSPhysObject | |||
1736 | { | 1454 | { |
1737 | // Create the correct physical representation for this type of object. | 1455 | // Create the correct physical representation for this type of object. |
1738 | // Updates base.PhysBody and base.PhysShape with the new information. | 1456 | // Updates base.PhysBody and base.PhysShape with the new information. |
1739 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1457 | // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. |
1740 | PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) | 1458 | PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape) |
1741 | { | 1459 | { |
1742 | // Called if the current prim body is about to be destroyed. | 1460 | // Called if the current prim body is about to be destroyed. |
1743 | // Remove all the physical dependencies on the old body. | 1461 | // Remove all the physical dependencies on the old body. |
1744 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) | 1462 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) |
1745 | RemoveBodyDependencies(); | 1463 | // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints. |
1464 | RemoveDependencies(); | ||
1746 | }); | 1465 | }); |
1747 | 1466 | ||
1748 | // Make sure the properties are set on the new object | 1467 | // Make sure the properties are set on the new object |
@@ -1750,24 +1469,19 @@ public class BSPrim : BSPhysObject | |||
1750 | return; | 1469 | return; |
1751 | } | 1470 | } |
1752 | 1471 | ||
1753 | protected virtual void RemoveBodyDependencies() | 1472 | // Called at taint-time |
1473 | protected virtual void RemoveDependencies() | ||
1754 | { | 1474 | { |
1755 | VehicleController.RemoveBodyDependencies(this); | 1475 | PhysicalActors.RemoveDependencies(); |
1756 | } | 1476 | } |
1757 | 1477 | ||
1758 | // The physics engine says that properties have updated. Update same and inform | 1478 | // The physics engine says that properties have updated. Update same and inform |
1759 | // the world that things have changed. | 1479 | // the world that things have changed. |
1760 | public override void UpdateProperties(EntityProperties entprop) | 1480 | public override void UpdateProperties(EntityProperties entprop) |
1761 | { | 1481 | { |
1482 | // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. | ||
1762 | TriggerPreUpdatePropertyAction(ref entprop); | 1483 | TriggerPreUpdatePropertyAction(ref entprop); |
1763 | 1484 | ||
1764 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet | ||
1765 | // TODO: handle physics introduced by Bullet with computed vehicle physics. | ||
1766 | if (VehicleController.IsActive) | ||
1767 | { | ||
1768 | entprop.RotationalVelocity = OMV.Vector3.Zero; | ||
1769 | } | ||
1770 | |||
1771 | // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG | 1485 | // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG |
1772 | 1486 | ||
1773 | // Assign directly to the local variables so the normal set actions do not happen | 1487 | // Assign directly to the local variables so the normal set actions do not happen |
@@ -1775,8 +1489,8 @@ public class BSPrim : BSPhysObject | |||
1775 | _orientation = entprop.Rotation; | 1489 | _orientation = entprop.Rotation; |
1776 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be | 1490 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be |
1777 | // very sensitive to velocity changes. | 1491 | // very sensitive to velocity changes. |
1778 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold)) | 1492 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) |
1779 | _velocity = entprop.Velocity; | 1493 | RawVelocity = entprop.Velocity; |
1780 | _acceleration = entprop.Acceleration; | 1494 | _acceleration = entprop.Acceleration; |
1781 | _rotationalVelocity = entprop.RotationalVelocity; | 1495 | _rotationalVelocity = entprop.RotationalVelocity; |
1782 | 1496 | ||
@@ -1786,7 +1500,7 @@ public class BSPrim : BSPhysObject | |||
1786 | if (PositionSanityCheck(true /* inTaintTime */ )) | 1500 | if (PositionSanityCheck(true /* inTaintTime */ )) |
1787 | { | 1501 | { |
1788 | entprop.Position = _position; | 1502 | entprop.Position = _position; |
1789 | entprop.Velocity = _velocity; | 1503 | entprop.Velocity = RawVelocity; |
1790 | entprop.RotationalVelocity = _rotationalVelocity; | 1504 | entprop.RotationalVelocity = _rotationalVelocity; |
1791 | entprop.Acceleration = _acceleration; | 1505 | entprop.Acceleration = _acceleration; |
1792 | } | 1506 | } |
@@ -1798,16 +1512,9 @@ public class BSPrim : BSPhysObject | |||
1798 | LastEntityProperties = CurrentEntityProperties; | 1512 | LastEntityProperties = CurrentEntityProperties; |
1799 | CurrentEntityProperties = entprop; | 1513 | CurrentEntityProperties = entprop; |
1800 | 1514 | ||
1801 | base.RequestPhysicsterseUpdate(); | 1515 | // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. |
1802 | /* | 1516 | |
1803 | else | 1517 | PhysScene.PostUpdate(this); |
1804 | { | ||
1805 | // For debugging, report the movement of children | ||
1806 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
1807 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | ||
1808 | entprop.Acceleration, entprop.RotationalVelocity); | ||
1809 | } | ||
1810 | */ | ||
1811 | } | 1518 | } |
1812 | } | 1519 | } |
1813 | } | 1520 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs index f1c3b5c..f5ee671 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs | |||
@@ -78,14 +78,16 @@ public class BSPrimDisplaced : BSPrim | |||
78 | // Set this sets and computes the displacement from the passed prim to the center-of-mass. | 78 | // Set this sets and computes the displacement from the passed prim to the center-of-mass. |
79 | // A user set value for center-of-mass overrides whatever might be passed in here. | 79 | // A user set value for center-of-mass overrides whatever might be passed in here. |
80 | // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). | 80 | // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). |
81 | public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement) | 81 | public virtual void SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) |
82 | { | 82 | { |
83 | Vector3 comDisp; | 83 | Vector3 comDisp; |
84 | if (UserSetCenterOfMass.HasValue) | 84 | if (UserSetCenterOfMassDisplacement.HasValue) |
85 | comDisp = (OMV.Vector3)UserSetCenterOfMass; | 85 | comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement; |
86 | else | 86 | else |
87 | comDisp = centerOfMassDisplacement; | 87 | comDisp = centerOfMassDisplacement; |
88 | 88 | ||
89 | DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}", | ||
90 | LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp); | ||
89 | if (comDisp == Vector3.Zero) | 91 | if (comDisp == Vector3.Zero) |
90 | { | 92 | { |
91 | // If there is no diplacement. Things get reset. | 93 | // If there is no diplacement. Things get reset. |
@@ -107,9 +109,15 @@ public class BSPrimDisplaced : BSPrim | |||
107 | set | 109 | set |
108 | { | 110 | { |
109 | if (PositionDisplacement != OMV.Vector3.Zero) | 111 | if (PositionDisplacement != OMV.Vector3.Zero) |
110 | base.ForcePosition = value - (PositionDisplacement * RawOrientation); | 112 | { |
113 | OMV.Vector3 displacedPos = value - (PositionDisplacement * RawOrientation); | ||
114 | DetailLog("{0},BSPrimDisplaced.ForcePosition,val={1},disp={2},newPos={3}", LocalID, value, PositionDisplacement, displacedPos); | ||
115 | base.ForcePosition = displacedPos; | ||
116 | } | ||
111 | else | 117 | else |
118 | { | ||
112 | base.ForcePosition = value; | 119 | base.ForcePosition = value; |
120 | } | ||
113 | } | 121 | } |
114 | } | 122 | } |
115 | 123 | ||
@@ -118,6 +126,7 @@ public class BSPrimDisplaced : BSPrim | |||
118 | get { return base.ForceOrientation; } | 126 | get { return base.ForceOrientation; } |
119 | set | 127 | set |
120 | { | 128 | { |
129 | // TODO: | ||
121 | base.ForceOrientation = value; | 130 | base.ForceOrientation = value; |
122 | } | 131 | } |
123 | } | 132 | } |
@@ -143,7 +152,10 @@ public class BSPrimDisplaced : BSPrim | |||
143 | { | 152 | { |
144 | // Correct for any rotation around the center-of-mass | 153 | // Correct for any rotation around the center-of-mass |
145 | // TODO!!! | 154 | // TODO!!! |
146 | entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation); | 155 | |
156 | OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * entprop.Rotation); | ||
157 | DetailLog("{0},BSPrimDisplaced.ForcePosition,physPos={1},disp={2},newPos={3}", LocalID, entprop.Position, PositionDisplacement, displacedPos); | ||
158 | entprop.Position = displacedPos; | ||
147 | // entprop.Rotation = something; | 159 | // entprop.Rotation = something; |
148 | } | 160 | } |
149 | 161 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index d65d407..235da78 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs | |||
@@ -47,9 +47,9 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
47 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 47 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
48 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) | 48 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) |
49 | { | 49 | { |
50 | Linkset = BSLinkset.Factory(PhysicsScene, this); | 50 | Linkset = BSLinkset.Factory(PhysScene, this); |
51 | 51 | ||
52 | PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() | 52 | PhysScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() |
53 | { | 53 | { |
54 | Linkset.Refresh(this); | 54 | Linkset.Refresh(this); |
55 | }); | 55 | }); |
@@ -61,9 +61,6 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
61 | base.Destroy(); | 61 | base.Destroy(); |
62 | } | 62 | } |
63 | 63 | ||
64 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
65 | { get { return Linkset.PreferredPhysicalShape(this); } } | ||
66 | |||
67 | public override void link(Manager.PhysicsActor obj) | 64 | public override void link(Manager.PhysicsActor obj) |
68 | { | 65 | { |
69 | BSPrimLinkable parent = obj as BSPrimLinkable; | 66 | BSPrimLinkable parent = obj as BSPrimLinkable; |
@@ -102,7 +99,7 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
102 | set | 99 | set |
103 | { | 100 | { |
104 | base.Position = value; | 101 | base.Position = value; |
105 | PhysicsScene.TaintedObject("BSPrimLinkset.setPosition", delegate() | 102 | PhysScene.TaintedObject("BSPrimLinkset.setPosition", delegate() |
106 | { | 103 | { |
107 | Linkset.UpdateProperties(UpdatedProperties.Position, this); | 104 | Linkset.UpdateProperties(UpdatedProperties.Position, this); |
108 | }); | 105 | }); |
@@ -116,7 +113,7 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
116 | set | 113 | set |
117 | { | 114 | { |
118 | base.Orientation = value; | 115 | base.Orientation = value; |
119 | PhysicsScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() | 116 | PhysScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() |
120 | { | 117 | { |
121 | Linkset.UpdateProperties(UpdatedProperties.Orientation, this); | 118 | Linkset.UpdateProperties(UpdatedProperties.Orientation, this); |
122 | }); | 119 | }); |
@@ -149,10 +146,10 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
149 | } | 146 | } |
150 | 147 | ||
151 | // Body is being taken apart. Remove physical dependencies and schedule a rebuild. | 148 | // Body is being taken apart. Remove physical dependencies and schedule a rebuild. |
152 | protected override void RemoveBodyDependencies() | 149 | protected override void RemoveDependencies() |
153 | { | 150 | { |
154 | Linkset.RemoveBodyDependencies(this); | 151 | Linkset.RemoveDependencies(this); |
155 | base.RemoveBodyDependencies(); | 152 | base.RemoveDependencies(); |
156 | } | 153 | } |
157 | 154 | ||
158 | public override void UpdateProperties(EntityProperties entprop) | 155 | public override void UpdateProperties(EntityProperties entprop) |
@@ -163,6 +160,15 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
163 | // TODO: this will have to change when linksets are articulated. | 160 | // TODO: this will have to change when linksets are articulated. |
164 | base.UpdateProperties(entprop); | 161 | base.UpdateProperties(entprop); |
165 | } | 162 | } |
163 | /* | ||
164 | else | ||
165 | { | ||
166 | // For debugging, report the movement of children | ||
167 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
168 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | ||
169 | entprop.Acceleration, entprop.RotationalVelocity); | ||
170 | } | ||
171 | */ | ||
166 | // The linkset might like to know about changing locations | 172 | // The linkset might like to know about changing locations |
167 | Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); | 173 | Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); |
168 | } | 174 | } |
@@ -176,6 +182,10 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
176 | { | 182 | { |
177 | return false; | 183 | return false; |
178 | } | 184 | } |
185 | |||
186 | // TODO: handle collisions of other objects with with children of linkset. | ||
187 | // This is a problem for LinksetCompound since the children are packed into the root. | ||
188 | |||
179 | return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); | 189 | return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); |
180 | } | 190 | } |
181 | } | 191 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index e6aefd5..dec6b6f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -56,12 +56,23 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
56 | public string BulletEngineName { get; private set; } | 56 | public string BulletEngineName { get; private set; } |
57 | public BSAPITemplate PE; | 57 | public BSAPITemplate PE; |
58 | 58 | ||
59 | // If the physics engine is running on a separate thread | ||
60 | public Thread m_physicsThread; | ||
61 | |||
59 | public Dictionary<uint, BSPhysObject> PhysObjects; | 62 | public Dictionary<uint, BSPhysObject> PhysObjects; |
60 | public BSShapeCollection Shapes; | 63 | public BSShapeCollection Shapes; |
61 | 64 | ||
62 | // Keeping track of the objects with collisions so we can report begin and end of a collision | 65 | // Keeping track of the objects with collisions so we can report begin and end of a collision |
63 | public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); | 66 | public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); |
64 | public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); | 67 | public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); |
68 | |||
69 | // All the collision processing is protected with this lock object | ||
70 | public Object CollisionLock = new Object(); | ||
71 | |||
72 | // Properties are updated here | ||
73 | public Object UpdateLock = new Object(); | ||
74 | public HashSet<BSPhysObject> ObjectsWithUpdates = new HashSet<BSPhysObject>(); | ||
75 | |||
65 | // Keep track of all the avatars so we can send them a collision event | 76 | // Keep track of all the avatars so we can send them a collision event |
66 | // every tick so OpenSim will update its animation. | 77 | // every tick so OpenSim will update its animation. |
67 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); | 78 | private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); |
@@ -77,12 +88,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
77 | public BSConstraintCollection Constraints { get; private set; } | 88 | public BSConstraintCollection Constraints { get; private set; } |
78 | 89 | ||
79 | // Simulation parameters | 90 | // Simulation parameters |
91 | internal float m_physicsStepTime; // if running independently, the interval simulated by default | ||
92 | |||
80 | internal int m_maxSubSteps; | 93 | internal int m_maxSubSteps; |
81 | internal float m_fixedTimeStep; | 94 | internal float m_fixedTimeStep; |
82 | internal long m_simulationStep = 0; | 95 | |
83 | internal float NominalFrameRate { get; set; } | 96 | internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc. |
97 | |||
98 | internal long m_simulationStep = 0; // The current simulation step. | ||
84 | public long SimulationStep { get { return m_simulationStep; } } | 99 | public long SimulationStep { get { return m_simulationStep; } } |
85 | internal float LastTimeStep { get; private set; } | 100 | |
101 | internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate() | ||
102 | |||
103 | internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to | ||
86 | 104 | ||
87 | // Physical objects can register for prestep or poststep events | 105 | // Physical objects can register for prestep or poststep events |
88 | public delegate void PreStepAction(float timeStep); | 106 | public delegate void PreStepAction(float timeStep); |
@@ -90,7 +108,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
90 | public event PreStepAction BeforeStep; | 108 | public event PreStepAction BeforeStep; |
91 | public event PostStepAction AfterStep; | 109 | public event PostStepAction AfterStep; |
92 | 110 | ||
93 | // A value of the time now so all the collision and update routines do not have to get their own | 111 | // A value of the time 'now' so all the collision and update routines do not have to get their own |
94 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 112 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
95 | public int SimulationNowTime { get; private set; } | 113 | public int SimulationNowTime { get; private set; } |
96 | 114 | ||
@@ -188,6 +206,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
188 | PhysObjects = new Dictionary<uint, BSPhysObject>(); | 206 | PhysObjects = new Dictionary<uint, BSPhysObject>(); |
189 | Shapes = new BSShapeCollection(this); | 207 | Shapes = new BSShapeCollection(this); |
190 | 208 | ||
209 | m_simulatedTime = 0f; | ||
210 | LastTimeStep = 0.1f; | ||
211 | |||
191 | // Allocate pinned memory to pass parameters. | 212 | // Allocate pinned memory to pass parameters. |
192 | UnmanagedParams = new ConfigurationParameters[1]; | 213 | UnmanagedParams = new ConfigurationParameters[1]; |
193 | 214 | ||
@@ -227,10 +248,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
227 | TerrainManager = new BSTerrainManager(this); | 248 | TerrainManager = new BSTerrainManager(this); |
228 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | 249 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); |
229 | 250 | ||
230 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); | 251 | // Put some informational messages into the log file. |
252 | m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); | ||
231 | 253 | ||
232 | InTaintTime = false; | 254 | InTaintTime = false; |
233 | m_initialized = true; | 255 | m_initialized = true; |
256 | |||
257 | // If the physics engine runs on its own thread, start same. | ||
258 | if (BSParam.UseSeparatePhysicsThread) | ||
259 | { | ||
260 | // The physics simulation should happen independently of the heartbeat loop | ||
261 | m_physicsThread = new Thread(BulletSPluginPhysicsThread); | ||
262 | m_physicsThread.Name = BulletEngineName; | ||
263 | m_physicsThread.Start(); | ||
264 | } | ||
234 | } | 265 | } |
235 | 266 | ||
236 | // All default parameter values are set here. There should be no values set in the | 267 | // All default parameter values are set here. There should be no values set in the |
@@ -268,6 +299,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
268 | // Do any replacements in the parameters | 299 | // Do any replacements in the parameters |
269 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | 300 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); |
270 | } | 301 | } |
302 | else | ||
303 | { | ||
304 | // Nothing in the configuration INI file so assume unmanaged and other defaults. | ||
305 | BulletEngineName = "BulletUnmanaged"; | ||
306 | m_physicsLoggingEnabled = false; | ||
307 | VehicleLoggingEnabled = false; | ||
308 | } | ||
271 | 309 | ||
272 | // The material characteristics. | 310 | // The material characteristics. |
273 | BSMaterials.InitializeFromDefaults(Params); | 311 | BSMaterials.InitializeFromDefaults(Params); |
@@ -311,11 +349,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
311 | 349 | ||
312 | switch (selectionName) | 350 | switch (selectionName) |
313 | { | 351 | { |
352 | case "bullet": | ||
314 | case "bulletunmanaged": | 353 | case "bulletunmanaged": |
315 | ret = new BSAPIUnman(engineName, this); | 354 | ret = new BSAPIUnman(engineName, this); |
316 | break; | 355 | break; |
317 | case "bulletxna": | 356 | case "bulletxna": |
318 | ret = new BSAPIXNA(engineName, this); | 357 | ret = new BSAPIXNA(engineName, this); |
358 | // Disable some features that are not implemented in BulletXNA | ||
359 | m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader); | ||
360 | m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader); | ||
361 | BSParam.ShouldUseBulletHACD = false; | ||
362 | m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader); | ||
363 | BSParam.ShouldUseSingleConvexHullForPrims = false; | ||
364 | m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader); | ||
365 | BSParam.ShouldUseGImpactShapeForPrims = false; | ||
366 | m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader); | ||
367 | BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap; | ||
319 | break; | 368 | break; |
320 | } | 369 | } |
321 | 370 | ||
@@ -325,7 +374,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
325 | } | 374 | } |
326 | else | 375 | else |
327 | { | 376 | { |
328 | m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); | 377 | m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); |
329 | } | 378 | } |
330 | 379 | ||
331 | return ret; | 380 | return ret; |
@@ -463,7 +512,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
463 | 512 | ||
464 | if (!m_initialized) return null; | 513 | if (!m_initialized) return null; |
465 | 514 | ||
466 | DetailLog("{0},BSScene.AddPrimShape,call", localID); | 515 | // DetailLog("{0},BSScene.AddPrimShape,call", localID); |
467 | 516 | ||
468 | BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); | 517 | BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); |
469 | lock (PhysObjects) PhysObjects.Add(localID, prim); | 518 | lock (PhysObjects) PhysObjects.Add(localID, prim); |
@@ -478,25 +527,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
478 | #endregion // Prim and Avatar addition and removal | 527 | #endregion // Prim and Avatar addition and removal |
479 | 528 | ||
480 | #region Simulation | 529 | #region Simulation |
481 | // Simulate one timestep | 530 | |
531 | // Call from the simulator to send physics information to the simulator objects. | ||
532 | // This pushes all the collision and property update events into the objects in | ||
533 | // the simulator and, since it is on the heartbeat thread, there is an implicit | ||
534 | // locking of those data structures from other heartbeat events. | ||
535 | // If the physics engine is running on a separate thread, the update information | ||
536 | // will be in the ObjectsWithCollions and ObjectsWithUpdates structures. | ||
482 | public override float Simulate(float timeStep) | 537 | public override float Simulate(float timeStep) |
483 | { | 538 | { |
539 | if (!BSParam.UseSeparatePhysicsThread) | ||
540 | { | ||
541 | DoPhysicsStep(timeStep); | ||
542 | } | ||
543 | return SendUpdatesToSimulator(timeStep); | ||
544 | } | ||
545 | |||
546 | // Call the physics engine to do one 'timeStep' and collect collisions and updates | ||
547 | // into ObjectsWithCollisions and ObjectsWithUpdates data structures. | ||
548 | private void DoPhysicsStep(float timeStep) | ||
549 | { | ||
484 | // prevent simulation until we've been initialized | 550 | // prevent simulation until we've been initialized |
485 | if (!m_initialized) return 5.0f; | 551 | if (!m_initialized) return; |
486 | 552 | ||
487 | LastTimeStep = timeStep; | 553 | LastTimeStep = timeStep; |
488 | 554 | ||
489 | int updatedEntityCount = 0; | 555 | int updatedEntityCount = 0; |
490 | int collidersCount = 0; | 556 | int collidersCount = 0; |
491 | 557 | ||
492 | int beforeTime = 0; | 558 | int beforeTime = Util.EnvironmentTickCount(); |
493 | int simTime = 0; | 559 | int simTime = 0; |
494 | 560 | ||
495 | // update the prim states while we know the physics engine is not busy | ||
496 | int numTaints = _taintOperations.Count; | 561 | int numTaints = _taintOperations.Count; |
497 | |||
498 | InTaintTime = true; // Only used for debugging so locking is not necessary. | 562 | InTaintTime = true; // Only used for debugging so locking is not necessary. |
499 | 563 | ||
564 | // update the prim states while we know the physics engine is not busy | ||
500 | ProcessTaints(); | 565 | ProcessTaints(); |
501 | 566 | ||
502 | // Some of the physical objects requre individual, pre-step calls | 567 | // Some of the physical objects requre individual, pre-step calls |
@@ -519,18 +584,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
519 | int numSubSteps = 0; | 584 | int numSubSteps = 0; |
520 | try | 585 | try |
521 | { | 586 | { |
522 | if (PhysicsLogging.Enabled) | ||
523 | beforeTime = Util.EnvironmentTickCount(); | ||
524 | |||
525 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); | 587 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); |
526 | 588 | ||
527 | if (PhysicsLogging.Enabled) | ||
528 | { | ||
529 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
530 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | ||
531 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
532 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
533 | } | ||
534 | } | 589 | } |
535 | catch (Exception e) | 590 | catch (Exception e) |
536 | { | 591 | { |
@@ -542,77 +597,62 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
542 | collidersCount = 0; | 597 | collidersCount = 0; |
543 | } | 598 | } |
544 | 599 | ||
600 | // Make the physics engine dump useful statistics periodically | ||
545 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) | 601 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) |
546 | PE.DumpPhysicsStatistics(World); | 602 | PE.DumpPhysicsStatistics(World); |
547 | 603 | ||
548 | // Get a value for 'now' so all the collision and update routines don't have to get their own. | 604 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
549 | SimulationNowTime = Util.EnvironmentTickCount(); | 605 | SimulationNowTime = Util.EnvironmentTickCount(); |
550 | 606 | ||
551 | // If there were collisions, process them by sending the event to the prim. | 607 | // Send collision information to the colliding objects. The objects decide if the collision |
552 | // Collisions must be processed before updates. | 608 | // is 'real' (like linksets don't collide with themselves) and the individual objects |
553 | if (collidersCount > 0) | 609 | // know if the simulator has subscribed to collisions. |
610 | lock (CollisionLock) | ||
554 | { | 611 | { |
555 | for (int ii = 0; ii < collidersCount; ii++) | 612 | if (collidersCount > 0) |
556 | { | 613 | { |
557 | uint cA = m_collisionArray[ii].aID; | 614 | for (int ii = 0; ii < collidersCount; ii++) |
558 | uint cB = m_collisionArray[ii].bID; | ||
559 | Vector3 point = m_collisionArray[ii].point; | ||
560 | Vector3 normal = m_collisionArray[ii].normal; | ||
561 | float penetration = m_collisionArray[ii].penetration; | ||
562 | SendCollision(cA, cB, point, normal, penetration); | ||
563 | SendCollision(cB, cA, point, -normal, penetration); | ||
564 | } | ||
565 | } | ||
566 | |||
567 | // The above SendCollision's batch up the collisions on the objects. | ||
568 | // Now push the collisions into the simulator. | ||
569 | if (ObjectsWithCollisions.Count > 0) | ||
570 | { | ||
571 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | ||
572 | if (!bsp.SendCollisions()) | ||
573 | { | 615 | { |
574 | // If the object is done colliding, see that it's removed from the colliding list | 616 | uint cA = m_collisionArray[ii].aID; |
575 | ObjectsWithNoMoreCollisions.Add(bsp); | 617 | uint cB = m_collisionArray[ii].bID; |
618 | Vector3 point = m_collisionArray[ii].point; | ||
619 | Vector3 normal = m_collisionArray[ii].normal; | ||
620 | float penetration = m_collisionArray[ii].penetration; | ||
621 | SendCollision(cA, cB, point, normal, penetration); | ||
622 | SendCollision(cB, cA, point, -normal, penetration); | ||
576 | } | 623 | } |
624 | } | ||
577 | } | 625 | } |
578 | 626 | ||
579 | // This is a kludge to get avatar movement updates. | 627 | // If any of the objects had updated properties, tell the managed objects about the update |
580 | // The simulator expects collisions for avatars even if there are have been no collisions. | 628 | // and remember that there was a change so it will be passed to the simulator. |
581 | // The event updates avatar animations and stuff. | 629 | lock (UpdateLock) |
582 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
583 | foreach (BSPhysObject bsp in m_avatars) | ||
584 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
585 | bsp.SendCollisions(); | ||
586 | |||
587 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
588 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
589 | // This complex collision processing is required to create an empty collision | ||
590 | // event call after all real collisions have happened on an object. This enables | ||
591 | // the simulator to generate the 'collision end' event. | ||
592 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
593 | { | ||
594 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
595 | ObjectsWithCollisions.Remove(po); | ||
596 | ObjectsWithNoMoreCollisions.Clear(); | ||
597 | } | ||
598 | // Done with collisions. | ||
599 | |||
600 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | ||
601 | if (updatedEntityCount > 0) | ||
602 | { | 630 | { |
603 | for (int ii = 0; ii < updatedEntityCount; ii++) | 631 | if (updatedEntityCount > 0) |
604 | { | 632 | { |
605 | EntityProperties entprop = m_updateArray[ii]; | 633 | for (int ii = 0; ii < updatedEntityCount; ii++) |
606 | BSPhysObject pobj; | ||
607 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
608 | { | 634 | { |
609 | pobj.UpdateProperties(entprop); | 635 | EntityProperties entprop = m_updateArray[ii]; |
636 | BSPhysObject pobj; | ||
637 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
638 | { | ||
639 | pobj.UpdateProperties(entprop); | ||
640 | } | ||
610 | } | 641 | } |
611 | } | 642 | } |
612 | } | 643 | } |
613 | 644 | ||
645 | // Some actors want to know when the simulation step is complete. | ||
614 | TriggerPostStepEvent(timeStep); | 646 | TriggerPostStepEvent(timeStep); |
615 | 647 | ||
648 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
649 | if (PhysicsLogging.Enabled) | ||
650 | { | ||
651 | DetailLog("{0},DoPhysicsStep,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | ||
652 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
653 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
654 | } | ||
655 | |||
616 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 656 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
617 | // Only enable this in a limited test world with few objects. | 657 | // Only enable this in a limited test world with few objects. |
618 | if (m_physicsPhysicalDumpEnabled) | 658 | if (m_physicsPhysicalDumpEnabled) |
@@ -621,7 +661,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
621 | // The physics engine returns the number of milliseconds it simulated this call. | 661 | // The physics engine returns the number of milliseconds it simulated this call. |
622 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 662 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
623 | // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). | 663 | // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). |
624 | return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; | 664 | m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; |
665 | } | ||
666 | |||
667 | // Called by a BSPhysObject to note that it has changed properties and this information | ||
668 | // should be passed up to the simulator at the proper time. | ||
669 | // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so | ||
670 | // this is is under UpdateLock. | ||
671 | public void PostUpdate(BSPhysObject updatee) | ||
672 | { | ||
673 | ObjectsWithUpdates.Add(updatee); | ||
674 | } | ||
675 | |||
676 | // The simulator thinks it is physics time so return all the collisions and position | ||
677 | // updates that were collected in actual physics simulation. | ||
678 | private float SendUpdatesToSimulator(float timeStep) | ||
679 | { | ||
680 | if (!m_initialized) return 5.0f; | ||
681 | |||
682 | DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}", | ||
683 | BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime); | ||
684 | // Push the collisions into the simulator. | ||
685 | lock (CollisionLock) | ||
686 | { | ||
687 | if (ObjectsWithCollisions.Count > 0) | ||
688 | { | ||
689 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | ||
690 | if (!bsp.SendCollisions()) | ||
691 | { | ||
692 | // If the object is done colliding, see that it's removed from the colliding list | ||
693 | ObjectsWithNoMoreCollisions.Add(bsp); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | // This is a kludge to get avatar movement updates. | ||
698 | // The simulator expects collisions for avatars even if there are have been no collisions. | ||
699 | // The event updates avatar animations and stuff. | ||
700 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
701 | foreach (BSPhysObject bsp in m_avatars) | ||
702 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
703 | bsp.SendCollisions(); | ||
704 | |||
705 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
706 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
707 | // This complex collision processing is required to create an empty collision | ||
708 | // event call after all real collisions have happened on an object. This allows | ||
709 | // the simulator to generate the 'collision end' event. | ||
710 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
711 | { | ||
712 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
713 | ObjectsWithCollisions.Remove(po); | ||
714 | ObjectsWithNoMoreCollisions.Clear(); | ||
715 | } | ||
716 | } | ||
717 | |||
718 | // Call the simulator for each object that has physics property updates. | ||
719 | HashSet<BSPhysObject> updatedObjects = null; | ||
720 | lock (UpdateLock) | ||
721 | { | ||
722 | if (ObjectsWithUpdates.Count > 0) | ||
723 | { | ||
724 | updatedObjects = ObjectsWithUpdates; | ||
725 | ObjectsWithUpdates = new HashSet<BSPhysObject>(); | ||
726 | } | ||
727 | } | ||
728 | if (updatedObjects != null) | ||
729 | { | ||
730 | foreach (BSPhysObject obj in updatedObjects) | ||
731 | { | ||
732 | obj.RequestPhysicsterseUpdate(); | ||
733 | } | ||
734 | updatedObjects.Clear(); | ||
735 | } | ||
736 | |||
737 | // Return the framerate simulated to give the above returned results. | ||
738 | // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock). | ||
739 | float simTime = m_simulatedTime; | ||
740 | m_simulatedTime = 0f; | ||
741 | return simTime; | ||
625 | } | 742 | } |
626 | 743 | ||
627 | // Something has collided | 744 | // Something has collided |
@@ -640,7 +757,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
640 | return; | 757 | return; |
641 | } | 758 | } |
642 | 759 | ||
643 | // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. | 760 | // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called. |
644 | BSPhysObject collidee = null; | 761 | BSPhysObject collidee = null; |
645 | PhysObjects.TryGetValue(collidingWith, out collidee); | 762 | PhysObjects.TryGetValue(collidingWith, out collidee); |
646 | 763 | ||
@@ -648,13 +765,39 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
648 | 765 | ||
649 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) | 766 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) |
650 | { | 767 | { |
651 | // If a collision was posted, remember to send it to the simulator | 768 | // If a collision was 'good', remember to send it to the simulator |
652 | ObjectsWithCollisions.Add(collider); | 769 | ObjectsWithCollisions.Add(collider); |
653 | } | 770 | } |
654 | 771 | ||
655 | return; | 772 | return; |
656 | } | 773 | } |
657 | 774 | ||
775 | public void BulletSPluginPhysicsThread() | ||
776 | { | ||
777 | while (m_initialized) | ||
778 | { | ||
779 | int beginSimulationRealtimeMS = Util.EnvironmentTickCount(); | ||
780 | DoPhysicsStep(BSParam.PhysicsTimeStep); | ||
781 | int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS); | ||
782 | int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS; | ||
783 | |||
784 | if (simulationTimeVsRealtimeDifferenceMS > 0) | ||
785 | { | ||
786 | // The simulation of the time interval took less than realtime. | ||
787 | // Do a sleep for the rest of realtime. | ||
788 | DetailLog("{0},BulletSPluginPhysicsThread,sleeping={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); | ||
789 | Thread.Sleep(simulationTimeVsRealtimeDifferenceMS); | ||
790 | } | ||
791 | else | ||
792 | { | ||
793 | // The simulation took longer than realtime. | ||
794 | // Do some scaling of simulation time. | ||
795 | // TODO. | ||
796 | DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); | ||
797 | } | ||
798 | } | ||
799 | } | ||
800 | |||
658 | #endregion // Simulation | 801 | #endregion // Simulation |
659 | 802 | ||
660 | public override void GetResults() { } | 803 | public override void GetResults() { } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 220fbbc..32bbc8f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -38,38 +38,15 @@ public sealed class BSShapeCollection : IDisposable | |||
38 | { | 38 | { |
39 | private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; | 39 | private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; |
40 | 40 | ||
41 | private BSScene PhysicsScene { get; set; } | 41 | private BSScene m_physicsScene { get; set; } |
42 | 42 | ||
43 | private Object m_collectionActivityLock = new Object(); | 43 | private Object m_collectionActivityLock = new Object(); |
44 | 44 | ||
45 | // Description of a Mesh | ||
46 | private struct MeshDesc | ||
47 | { | ||
48 | public BulletShape shape; | ||
49 | public int referenceCount; | ||
50 | public DateTime lastReferenced; | ||
51 | public UInt64 shapeKey; | ||
52 | } | ||
53 | |||
54 | // Description of a hull. | ||
55 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. | ||
56 | private struct HullDesc | ||
57 | { | ||
58 | public BulletShape shape; | ||
59 | public int referenceCount; | ||
60 | public DateTime lastReferenced; | ||
61 | public UInt64 shapeKey; | ||
62 | } | ||
63 | |||
64 | // The sharable set of meshes and hulls. Indexed by their shape hash. | ||
65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); | ||
66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); | ||
67 | |||
68 | private bool DDetail = false; | 45 | private bool DDetail = false; |
69 | 46 | ||
70 | public BSShapeCollection(BSScene physScene) | 47 | public BSShapeCollection(BSScene physScene) |
71 | { | 48 | { |
72 | PhysicsScene = physScene; | 49 | m_physicsScene = physScene; |
73 | // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) | 50 | // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) |
74 | // While detailed debugging is still active, this is better than commenting out all the | 51 | // While detailed debugging is still active, this is better than commenting out all the |
75 | // DetailLog statements. When debugging slows down, this and the protected logging | 52 | // DetailLog statements. When debugging slows down, this and the protected logging |
@@ -86,22 +63,18 @@ public sealed class BSShapeCollection : IDisposable | |||
86 | // Mostly used for changing bodies out from under Linksets. | 63 | // Mostly used for changing bodies out from under Linksets. |
87 | // Useful for other cases where parameters need saving. | 64 | // Useful for other cases where parameters need saving. |
88 | // Passing 'null' says no callback. | 65 | // Passing 'null' says no callback. |
89 | public delegate void ShapeDestructionCallback(BulletShape shape); | 66 | public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape); |
90 | public delegate void BodyDestructionCallback(BulletBody body); | ||
91 | 67 | ||
92 | // Called to update/change the body and shape for an object. | 68 | // Called to update/change the body and shape for an object. |
93 | // First checks the shape and updates that if necessary then makes | 69 | // The object has some shape and body on it. Here we decide if that is the correct shape |
94 | // sure the body is of the right type. | 70 | // for the current state of the object (static/dynamic/...). |
71 | // If bodyCallback is not null, it is called if either the body or the shape are changed | ||
72 | // so dependencies (like constraints) can be removed before the physical object is dereferenced. | ||
95 | // Return 'true' if either the body or the shape changed. | 73 | // Return 'true' if either the body or the shape changed. |
96 | // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before | 74 | // Called at taint-time. |
97 | // the current shape or body is destroyed. This allows the caller to remove any | 75 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback) |
98 | // higher level dependencies on the shape or body. Mostly used for LinkSets to | ||
99 | // remove the physical constraints before the body is destroyed. | ||
100 | // Called at taint-time!! | ||
101 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, | ||
102 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) | ||
103 | { | 76 | { |
104 | PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); | 77 | m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); |
105 | 78 | ||
106 | bool ret = false; | 79 | bool ret = false; |
107 | 80 | ||
@@ -111,12 +84,12 @@ public sealed class BSShapeCollection : IDisposable | |||
111 | // Do we have the correct geometry for this type of object? | 84 | // Do we have the correct geometry for this type of object? |
112 | // Updates prim.BSShape with information/pointers to shape. | 85 | // Updates prim.BSShape with information/pointers to shape. |
113 | // Returns 'true' of BSShape is changed to a new shape. | 86 | // Returns 'true' of BSShape is changed to a new shape. |
114 | bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback); | 87 | bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback); |
115 | // If we had to select a new shape geometry for the object, | 88 | // If we had to select a new shape geometry for the object, |
116 | // rebuild the body around it. | 89 | // rebuild the body around it. |
117 | // Updates prim.BSBody with information/pointers to requested body | 90 | // Updates prim.BSBody with information/pointers to requested body |
118 | // Returns 'true' if BSBody was changed. | 91 | // Returns 'true' if BSBody was changed. |
119 | bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bodyCallback); | 92 | bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback); |
120 | ret = newGeom || newBody; | 93 | ret = newGeom || newBody; |
121 | } | 94 | } |
122 | DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", | 95 | DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", |
@@ -127,274 +100,20 @@ public sealed class BSShapeCollection : IDisposable | |||
127 | 100 | ||
128 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) | 101 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) |
129 | { | 102 | { |
130 | return GetBodyAndShape(forceRebuild, sim, prim, null, null); | 103 | return GetBodyAndShape(forceRebuild, sim, prim, null); |
131 | } | ||
132 | |||
133 | // Track another user of a body. | ||
134 | // We presume the caller has allocated the body. | ||
135 | // Bodies only have one user so the body is just put into the world if not already there. | ||
136 | private void ReferenceBody(BulletBody body) | ||
137 | { | ||
138 | lock (m_collectionActivityLock) | ||
139 | { | ||
140 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); | ||
141 | if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) | ||
142 | { | ||
143 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body); | ||
144 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | // Release the usage of a body. | ||
150 | // Called when releasing use of a BSBody. BSShape is handled separately. | ||
151 | // Called in taint time. | ||
152 | public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback ) | ||
153 | { | ||
154 | if (!body.HasPhysicalBody) | ||
155 | return; | ||
156 | |||
157 | PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody"); | ||
158 | |||
159 | lock (m_collectionActivityLock) | ||
160 | { | ||
161 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); | ||
162 | // If the caller needs to know the old body is going away, pass the event up. | ||
163 | if (bodyCallback != null) bodyCallback(body); | ||
164 | |||
165 | if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) | ||
166 | { | ||
167 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body); | ||
168 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); | ||
169 | } | ||
170 | |||
171 | // Zero any reference to the shape so it is not freed when the body is deleted. | ||
172 | PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null); | ||
173 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, body); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | // Track the datastructures and use count for a shape. | ||
178 | // When creating a hull, this is called first to reference the mesh | ||
179 | // and then again to reference the hull. | ||
180 | // Meshes and hulls for the same shape have the same hash key. | ||
181 | // NOTE that native shapes are not added to the mesh list or removed. | ||
182 | // Returns 'true' if this is the initial reference to the shape. Otherwise reused. | ||
183 | public bool ReferenceShape(BulletShape shape) | ||
184 | { | ||
185 | bool ret = false; | ||
186 | switch (shape.type) | ||
187 | { | ||
188 | case BSPhysicsShapeType.SHAPE_MESH: | ||
189 | MeshDesc meshDesc; | ||
190 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) | ||
191 | { | ||
192 | // There is an existing instance of this mesh. | ||
193 | meshDesc.referenceCount++; | ||
194 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", | ||
195 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | // This is a new reference to a mesh | ||
200 | meshDesc.shape = shape.Clone(); | ||
201 | meshDesc.shapeKey = shape.shapeKey; | ||
202 | // We keep a reference to the underlying IMesh data so a hull can be built | ||
203 | meshDesc.referenceCount = 1; | ||
204 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", | ||
205 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | ||
206 | ret = true; | ||
207 | } | ||
208 | meshDesc.lastReferenced = System.DateTime.Now; | ||
209 | Meshes[shape.shapeKey] = meshDesc; | ||
210 | break; | ||
211 | case BSPhysicsShapeType.SHAPE_HULL: | ||
212 | HullDesc hullDesc; | ||
213 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) | ||
214 | { | ||
215 | // There is an existing instance of this hull. | ||
216 | hullDesc.referenceCount++; | ||
217 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", | ||
218 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | ||
219 | } | ||
220 | else | ||
221 | { | ||
222 | // This is a new reference to a hull | ||
223 | hullDesc.shape = shape.Clone(); | ||
224 | hullDesc.shapeKey = shape.shapeKey; | ||
225 | hullDesc.referenceCount = 1; | ||
226 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", | ||
227 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | ||
228 | ret = true; | ||
229 | |||
230 | } | ||
231 | hullDesc.lastReferenced = System.DateTime.Now; | ||
232 | Hulls[shape.shapeKey] = hullDesc; | ||
233 | break; | ||
234 | case BSPhysicsShapeType.SHAPE_UNKNOWN: | ||
235 | break; | ||
236 | default: | ||
237 | // Native shapes are not tracked and they don't go into any list | ||
238 | break; | ||
239 | } | ||
240 | return ret; | ||
241 | } | 104 | } |
242 | 105 | ||
243 | // Release the usage of a shape. | 106 | // If the existing prim's shape is to be replaced, remove the tie to the existing shape |
244 | public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback) | 107 | // before replacing it. |
108 | private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) | ||
245 | { | 109 | { |
246 | if (!shape.HasPhysicalShape) | 110 | if (prim.PhysShape.HasPhysicalShape) |
247 | return; | ||
248 | |||
249 | PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape"); | ||
250 | |||
251 | if (shape.HasPhysicalShape) | ||
252 | { | ||
253 | if (shape.isNativeShape) | ||
254 | { | ||
255 | // Native shapes are not tracked and are released immediately | ||
256 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}", | ||
257 | BSScene.DetailLogZero, shape.AddrString); | ||
258 | if (shapeCallback != null) shapeCallback(shape); | ||
259 | PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); | ||
260 | } | ||
261 | else | ||
262 | { | ||
263 | switch (shape.type) | ||
264 | { | ||
265 | case BSPhysicsShapeType.SHAPE_HULL: | ||
266 | DereferenceHull(shape, shapeCallback); | ||
267 | break; | ||
268 | case BSPhysicsShapeType.SHAPE_MESH: | ||
269 | DereferenceMesh(shape, shapeCallback); | ||
270 | break; | ||
271 | case BSPhysicsShapeType.SHAPE_COMPOUND: | ||
272 | DereferenceCompound(shape, shapeCallback); | ||
273 | break; | ||
274 | case BSPhysicsShapeType.SHAPE_UNKNOWN: | ||
275 | break; | ||
276 | default: | ||
277 | break; | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | |||
283 | // Count down the reference count for a mesh shape | ||
284 | // Called at taint-time. | ||
285 | private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
286 | { | ||
287 | MeshDesc meshDesc; | ||
288 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) | ||
289 | { | 111 | { |
290 | meshDesc.referenceCount--; | 112 | if (shapeCallback != null) |
291 | // TODO: release the Bullet storage | 113 | shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo); |
292 | if (shapeCallback != null) shapeCallback(shape); | 114 | prim.PhysShape.Dereference(m_physicsScene); |
293 | meshDesc.lastReferenced = System.DateTime.Now; | ||
294 | Meshes[shape.shapeKey] = meshDesc; | ||
295 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", | ||
296 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); | ||
297 | |||
298 | } | ||
299 | } | ||
300 | |||
301 | // Count down the reference count for a hull shape | ||
302 | // Called at taint-time. | ||
303 | private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
304 | { | ||
305 | HullDesc hullDesc; | ||
306 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) | ||
307 | { | ||
308 | hullDesc.referenceCount--; | ||
309 | // TODO: release the Bullet storage (aging old entries?) | ||
310 | |||
311 | // Tell upper layers that, if they have dependencies on this shape, this link is going away | ||
312 | if (shapeCallback != null) shapeCallback(shape); | ||
313 | |||
314 | hullDesc.lastReferenced = System.DateTime.Now; | ||
315 | Hulls[shape.shapeKey] = hullDesc; | ||
316 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", | ||
317 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); | ||
318 | } | ||
319 | } | ||
320 | |||
321 | // Remove a reference to a compound shape. | ||
322 | // Taking a compound shape apart is a little tricky because if you just delete the | ||
323 | // physical shape, it will free all the underlying children. We can't do that because | ||
324 | // they could be shared. So, this removes each of the children from the compound and | ||
325 | // dereferences them separately before destroying the compound collision object itself. | ||
326 | // Called at taint-time. | ||
327 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
328 | { | ||
329 | if (!PhysicsScene.PE.IsCompound(shape)) | ||
330 | { | ||
331 | // Failed the sanity check!! | ||
332 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | ||
333 | LogHeader, shape.type, shape.AddrString); | ||
334 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | ||
335 | BSScene.DetailLogZero, shape.type, shape.AddrString); | ||
336 | return; | ||
337 | } | ||
338 | |||
339 | int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape); | ||
340 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); | ||
341 | |||
342 | for (int ii = numChildren - 1; ii >= 0; ii--) | ||
343 | { | ||
344 | BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii); | ||
345 | DereferenceAnonCollisionShape(childShape); | ||
346 | } | ||
347 | PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); | ||
348 | } | ||
349 | |||
350 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | ||
351 | // Figure out type and call the correct dereference routine. | ||
352 | // Called at taint-time. | ||
353 | private void DereferenceAnonCollisionShape(BulletShape shapeInfo) | ||
354 | { | ||
355 | MeshDesc meshDesc; | ||
356 | HullDesc hullDesc; | ||
357 | |||
358 | if (TryGetMeshByPtr(shapeInfo, out meshDesc)) | ||
359 | { | ||
360 | shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; | ||
361 | shapeInfo.shapeKey = meshDesc.shapeKey; | ||
362 | } | ||
363 | else | ||
364 | { | ||
365 | if (TryGetHullByPtr(shapeInfo, out hullDesc)) | ||
366 | { | ||
367 | shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; | ||
368 | shapeInfo.shapeKey = hullDesc.shapeKey; | ||
369 | } | ||
370 | else | ||
371 | { | ||
372 | if (PhysicsScene.PE.IsCompound(shapeInfo)) | ||
373 | { | ||
374 | shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | if (PhysicsScene.PE.IsNativeShape(shapeInfo)) | ||
379 | { | ||
380 | shapeInfo.isNativeShape = true; | ||
381 | shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) | ||
382 | } | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | |||
387 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); | ||
388 | |||
389 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) | ||
390 | { | ||
391 | DereferenceShape(shapeInfo, null); | ||
392 | } | ||
393 | else | ||
394 | { | ||
395 | PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", | ||
396 | LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString); | ||
397 | } | 115 | } |
116 | prim.PhysShape = new BSShapeNull(); | ||
398 | } | 117 | } |
399 | 118 | ||
400 | // Create the geometry information in Bullet for later use. | 119 | // Create the geometry information in Bullet for later use. |
@@ -405,60 +124,41 @@ public sealed class BSShapeCollection : IDisposable | |||
405 | // Info in prim.BSShape is updated to the new shape. | 124 | // Info in prim.BSShape is updated to the new shape. |
406 | // Returns 'true' if the geometry was rebuilt. | 125 | // Returns 'true' if the geometry was rebuilt. |
407 | // Called at taint-time! | 126 | // Called at taint-time! |
408 | private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 127 | private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback) |
409 | { | 128 | { |
410 | bool ret = false; | 129 | bool ret = false; |
411 | bool haveShape = false; | 130 | bool haveShape = false; |
131 | bool nativeShapePossible = true; | ||
132 | PrimitiveBaseShape pbs = prim.BaseShape; | ||
412 | 133 | ||
413 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) | 134 | // Kludge to create the capsule for the avatar. |
135 | // TDOD: Remove/redo this when BSShapeAvatar is working!! | ||
136 | BSCharacter theChar = prim as BSCharacter; | ||
137 | if (theChar != null) | ||
414 | { | 138 | { |
415 | // an avatar capsule is close to a native shape (it is not shared) | 139 | DereferenceExistingShape(prim, shapeCallback); |
416 | GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback); | 140 | prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, |
417 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); | 141 | BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE); |
418 | ret = true; | 142 | ret = true; |
419 | haveShape = true; | 143 | haveShape = true; |
420 | } | 144 | } |
421 | 145 | ||
422 | // Compound shapes are handled special as they are rebuilt from scratch. | ||
423 | // This isn't too great a hardship since most of the child shapes will have already been created. | ||
424 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | ||
425 | { | ||
426 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | ||
427 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | ||
428 | haveShape = true; | ||
429 | } | ||
430 | |||
431 | if (!haveShape) | ||
432 | { | ||
433 | ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback); | ||
434 | } | ||
435 | |||
436 | return ret; | ||
437 | } | ||
438 | |||
439 | // Create a mesh, hull or native shape. | ||
440 | // Return 'true' if the prim's shape was changed. | ||
441 | public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
442 | { | ||
443 | bool ret = false; | ||
444 | bool haveShape = false; | ||
445 | bool nativeShapePossible = true; | ||
446 | PrimitiveBaseShape pbs = prim.BaseShape; | ||
447 | |||
448 | // If the prim attributes are simple, this could be a simple Bullet native shape | 146 | // If the prim attributes are simple, this could be a simple Bullet native shape |
147 | // Native shapes work whether to object is static or physical. | ||
449 | if (!haveShape | 148 | if (!haveShape |
450 | && nativeShapePossible | 149 | && nativeShapePossible |
451 | && pbs != null | 150 | && pbs != null |
452 | && !pbs.SculptEntry | 151 | && PrimHasNoCuts(pbs) |
453 | && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) ) | 152 | && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) ) |
153 | ) | ||
454 | { | 154 | { |
455 | // Get the scale of any existing shape so we can see if the new shape is same native type and same size. | 155 | // Get the scale of any existing shape so we can see if the new shape is same native type and same size. |
456 | OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; | 156 | OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; |
457 | if (prim.PhysShape.HasPhysicalShape) | 157 | if (prim.PhysShape.HasPhysicalShape) |
458 | scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); | 158 | scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo); |
459 | 159 | ||
460 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", | 160 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", |
461 | prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); | 161 | prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType); |
462 | 162 | ||
463 | // It doesn't look like Bullet scales native spheres so make sure the scales are all equal | 163 | // It doesn't look like Bullet scales native spheres so make sure the scales are all equal |
464 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | 164 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) |
@@ -466,26 +166,30 @@ public sealed class BSShapeCollection : IDisposable | |||
466 | { | 166 | { |
467 | haveShape = true; | 167 | haveShape = true; |
468 | if (forceRebuild | 168 | if (forceRebuild |
469 | || prim.Scale != scaleOfExistingShape | 169 | || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE |
470 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE | 170 | ) |
471 | ) | ||
472 | { | 171 | { |
473 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, | 172 | DereferenceExistingShape(prim, shapeCallback); |
474 | FixedShapeKey.KEY_SPHERE, shapeCallback); | 173 | prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, |
174 | BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE); | ||
175 | ret = true; | ||
475 | } | 176 | } |
476 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", | 177 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", |
477 | prim.LocalID, forceRebuild, ret, prim.PhysShape); | 178 | prim.LocalID, forceRebuild, ret, prim.PhysShape); |
478 | } | 179 | } |
180 | // If we didn't make a sphere, maybe a box will work. | ||
479 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | 181 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) |
480 | { | 182 | { |
481 | haveShape = true; | 183 | haveShape = true; |
482 | if (forceRebuild | 184 | if (forceRebuild |
483 | || prim.Scale != scaleOfExistingShape | 185 | || prim.Scale != scaleOfExistingShape |
484 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX | 186 | || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX |
485 | ) | 187 | ) |
486 | { | 188 | { |
487 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, | 189 | DereferenceExistingShape(prim, shapeCallback); |
488 | FixedShapeKey.KEY_BOX, shapeCallback); | 190 | prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, |
191 | BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
192 | ret = true; | ||
489 | } | 193 | } |
490 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", | 194 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", |
491 | prim.LocalID, forceRebuild, ret, prim.PhysShape); | 195 | prim.LocalID, forceRebuild, ret, prim.PhysShape); |
@@ -502,7 +206,7 @@ public sealed class BSShapeCollection : IDisposable | |||
502 | } | 206 | } |
503 | 207 | ||
504 | // return 'true' if this shape description does not include any cutting or twisting. | 208 | // return 'true' if this shape description does not include any cutting or twisting. |
505 | private bool PrimHasNoCuts(PrimitiveBaseShape pbs) | 209 | public static bool PrimHasNoCuts(PrimitiveBaseShape pbs) |
506 | { | 210 | { |
507 | return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | 211 | return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 |
508 | && pbs.ProfileHollow == 0 | 212 | && pbs.ProfileHollow == 0 |
@@ -514,7 +218,7 @@ public sealed class BSShapeCollection : IDisposable | |||
514 | } | 218 | } |
515 | 219 | ||
516 | // return 'true' if the prim's shape was changed. | 220 | // return 'true' if the prim's shape was changed. |
517 | public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 221 | private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) |
518 | { | 222 | { |
519 | 223 | ||
520 | bool ret = false; | 224 | bool ret = false; |
@@ -522,503 +226,121 @@ public sealed class BSShapeCollection : IDisposable | |||
522 | // made. Native shapes work in either case. | 226 | // made. Native shapes work in either case. |
523 | if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) | 227 | if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) |
524 | { | 228 | { |
525 | // Update prim.BSShape to reference a hull of this shape. | 229 | // Use a simple, single mesh convex hull shape if the object is simple enough |
526 | ret = GetReferenceToHull(prim, shapeCallback); | 230 | BSShape potentialHull = null; |
527 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", | ||
528 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | ||
529 | } | ||
530 | else | ||
531 | { | ||
532 | ret = GetReferenceToMesh(prim, shapeCallback); | ||
533 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", | ||
534 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | ||
535 | } | ||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | // Creates a native shape and assignes it to prim.BSShape. | ||
540 | // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). | ||
541 | private bool GetReferenceToNativeShape(BSPhysObject prim, | ||
542 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey, | ||
543 | ShapeDestructionCallback shapeCallback) | ||
544 | { | ||
545 | // release any previous shape | ||
546 | DereferenceShape(prim.PhysShape, shapeCallback); | ||
547 | |||
548 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); | ||
549 | |||
550 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | ||
551 | if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | ||
552 | prim.LocalID, newShape, prim.Scale); | ||
553 | |||
554 | // native shapes are scaled by Bullet | ||
555 | prim.PhysShape = newShape; | ||
556 | return true; | ||
557 | } | ||
558 | |||
559 | private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType, | ||
560 | FixedShapeKey shapeKey) | ||
561 | { | ||
562 | BulletShape newShape; | ||
563 | // Need to make sure the passed shape information is for the native type. | ||
564 | ShapeData nativeShapeData = new ShapeData(); | ||
565 | nativeShapeData.Type = shapeType; | ||
566 | nativeShapeData.ID = prim.LocalID; | ||
567 | nativeShapeData.Scale = prim.Scale; | ||
568 | nativeShapeData.Size = prim.Scale; // unneeded, I think. | ||
569 | nativeShapeData.MeshKey = (ulong)shapeKey; | ||
570 | nativeShapeData.HullKey = (ulong)shapeKey; | ||
571 | |||
572 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | ||
573 | { | ||
574 | 231 | ||
575 | newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale); | 232 | PrimitiveBaseShape pbs = prim.BaseShape; |
576 | if (DDetail) DetailLog("{0},BSShapeCollection.BuildPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | 233 | // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists) |
577 | } | 234 | if (BSParam.ShouldUseSingleConvexHullForPrims |
578 | else | 235 | && pbs != null |
579 | { | 236 | && !pbs.SculptEntry |
580 | // Native shapes are scaled in Bullet so set the scaling to the size | 237 | && PrimHasNoCuts(pbs) |
581 | newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData); | 238 | ) |
582 | 239 | { | |
583 | } | 240 | potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim); |
584 | if (!newShape.HasPhysicalShape) | 241 | } |
585 | { | 242 | // Use the GImpact shape if it is a prim that has some concaveness |
586 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | 243 | if (potentialHull == null |
587 | LogHeader, prim.LocalID, shapeType); | 244 | && BSParam.ShouldUseGImpactShapeForPrims |
588 | } | 245 | && pbs != null |
589 | newShape.shapeKey = (System.UInt64)shapeKey; | 246 | && !pbs.SculptEntry |
590 | newShape.isNativeShape = true; | 247 | ) |
591 | 248 | { | |
592 | return newShape; | 249 | potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim); |
593 | } | 250 | } |
594 | 251 | // If not any of the simple cases, just make a hull | |
595 | // Builds a mesh shape in the physical world and updates prim.BSShape. | 252 | if (potentialHull == null) |
596 | // Dereferences previous shape in BSShape and adds a reference for this new shape. | 253 | { |
597 | // Returns 'true' of a mesh was actually built. Otherwise . | 254 | potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); |
598 | // Called at taint-time! | 255 | } |
599 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
600 | { | ||
601 | BulletShape newShape = new BulletShape(); | ||
602 | |||
603 | float lod; | ||
604 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
605 | |||
606 | // if this new shape is the same as last time, don't recreate the mesh | ||
607 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) | ||
608 | return false; | ||
609 | |||
610 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2},size={3},lod={4}", | ||
611 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod); | ||
612 | |||
613 | // Since we're recreating new, get rid of the reference to the previous shape | ||
614 | DereferenceShape(prim.PhysShape, shapeCallback); | ||
615 | |||
616 | newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod); | ||
617 | // Take evasive action if the mesh was not constructed. | ||
618 | newShape = VerifyMeshCreated(newShape, prim); | ||
619 | |||
620 | ReferenceShape(newShape); | ||
621 | |||
622 | prim.PhysShape = newShape; | ||
623 | |||
624 | return true; // 'true' means a new shape has been added to this prim | ||
625 | } | ||
626 | |||
627 | private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
628 | { | ||
629 | BulletShape newShape = new BulletShape(); | ||
630 | 256 | ||
631 | MeshDesc meshDesc; | 257 | // If the current shape is not what is on the prim at the moment, time to change. |
632 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) | 258 | if (!prim.PhysShape.HasPhysicalShape |
633 | { | 259 | || potentialHull.ShapeType != prim.PhysShape.ShapeType |
634 | // If the mesh has already been built just use it. | 260 | || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) |
635 | newShape = meshDesc.shape.Clone(); | 261 | { |
262 | DereferenceExistingShape(prim, shapeCallback); | ||
263 | prim.PhysShape = potentialHull; | ||
264 | ret = true; | ||
265 | } | ||
266 | else | ||
267 | { | ||
268 | // The current shape on the prim is the correct one. We don't need the potential reference. | ||
269 | potentialHull.Dereference(m_physicsScene); | ||
270 | } | ||
271 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape); | ||
636 | } | 272 | } |
637 | else | 273 | else |
638 | { | 274 | { |
639 | IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, | 275 | // Non-physical objects should be just meshes. |
640 | true, | 276 | BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); |
641 | false, // say it is not physical so a bounding box is not built | 277 | // If the current shape is not what is on the prim at the moment, time to change. |
642 | false, // do not cache the mesh and do not use previously built versions | 278 | if (!prim.PhysShape.HasPhysicalShape |
643 | false // It's NOT for ODE | 279 | || potentialMesh.ShapeType != prim.PhysShape.ShapeType |
644 | ); | 280 | || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) |
645 | |||
646 | if (meshData != null) | ||
647 | { | 281 | { |
648 | 282 | DereferenceExistingShape(prim, shapeCallback); | |
649 | int[] indices = meshData.getIndexListAsInt(); | 283 | prim.PhysShape = potentialMesh; |
650 | int realIndicesIndex = indices.Length; | 284 | ret = true; |
651 | float[] verticesAsFloats = meshData.getVertexListAsFloat(); | ||
652 | |||
653 | if (BSParam.ShouldRemoveZeroWidthTriangles) | ||
654 | { | ||
655 | // Remove degenerate triangles. These are triangles with two of the vertices | ||
656 | // are the same. This is complicated by the problem that vertices are not | ||
657 | // made unique in sculpties so we have to compare the values in the vertex. | ||
658 | realIndicesIndex = 0; | ||
659 | for (int tri = 0; tri < indices.Length; tri += 3) | ||
660 | { | ||
661 | // Compute displacements into vertex array for each vertex of the triangle | ||
662 | int v1 = indices[tri + 0] * 3; | ||
663 | int v2 = indices[tri + 1] * 3; | ||
664 | int v3 = indices[tri + 2] * 3; | ||
665 | // Check to see if any two of the vertices are the same | ||
666 | if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] | ||
667 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] | ||
668 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) | ||
669 | || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] | ||
670 | && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] | ||
671 | && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) | ||
672 | || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] | ||
673 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] | ||
674 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) | ||
675 | ) | ||
676 | { | ||
677 | // None of the vertices of the triangles are the same. This is a good triangle; | ||
678 | indices[realIndicesIndex + 0] = indices[tri + 0]; | ||
679 | indices[realIndicesIndex + 1] = indices[tri + 1]; | ||
680 | indices[realIndicesIndex + 2] = indices[tri + 2]; | ||
681 | realIndicesIndex += 3; | ||
682 | } | ||
683 | } | ||
684 | } | ||
685 | DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}", | ||
686 | BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); | ||
687 | |||
688 | if (realIndicesIndex != 0) | ||
689 | { | ||
690 | newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, | ||
691 | realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); | ||
692 | } | ||
693 | else | ||
694 | { | ||
695 | PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", | ||
696 | LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name); | ||
697 | } | ||
698 | } | 285 | } |
286 | else | ||
287 | { | ||
288 | // We don't need this reference to the mesh that is already being using. | ||
289 | potentialMesh.Dereference(m_physicsScene); | ||
290 | } | ||
291 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape); | ||
699 | } | 292 | } |
700 | newShape.shapeKey = newMeshKey; | 293 | return ret; |
701 | |||
702 | return newShape; | ||
703 | } | ||
704 | |||
705 | // See that hull shape exists in the physical world and update prim.BSShape. | ||
706 | // We could be creating the hull because scale changed or whatever. | ||
707 | // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance. | ||
708 | private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
709 | { | ||
710 | BulletShape newShape; | ||
711 | |||
712 | float lod; | ||
713 | System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
714 | |||
715 | // if the hull hasn't changed, don't rebuild it | ||
716 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) | ||
717 | return false; | ||
718 | |||
719 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", | ||
720 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | ||
721 | |||
722 | // Remove usage of the previous shape. | ||
723 | DereferenceShape(prim.PhysShape, shapeCallback); | ||
724 | |||
725 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); | ||
726 | // It might not have been created if we're waiting for an asset. | ||
727 | newShape = VerifyMeshCreated(newShape, prim); | ||
728 | |||
729 | ReferenceShape(newShape); | ||
730 | |||
731 | prim.PhysShape = newShape; | ||
732 | return true; // 'true' means a new shape has been added to this prim | ||
733 | } | 294 | } |
734 | 295 | ||
735 | List<ConvexResult> m_hulls; | 296 | // Track another user of a body. |
736 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 297 | // We presume the caller has allocated the body. |
298 | // Bodies only have one user so the body is just put into the world if not already there. | ||
299 | private void ReferenceBody(BulletBody body) | ||
737 | { | 300 | { |
738 | 301 | lock (m_collectionActivityLock) | |
739 | BulletShape newShape = new BulletShape(); | ||
740 | IntPtr hullPtr = IntPtr.Zero; | ||
741 | |||
742 | HullDesc hullDesc; | ||
743 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | ||
744 | { | ||
745 | // If the hull shape already has been created, just use the one shared instance. | ||
746 | newShape = hullDesc.shape.Clone(); | ||
747 | } | ||
748 | else | ||
749 | { | 302 | { |
750 | // Build a new hull in the physical world. | 303 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); |
751 | // Pass true for physicalness as this prevents the creation of bounding box which is not needed | 304 | if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body)) |
752 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); | ||
753 | if (meshData != null) | ||
754 | { | 305 | { |
755 | 306 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body); | |
756 | int[] indices = meshData.getIndexListAsInt(); | 307 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); |
757 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
758 | |||
759 | //format conversion from IMesh format to DecompDesc format | ||
760 | List<int> convIndices = new List<int>(); | ||
761 | List<float3> convVertices = new List<float3>(); | ||
762 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
763 | { | ||
764 | convIndices.Add(indices[ii]); | ||
765 | } | ||
766 | foreach (OMV.Vector3 vv in vertices) | ||
767 | { | ||
768 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
769 | } | ||
770 | |||
771 | uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; | ||
772 | if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) | ||
773 | { | ||
774 | // Simple primitive shapes we know are convex so they are better implemented with | ||
775 | // fewer hulls. | ||
776 | // Check for simple shape (prim without cuts) and reduce split parameter if so. | ||
777 | if (PrimHasNoCuts(pbs)) | ||
778 | { | ||
779 | maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; | ||
780 | } | ||
781 | } | ||
782 | |||
783 | // setup and do convex hull conversion | ||
784 | m_hulls = new List<ConvexResult>(); | ||
785 | DecompDesc dcomp = new DecompDesc(); | ||
786 | dcomp.mIndices = convIndices; | ||
787 | dcomp.mVertices = convVertices; | ||
788 | dcomp.mDepth = maxDepthSplit; | ||
789 | dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; | ||
790 | dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; | ||
791 | dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; | ||
792 | dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; | ||
793 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
794 | // create the hull into the _hulls variable | ||
795 | convexBuilder.process(dcomp); | ||
796 | |||
797 | DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", | ||
798 | BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); | ||
799 | |||
800 | // Convert the vertices and indices for passing to unmanaged. | ||
801 | // The hull information is passed as a large floating point array. | ||
802 | // The format is: | ||
803 | // convHulls[0] = number of hulls | ||
804 | // convHulls[1] = number of vertices in first hull | ||
805 | // convHulls[2] = hull centroid X coordinate | ||
806 | // convHulls[3] = hull centroid Y coordinate | ||
807 | // convHulls[4] = hull centroid Z coordinate | ||
808 | // convHulls[5] = first hull vertex X | ||
809 | // convHulls[6] = first hull vertex Y | ||
810 | // convHulls[7] = first hull vertex Z | ||
811 | // convHulls[8] = second hull vertex X | ||
812 | // ... | ||
813 | // convHulls[n] = number of vertices in second hull | ||
814 | // convHulls[n+1] = second hull centroid X coordinate | ||
815 | // ... | ||
816 | // | ||
817 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
818 | // data structures that do not need to be converted in order to pass to Bullet. | ||
819 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
820 | int hullCount = m_hulls.Count; | ||
821 | int totalVertices = 1; // include one for the count of the hulls | ||
822 | foreach (ConvexResult cr in m_hulls) | ||
823 | { | ||
824 | totalVertices += 4; // add four for the vertex count and centroid | ||
825 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
826 | } | ||
827 | float[] convHulls = new float[totalVertices]; | ||
828 | |||
829 | convHulls[0] = (float)hullCount; | ||
830 | int jj = 1; | ||
831 | foreach (ConvexResult cr in m_hulls) | ||
832 | { | ||
833 | // copy vertices for index access | ||
834 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
835 | int kk = 0; | ||
836 | foreach (float3 ff in cr.HullVertices) | ||
837 | { | ||
838 | verts[kk++] = ff; | ||
839 | } | ||
840 | |||
841 | // add to the array one hull's worth of data | ||
842 | convHulls[jj++] = cr.HullIndices.Count; | ||
843 | convHulls[jj++] = 0f; // centroid x,y,z | ||
844 | convHulls[jj++] = 0f; | ||
845 | convHulls[jj++] = 0f; | ||
846 | foreach (int ind in cr.HullIndices) | ||
847 | { | ||
848 | convHulls[jj++] = verts[ind].x; | ||
849 | convHulls[jj++] = verts[ind].y; | ||
850 | convHulls[jj++] = verts[ind].z; | ||
851 | } | ||
852 | } | ||
853 | // create the hull data structure in Bullet | ||
854 | newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls); | ||
855 | } | 308 | } |
856 | } | 309 | } |
857 | |||
858 | newShape.shapeKey = newHullKey; | ||
859 | |||
860 | return newShape; | ||
861 | } | ||
862 | |||
863 | // Callback from convex hull creater with a newly created hull. | ||
864 | // Just add it to our collection of hulls for this shape. | ||
865 | private void HullReturn(ConvexResult result) | ||
866 | { | ||
867 | m_hulls.Add(result); | ||
868 | return; | ||
869 | } | 310 | } |
870 | 311 | ||
871 | // Compound shapes are always built from scratch. | 312 | // Release the usage of a body. |
872 | // This shouldn't be to bad since most of the parts will be meshes that had been built previously. | 313 | // Called when releasing use of a BSBody. BSShape is handled separately. |
873 | private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 314 | // Called in taint time. |
874 | { | 315 | public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback ) |
875 | // Remove reference to the old shape | ||
876 | // Don't need to do this as the shape is freed when the new root shape is created below. | ||
877 | // DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
878 | |||
879 | BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false); | ||
880 | |||
881 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. | ||
882 | CreateGeomMeshOrHull(prim, shapeCallback); | ||
883 | PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity); | ||
884 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", | ||
885 | prim.LocalID, cShape, prim.PhysShape); | ||
886 | |||
887 | prim.PhysShape = cShape; | ||
888 | |||
889 | return true; | ||
890 | } | ||
891 | |||
892 | // Create a hash of all the shape parameters to be used as a key | ||
893 | // for this particular shape. | ||
894 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | ||
895 | { | ||
896 | // level of detail based on size and type of the object | ||
897 | float lod = BSParam.MeshLOD; | ||
898 | |||
899 | // prims with curvy internal cuts need higher lod | ||
900 | if (pbs.HollowShape == HollowShape.Circle) | ||
901 | lod = BSParam.MeshCircularLOD; | ||
902 | |||
903 | if (pbs.SculptEntry) | ||
904 | lod = BSParam.SculptLOD; | ||
905 | |||
906 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | ||
907 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); | ||
908 | if (maxAxis > BSParam.MeshMegaPrimThreshold) | ||
909 | lod = BSParam.MeshMegaPrimLOD; | ||
910 | |||
911 | retLod = lod; | ||
912 | return pbs.GetMeshKey(size, lod); | ||
913 | } | ||
914 | // For those who don't want the LOD | ||
915 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) | ||
916 | { | 316 | { |
917 | float lod; | 317 | if (!body.HasPhysicalBody) |
918 | return ComputeShapeKey(size, pbs, out lod); | 318 | return; |
919 | } | ||
920 | 319 | ||
921 | // The creation of a mesh or hull can fail if an underlying asset is not available. | 320 | m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody"); |
922 | // There are two cases: 1) the asset is not in the cache and it needs to be fetched; | ||
923 | // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). | ||
924 | // The first case causes the asset to be fetched. The second case requires | ||
925 | // us to not loop forever. | ||
926 | // Called after creating a physical mesh or hull. If the physical shape was created, | ||
927 | // just return. | ||
928 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) | ||
929 | { | ||
930 | // If the shape was successfully created, nothing more to do | ||
931 | if (newShape.HasPhysicalShape) | ||
932 | return newShape; | ||
933 | 321 | ||
934 | // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been | 322 | lock (m_collectionActivityLock) |
935 | // fetched but we end up here again, the meshing of the asset must have failed. | ||
936 | // Prevent trying to keep fetching the mesh by declaring failure. | ||
937 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
938 | { | ||
939 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; | ||
940 | PhysicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", | ||
941 | LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); | ||
942 | } | ||
943 | else | ||
944 | { | 323 | { |
945 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | 324 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); |
946 | if (prim.BaseShape.SculptEntry | 325 | // If the caller needs to know the old body is going away, pass the event up. |
947 | && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed | 326 | if (bodyCallback != null) |
948 | && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting | 327 | bodyCallback(body, null); |
949 | && prim.BaseShape.SculptTexture != OMV.UUID.Zero | ||
950 | ) | ||
951 | { | ||
952 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID); | ||
953 | // Multiple requestors will know we're waiting for this asset | ||
954 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; | ||
955 | |||
956 | BSPhysObject xprim = prim; | ||
957 | Util.FireAndForget(delegate | ||
958 | { | ||
959 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; | ||
960 | if (assetProvider != null) | ||
961 | { | ||
962 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
963 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
964 | { | ||
965 | bool assetFound = false; | ||
966 | string mismatchIDs = String.Empty; // DEBUG DEBUG | ||
967 | if (asset != null && yprim.BaseShape.SculptEntry) | ||
968 | { | ||
969 | if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) | ||
970 | { | ||
971 | yprim.BaseShape.SculptData = asset.Data; | ||
972 | // This will cause the prim to see that the filler shape is not the right | ||
973 | // one and try again to build the object. | ||
974 | // No race condition with the normal shape setting since the rebuild is at taint time. | ||
975 | yprim.ForceBodyShapeRebuild(false /* inTaintTime */); | ||
976 | assetFound = true; | ||
977 | } | ||
978 | else | ||
979 | { | ||
980 | mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; | ||
981 | } | ||
982 | } | ||
983 | if (assetFound) | ||
984 | yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; | ||
985 | else | ||
986 | yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; | ||
987 | DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}", | ||
988 | yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); | ||
989 | 328 | ||
990 | }); | 329 | // Removing an object not in the world is a NOOP |
991 | } | 330 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body); |
992 | else | ||
993 | { | ||
994 | xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; | ||
995 | PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", | ||
996 | LogHeader, PhysicsScene.Name); | ||
997 | } | ||
998 | }); | ||
999 | } | ||
1000 | else | ||
1001 | { | ||
1002 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) | ||
1003 | { | ||
1004 | PhysicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", | ||
1005 | LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); | ||
1006 | } | ||
1007 | } | ||
1008 | } | ||
1009 | 331 | ||
1010 | // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. | 332 | // Zero any reference to the shape so it is not freed when the body is deleted. |
1011 | BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | 333 | m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null); |
1012 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID); | ||
1013 | 334 | ||
1014 | return fillinShape; | 335 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, body); |
336 | } | ||
1015 | } | 337 | } |
1016 | 338 | ||
1017 | // Create a body object in Bullet. | 339 | // Create a body object in Bullet. |
1018 | // Updates prim.BSBody with the information about the new body if one is created. | 340 | // Updates prim.BSBody with the information about the new body if one is created. |
1019 | // Returns 'true' if an object was actually created. | 341 | // Returns 'true' if an object was actually created. |
1020 | // Called at taint-time. | 342 | // Called at taint-time. |
1021 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback) | 343 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback) |
1022 | { | 344 | { |
1023 | bool ret = false; | 345 | bool ret = false; |
1024 | 346 | ||
@@ -1029,7 +351,7 @@ public sealed class BSShapeCollection : IDisposable | |||
1029 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. | 351 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. |
1030 | if (!mustRebuild) | 352 | if (!mustRebuild) |
1031 | { | 353 | { |
1032 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); | 354 | CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody); |
1033 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY | 355 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY |
1034 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) | 356 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) |
1035 | { | 357 | { |
@@ -1047,12 +369,12 @@ public sealed class BSShapeCollection : IDisposable | |||
1047 | BulletBody aBody; | 369 | BulletBody aBody; |
1048 | if (prim.IsSolid) | 370 | if (prim.IsSolid) |
1049 | { | 371 | { |
1050 | aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); | 372 | aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
1051 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); | 373 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody); |
1052 | } | 374 | } |
1053 | else | 375 | else |
1054 | { | 376 | { |
1055 | aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); | 377 | aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
1056 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); | 378 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); |
1057 | } | 379 | } |
1058 | 380 | ||
@@ -1066,46 +388,10 @@ public sealed class BSShapeCollection : IDisposable | |||
1066 | return ret; | 388 | return ret; |
1067 | } | 389 | } |
1068 | 390 | ||
1069 | private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc) | ||
1070 | { | ||
1071 | bool ret = false; | ||
1072 | MeshDesc foundDesc = new MeshDesc(); | ||
1073 | foreach (MeshDesc md in Meshes.Values) | ||
1074 | { | ||
1075 | if (md.shape.ReferenceSame(shape)) | ||
1076 | { | ||
1077 | foundDesc = md; | ||
1078 | ret = true; | ||
1079 | break; | ||
1080 | } | ||
1081 | |||
1082 | } | ||
1083 | outDesc = foundDesc; | ||
1084 | return ret; | ||
1085 | } | ||
1086 | |||
1087 | private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc) | ||
1088 | { | ||
1089 | bool ret = false; | ||
1090 | HullDesc foundDesc = new HullDesc(); | ||
1091 | foreach (HullDesc hd in Hulls.Values) | ||
1092 | { | ||
1093 | if (hd.shape.ReferenceSame(shape)) | ||
1094 | { | ||
1095 | foundDesc = hd; | ||
1096 | ret = true; | ||
1097 | break; | ||
1098 | } | ||
1099 | |||
1100 | } | ||
1101 | outDesc = foundDesc; | ||
1102 | return ret; | ||
1103 | } | ||
1104 | |||
1105 | private void DetailLog(string msg, params Object[] args) | 391 | private void DetailLog(string msg, params Object[] args) |
1106 | { | 392 | { |
1107 | if (PhysicsScene.PhysicsLogging.Enabled) | 393 | if (m_physicsScene.PhysicsLogging.Enabled) |
1108 | PhysicsScene.DetailLog(msg, args); | 394 | m_physicsScene.DetailLog(msg, args); |
1109 | } | 395 | } |
1110 | } | 396 | } |
1111 | } | 397 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index ee18379..5a0a14c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | |||
@@ -29,115 +29,312 @@ using System; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Text; | 30 | using System.Text; |
31 | 31 | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | using OpenSim.Region.Physics.Meshing; | ||
35 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | ||
36 | |||
32 | using OMV = OpenMetaverse; | 37 | using OMV = OpenMetaverse; |
33 | 38 | ||
34 | namespace OpenSim.Region.Physics.BulletSPlugin | 39 | namespace OpenSim.Region.Physics.BulletSPlugin |
35 | { | 40 | { |
36 | public abstract class BSShape | 41 | public abstract class BSShape |
37 | { | 42 | { |
43 | private static string LogHeader = "[BULLETSIM SHAPE]"; | ||
44 | |||
38 | public int referenceCount { get; set; } | 45 | public int referenceCount { get; set; } |
39 | public DateTime lastReferenced { get; set; } | 46 | public DateTime lastReferenced { get; set; } |
47 | public BulletShape physShapeInfo { get; set; } | ||
40 | 48 | ||
41 | public BSShape() | 49 | public BSShape() |
42 | { | 50 | { |
43 | referenceCount = 0; | 51 | referenceCount = 1; |
44 | lastReferenced = DateTime.Now; | 52 | lastReferenced = DateTime.Now; |
53 | physShapeInfo = new BulletShape(); | ||
45 | } | 54 | } |
46 | 55 | public BSShape(BulletShape pShape) | |
47 | // Get a reference to a physical shape. Create if it doesn't exist | ||
48 | public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
49 | { | 56 | { |
50 | BSShape ret = null; | 57 | referenceCount = 1; |
51 | 58 | lastReferenced = DateTime.Now; | |
52 | if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) | 59 | physShapeInfo = pShape; |
53 | { | 60 | } |
54 | // an avatar capsule is close to a native shape (it is not shared) | ||
55 | ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE, | ||
56 | FixedShapeKey.KEY_CAPSULE); | ||
57 | physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret); | ||
58 | } | ||
59 | |||
60 | // Compound shapes are handled special as they are rebuilt from scratch. | ||
61 | // This isn't too great a hardship since most of the child shapes will have already been created. | ||
62 | if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | ||
63 | { | ||
64 | // Getting a reference to a compound shape gets you the compound shape with the root prim shape added | ||
65 | ret = BSShapeCompound.GetReference(prim); | ||
66 | physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); | ||
67 | } | ||
68 | |||
69 | // Avatars have their own unique shape | ||
70 | if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR) | ||
71 | { | ||
72 | // Getting a reference to a compound shape gets you the compound shape with the root prim shape added | ||
73 | ret = BSShapeAvatar.GetReference(prim); | ||
74 | physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret); | ||
75 | } | ||
76 | 61 | ||
77 | if (ret == null) | 62 | // Get another reference to this shape. |
78 | ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); | 63 | public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim); |
79 | 64 | ||
80 | return ret; | 65 | // Called when this shape is being used again. |
81 | } | 66 | // Used internally. External callers should call instance.GetReference() to properly copy/reference |
82 | public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | 67 | // the shape. |
68 | protected virtual void IncrementReference() | ||
83 | { | 69 | { |
84 | return null; | 70 | referenceCount++; |
71 | lastReferenced = DateTime.Now; | ||
85 | } | 72 | } |
86 | public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | 73 | |
74 | // Called when this shape is being used again. | ||
75 | protected virtual void DecrementReference() | ||
87 | { | 76 | { |
88 | return null; | 77 | referenceCount--; |
78 | lastReferenced = DateTime.Now; | ||
89 | } | 79 | } |
90 | 80 | ||
91 | // Release the use of a physical shape. | 81 | // Release the use of a physical shape. |
92 | public abstract void Dereference(BSScene physicsScene); | 82 | public abstract void Dereference(BSScene physicsScene); |
93 | 83 | ||
94 | // All shapes have a static call to get a reference to the physical shape | 84 | // Return 'true' if there is an allocated physics physical shape under this class instance. |
95 | // protected abstract static BSShape GetReference(); | 85 | public virtual bool HasPhysicalShape |
86 | { | ||
87 | get | ||
88 | { | ||
89 | if (physShapeInfo != null) | ||
90 | return physShapeInfo.HasPhysicalShape; | ||
91 | return false; | ||
92 | } | ||
93 | } | ||
94 | public virtual BSPhysicsShapeType ShapeType | ||
95 | { | ||
96 | get | ||
97 | { | ||
98 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
99 | if (physShapeInfo != null && physShapeInfo.HasPhysicalShape) | ||
100 | ret = physShapeInfo.shapeType; | ||
101 | return ret; | ||
102 | } | ||
103 | } | ||
96 | 104 | ||
97 | // Returns a string for debugging that uniquily identifies the memory used by this instance | 105 | // Returns a string for debugging that uniquily identifies the memory used by this instance |
98 | public virtual string AddrString | 106 | public virtual string AddrString |
99 | { | 107 | { |
100 | get { return "unknown"; } | 108 | get |
109 | { | ||
110 | if (physShapeInfo != null) | ||
111 | return physShapeInfo.AddrString; | ||
112 | return "unknown"; | ||
113 | } | ||
101 | } | 114 | } |
102 | 115 | ||
103 | public override string ToString() | 116 | public override string ToString() |
104 | { | 117 | { |
105 | StringBuilder buff = new StringBuilder(); | 118 | StringBuilder buff = new StringBuilder(); |
106 | buff.Append("<p="); | 119 | if (physShapeInfo == null) |
107 | buff.Append(AddrString); | 120 | { |
121 | buff.Append("<noPhys"); | ||
122 | } | ||
123 | else | ||
124 | { | ||
125 | buff.Append("<phy="); | ||
126 | buff.Append(physShapeInfo.ToString()); | ||
127 | } | ||
108 | buff.Append(",c="); | 128 | buff.Append(",c="); |
109 | buff.Append(referenceCount.ToString()); | 129 | buff.Append(referenceCount.ToString()); |
110 | buff.Append(">"); | 130 | buff.Append(">"); |
111 | return buff.ToString(); | 131 | return buff.ToString(); |
112 | } | 132 | } |
133 | |||
134 | #region Common shape routines | ||
135 | // Create a hash of all the shape parameters to be used as a key for this particular shape. | ||
136 | public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | ||
137 | { | ||
138 | // level of detail based on size and type of the object | ||
139 | float lod = BSParam.MeshLOD; | ||
140 | if (pbs.SculptEntry) | ||
141 | lod = BSParam.SculptLOD; | ||
142 | |||
143 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | ||
144 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); | ||
145 | if (maxAxis > BSParam.MeshMegaPrimThreshold) | ||
146 | lod = BSParam.MeshMegaPrimLOD; | ||
147 | |||
148 | retLod = lod; | ||
149 | return pbs.GetMeshKey(size, lod); | ||
150 | } | ||
151 | |||
152 | // The creation of a mesh or hull can fail if an underlying asset is not available. | ||
153 | // There are two cases: 1) the asset is not in the cache and it needs to be fetched; | ||
154 | // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). | ||
155 | // The first case causes the asset to be fetched. The second case requires | ||
156 | // us to not loop forever. | ||
157 | // Called after creating a physical mesh or hull. If the physical shape was created, | ||
158 | // just return. | ||
159 | public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim) | ||
160 | { | ||
161 | // If the shape was successfully created, nothing more to do | ||
162 | if (newShape.HasPhysicalShape) | ||
163 | return newShape; | ||
164 | |||
165 | // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been | ||
166 | // fetched but we end up here again, the meshing of the asset must have failed. | ||
167 | // Prevent trying to keep fetching the mesh by declaring failure. | ||
168 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
169 | { | ||
170 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; | ||
171 | physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}", | ||
172 | LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
173 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}", | ||
174 | prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
175 | } | ||
176 | else | ||
177 | { | ||
178 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | ||
179 | if (prim.BaseShape.SculptEntry | ||
180 | && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.FailedAssetFetch | ||
181 | && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.FailedMeshing | ||
182 | && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting | ||
183 | && prim.BaseShape.SculptTexture != OMV.UUID.Zero | ||
184 | ) | ||
185 | { | ||
186 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}", | ||
187 | prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); | ||
188 | // Multiple requestors will know we're waiting for this asset | ||
189 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; | ||
190 | |||
191 | BSPhysObject xprim = prim; | ||
192 | Util.FireAndForget(delegate | ||
193 | { | ||
194 | // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID); | ||
195 | RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; | ||
196 | if (assetProvider != null) | ||
197 | { | ||
198 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
199 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
200 | { | ||
201 | // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID); | ||
202 | bool assetFound = false; | ||
203 | string mismatchIDs = String.Empty; // DEBUG DEBUG | ||
204 | if (asset != null && yprim.BaseShape.SculptEntry) | ||
205 | { | ||
206 | if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) | ||
207 | { | ||
208 | yprim.BaseShape.SculptData = asset.Data; | ||
209 | // This will cause the prim to see that the filler shape is not the right | ||
210 | // one and try again to build the object. | ||
211 | // No race condition with the normal shape setting since the rebuild is at taint time. | ||
212 | yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; | ||
213 | yprim.ForceBodyShapeRebuild(false /* inTaintTime */); | ||
214 | assetFound = true; | ||
215 | } | ||
216 | else | ||
217 | { | ||
218 | mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; | ||
219 | } | ||
220 | } | ||
221 | if (!assetFound) | ||
222 | { | ||
223 | yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; | ||
224 | } | ||
225 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}", | ||
226 | yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); | ||
227 | }); | ||
228 | } | ||
229 | else | ||
230 | { | ||
231 | xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; | ||
232 | physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", | ||
233 | LogHeader, physicsScene.Name); | ||
234 | } | ||
235 | }); | ||
236 | } | ||
237 | else | ||
238 | { | ||
239 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) | ||
240 | { | ||
241 | physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}", | ||
242 | LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
243 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}", | ||
244 | prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
245 | } | ||
246 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing) | ||
247 | { | ||
248 | physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}", | ||
249 | LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
250 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}", | ||
251 | prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | |||
256 | // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. | ||
257 | BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
258 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID); | ||
259 | |||
260 | return fillShape.physShapeInfo; | ||
261 | } | ||
262 | |||
263 | public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim) | ||
264 | { | ||
265 | StringBuilder buff = new StringBuilder(prim.PhysObjectName); | ||
266 | buff.Append("/pos="); | ||
267 | buff.Append(prim.RawPosition.ToString()); | ||
268 | if (pScene != null) | ||
269 | { | ||
270 | buff.Append("/rgn="); | ||
271 | buff.Append(pScene.Name); | ||
272 | } | ||
273 | return buff.ToString(); | ||
274 | } | ||
275 | |||
276 | #endregion // Common shape routines | ||
113 | } | 277 | } |
114 | 278 | ||
279 | // ============================================================================================================ | ||
115 | public class BSShapeNull : BSShape | 280 | public class BSShapeNull : BSShape |
116 | { | 281 | { |
117 | public BSShapeNull() : base() | 282 | public BSShapeNull() : base() |
118 | { | 283 | { |
119 | } | 284 | } |
120 | public static BSShape GetReference() { return new BSShapeNull(); } | 285 | public static BSShape GetReference() { return new BSShapeNull(); } |
286 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); } | ||
121 | public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } | 287 | public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } |
122 | } | 288 | } |
123 | 289 | ||
290 | // ============================================================================================================ | ||
124 | public class BSShapeNative : BSShape | 291 | public class BSShapeNative : BSShape |
125 | { | 292 | { |
126 | private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; | 293 | private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; |
127 | public BSShapeNative() : base() | 294 | public BSShapeNative(BulletShape pShape) : base(pShape) |
128 | { | 295 | { |
129 | } | 296 | } |
130 | public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, | 297 | |
131 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | 298 | public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, |
299 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | ||
132 | { | 300 | { |
133 | // Native shapes are not shared and are always built anew. | 301 | // Native shapes are not shared and are always built anew. |
134 | //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); | 302 | return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); |
135 | return null; | ||
136 | } | 303 | } |
137 | 304 | ||
138 | private BSShapeNative(BSScene physicsScene, BSPhysObject prim, | 305 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) |
139 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | ||
140 | { | 306 | { |
307 | // Native shapes are not shared so we return a new shape. | ||
308 | BSShape ret = null; | ||
309 | lock (physShapeInfo) | ||
310 | { | ||
311 | ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim, | ||
312 | physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey)); | ||
313 | } | ||
314 | return ret; | ||
315 | } | ||
316 | |||
317 | // Make this reference to the physical shape go away since native shapes are not shared. | ||
318 | public override void Dereference(BSScene physicsScene) | ||
319 | { | ||
320 | // Native shapes are not tracked and are released immediately | ||
321 | lock (physShapeInfo) | ||
322 | { | ||
323 | if (physShapeInfo.HasPhysicalShape) | ||
324 | { | ||
325 | physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); | ||
326 | physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); | ||
327 | } | ||
328 | physShapeInfo.Clear(); | ||
329 | // Garbage collection will free up this instance. | ||
330 | } | ||
331 | } | ||
332 | |||
333 | private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, | ||
334 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | ||
335 | { | ||
336 | BulletShape newShape; | ||
337 | |||
141 | ShapeData nativeShapeData = new ShapeData(); | 338 | ShapeData nativeShapeData = new ShapeData(); |
142 | nativeShapeData.Type = shapeType; | 339 | nativeShapeData.Type = shapeType; |
143 | nativeShapeData.ID = prim.LocalID; | 340 | nativeShapeData.ID = prim.LocalID; |
@@ -146,84 +343,855 @@ public class BSShapeNative : BSShape | |||
146 | nativeShapeData.MeshKey = (ulong)shapeKey; | 343 | nativeShapeData.MeshKey = (ulong)shapeKey; |
147 | nativeShapeData.HullKey = (ulong)shapeKey; | 344 | nativeShapeData.HullKey = (ulong)shapeKey; |
148 | 345 | ||
149 | |||
150 | /* | ||
151 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | 346 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) |
152 | { | 347 | { |
153 | ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); | 348 | newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); |
154 | physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | 349 | physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale); |
155 | } | 350 | } |
156 | else | 351 | else |
157 | { | 352 | { |
158 | ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); | 353 | newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); |
159 | } | 354 | } |
160 | if (ptr == IntPtr.Zero) | 355 | if (!newShape.HasPhysicalShape) |
161 | { | 356 | { |
162 | physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | 357 | physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", |
163 | LogHeader, prim.LocalID, shapeType); | 358 | LogHeader, prim.LocalID, shapeType); |
164 | } | 359 | } |
165 | type = shapeType; | 360 | newShape.shapeType = shapeType; |
166 | key = (UInt64)shapeKey; | 361 | newShape.isNativeShape = true; |
167 | */ | 362 | newShape.shapeKey = (UInt64)shapeKey; |
168 | } | 363 | return newShape; |
169 | // Make this reference to the physical shape go away since native shapes are not shared. | ||
170 | public override void Dereference(BSScene physicsScene) | ||
171 | { | ||
172 | /* | ||
173 | // Native shapes are not tracked and are released immediately | ||
174 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); | ||
175 | PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this); | ||
176 | ptr = IntPtr.Zero; | ||
177 | // Garbage collection will free up this instance. | ||
178 | */ | ||
179 | } | 364 | } |
365 | |||
180 | } | 366 | } |
181 | 367 | ||
368 | // ============================================================================================================ | ||
182 | public class BSShapeMesh : BSShape | 369 | public class BSShapeMesh : BSShape |
183 | { | 370 | { |
184 | private static string LogHeader = "[BULLETSIM SHAPE MESH]"; | 371 | private static string LogHeader = "[BULLETSIM SHAPE MESH]"; |
185 | private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); | 372 | public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); |
186 | 373 | ||
187 | public BSShapeMesh() : base() | 374 | public BSShapeMesh(BulletShape pShape) : base(pShape) |
188 | { | 375 | { |
189 | } | 376 | } |
190 | public static BSShape GetReference() { return new BSShapeNull(); } | 377 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) |
191 | public override void Dereference(BSScene physicsScene) { } | 378 | { |
379 | float lod; | ||
380 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
381 | |||
382 | BSShapeMesh retMesh = null; | ||
383 | lock (Meshes) | ||
384 | { | ||
385 | if (Meshes.TryGetValue(newMeshKey, out retMesh)) | ||
386 | { | ||
387 | // The mesh has already been created. Return a new reference to same. | ||
388 | retMesh.IncrementReference(); | ||
389 | } | ||
390 | else | ||
391 | { | ||
392 | retMesh = new BSShapeMesh(new BulletShape()); | ||
393 | // An instance of this mesh has not been created. Build and remember same. | ||
394 | BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); | ||
395 | |||
396 | // Check to see if mesh was created (might require an asset). | ||
397 | newShape = VerifyMeshCreated(physicsScene, newShape, prim); | ||
398 | if (!newShape.isNativeShape | ||
399 | || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing | ||
400 | || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) | ||
401 | { | ||
402 | // If a mesh was what was created, remember the built shape for later sharing. | ||
403 | // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. | ||
404 | Meshes.Add(newMeshKey, retMesh); | ||
405 | } | ||
406 | |||
407 | retMesh.physShapeInfo = newShape; | ||
408 | } | ||
409 | } | ||
410 | physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod); | ||
411 | return retMesh; | ||
412 | } | ||
413 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
414 | { | ||
415 | BSShape ret = null; | ||
416 | // If the underlying shape is native, the actual shape has not been build (waiting for asset) | ||
417 | // and we must create a copy of the native shape since they are never shared. | ||
418 | if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) | ||
419 | { | ||
420 | // TODO: decide when the native shapes should be freed. Check in Dereference? | ||
421 | ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
422 | } | ||
423 | else | ||
424 | { | ||
425 | // Another reference to this shape is just counted. | ||
426 | IncrementReference(); | ||
427 | ret = this; | ||
428 | } | ||
429 | return ret; | ||
430 | } | ||
431 | public override void Dereference(BSScene physicsScene) | ||
432 | { | ||
433 | lock (Meshes) | ||
434 | { | ||
435 | this.DecrementReference(); | ||
436 | physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
437 | // TODO: schedule aging and destruction of unused meshes. | ||
438 | } | ||
439 | } | ||
440 | // Loop through all the known meshes and return the description based on the physical address. | ||
441 | public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh) | ||
442 | { | ||
443 | bool ret = false; | ||
444 | BSShapeMesh foundDesc = null; | ||
445 | lock (Meshes) | ||
446 | { | ||
447 | foreach (BSShapeMesh sm in Meshes.Values) | ||
448 | { | ||
449 | if (sm.physShapeInfo.ReferenceSame(pShape)) | ||
450 | { | ||
451 | foundDesc = sm; | ||
452 | ret = true; | ||
453 | break; | ||
454 | } | ||
455 | |||
456 | } | ||
457 | } | ||
458 | outMesh = foundDesc; | ||
459 | return ret; | ||
460 | } | ||
461 | |||
462 | public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices ); | ||
463 | private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, | ||
464 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
465 | { | ||
466 | return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, | ||
467 | (w, iC, i, vC, v) => physicsScene.PE.CreateMeshShape(w, iC, i, vC, v) ); | ||
468 | } | ||
469 | |||
470 | // Code that uses the mesher to create the index/vertices info for a trimesh shape. | ||
471 | // This is used by the passed 'makeShape' call to create the Bullet mesh shape. | ||
472 | // The actual build call is passed so this logic can be used by several of the shapes that use a | ||
473 | // simple mesh as their base shape. | ||
474 | public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, | ||
475 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape) | ||
476 | { | ||
477 | BulletShape newShape = new BulletShape(); | ||
478 | |||
479 | IMesh meshData = null; | ||
480 | lock (physicsScene.mesher) | ||
481 | { | ||
482 | meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, | ||
483 | false, // say it is not physical so a bounding box is not built | ||
484 | false, // do not cache the mesh and do not use previously built versions | ||
485 | false, | ||
486 | false | ||
487 | ); | ||
488 | } | ||
489 | |||
490 | if (meshData != null) | ||
491 | { | ||
492 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
493 | { | ||
494 | // Release the fetched asset data once it has been used. | ||
495 | pbs.SculptData = new byte[0]; | ||
496 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; | ||
497 | } | ||
498 | |||
499 | int[] indices = meshData.getIndexListAsInt(); | ||
500 | int realIndicesIndex = indices.Length; | ||
501 | float[] verticesAsFloats = meshData.getVertexListAsFloat(); | ||
502 | |||
503 | if (BSParam.ShouldRemoveZeroWidthTriangles) | ||
504 | { | ||
505 | // Remove degenerate triangles. These are triangles with two of the vertices | ||
506 | // are the same. This is complicated by the problem that vertices are not | ||
507 | // made unique in sculpties so we have to compare the values in the vertex. | ||
508 | realIndicesIndex = 0; | ||
509 | for (int tri = 0; tri < indices.Length; tri += 3) | ||
510 | { | ||
511 | // Compute displacements into vertex array for each vertex of the triangle | ||
512 | int v1 = indices[tri + 0] * 3; | ||
513 | int v2 = indices[tri + 1] * 3; | ||
514 | int v3 = indices[tri + 2] * 3; | ||
515 | // Check to see if any two of the vertices are the same | ||
516 | if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] | ||
517 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] | ||
518 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) | ||
519 | || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] | ||
520 | && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] | ||
521 | && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) | ||
522 | || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] | ||
523 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] | ||
524 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) | ||
525 | ) | ||
526 | { | ||
527 | // None of the vertices of the triangles are the same. This is a good triangle; | ||
528 | indices[realIndicesIndex + 0] = indices[tri + 0]; | ||
529 | indices[realIndicesIndex + 1] = indices[tri + 1]; | ||
530 | indices[realIndicesIndex + 2] = indices[tri + 2]; | ||
531 | realIndicesIndex += 3; | ||
532 | } | ||
533 | } | ||
534 | } | ||
535 | physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}", | ||
536 | BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); | ||
537 | |||
538 | if (realIndicesIndex != 0) | ||
539 | { | ||
540 | newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); | ||
541 | } | ||
542 | else | ||
543 | { | ||
544 | // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh. | ||
545 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; | ||
546 | physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) ); | ||
547 | physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey); | ||
548 | } | ||
549 | } | ||
550 | newShape.shapeKey = newMeshKey; | ||
551 | |||
552 | return newShape; | ||
553 | } | ||
192 | } | 554 | } |
193 | 555 | ||
556 | // ============================================================================================================ | ||
194 | public class BSShapeHull : BSShape | 557 | public class BSShapeHull : BSShape |
195 | { | 558 | { |
196 | private static string LogHeader = "[BULLETSIM SHAPE HULL]"; | 559 | private static string LogHeader = "[BULLETSIM SHAPE HULL]"; |
197 | private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); | 560 | public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); |
198 | 561 | ||
199 | public BSShapeHull() : base() | 562 | public BSShapeHull(BulletShape pShape) : base(pShape) |
200 | { | 563 | { |
201 | } | 564 | } |
202 | public static BSShape GetReference() { return new BSShapeNull(); } | 565 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) |
203 | public override void Dereference(BSScene physicsScene) { } | 566 | { |
567 | float lod; | ||
568 | System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
569 | |||
570 | BSShapeHull retHull = null; | ||
571 | lock (Hulls) | ||
572 | { | ||
573 | if (Hulls.TryGetValue(newHullKey, out retHull)) | ||
574 | { | ||
575 | // The mesh has already been created. Return a new reference to same. | ||
576 | retHull.IncrementReference(); | ||
577 | } | ||
578 | else | ||
579 | { | ||
580 | retHull = new BSShapeHull(new BulletShape()); | ||
581 | // An instance of this mesh has not been created. Build and remember same. | ||
582 | BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod); | ||
583 | |||
584 | // Check to see if hull was created (might require an asset). | ||
585 | newShape = VerifyMeshCreated(physicsScene, newShape, prim); | ||
586 | if (!newShape.isNativeShape | ||
587 | || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing | ||
588 | || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) | ||
589 | { | ||
590 | // If a mesh was what was created, remember the built shape for later sharing. | ||
591 | Hulls.Add(newHullKey, retHull); | ||
592 | } | ||
593 | retHull.physShapeInfo = newShape; | ||
594 | } | ||
595 | } | ||
596 | physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod); | ||
597 | return retHull; | ||
598 | } | ||
599 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
600 | { | ||
601 | BSShape ret = null; | ||
602 | // If the underlying shape is native, the actual shape has not been build (waiting for asset) | ||
603 | // and we must create a copy of the native shape since they are never shared. | ||
604 | if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) | ||
605 | { | ||
606 | // TODO: decide when the native shapes should be freed. Check in Dereference? | ||
607 | ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
608 | } | ||
609 | else | ||
610 | { | ||
611 | // Another reference to this shape is just counted. | ||
612 | IncrementReference(); | ||
613 | ret = this; | ||
614 | } | ||
615 | return ret; | ||
616 | } | ||
617 | public override void Dereference(BSScene physicsScene) | ||
618 | { | ||
619 | lock (Hulls) | ||
620 | { | ||
621 | this.DecrementReference(); | ||
622 | physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
623 | // TODO: schedule aging and destruction of unused meshes. | ||
624 | } | ||
625 | } | ||
626 | List<ConvexResult> m_hulls; | ||
627 | private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, | ||
628 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
629 | { | ||
630 | BulletShape newShape = new BulletShape(); | ||
631 | |||
632 | IMesh meshData = null; | ||
633 | List<List<OMV.Vector3>> allHulls = null; | ||
634 | lock (physicsScene.mesher) | ||
635 | { | ||
636 | // Pass true for physicalness as this prevents the creation of bounding box which is not needed | ||
637 | meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false); | ||
638 | |||
639 | // If we should use the asset's hull info, fetch it out of the locked mesher | ||
640 | if (meshData != null && BSParam.ShouldUseAssetHulls) | ||
641 | { | ||
642 | Meshmerizer realMesher = physicsScene.mesher as Meshmerizer; | ||
643 | if (realMesher != null) | ||
644 | { | ||
645 | allHulls = realMesher.GetConvexHulls(size); | ||
646 | } | ||
647 | if (allHulls == null) | ||
648 | { | ||
649 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID); | ||
650 | } | ||
651 | } | ||
652 | } | ||
653 | |||
654 | // If there is hull data in the mesh asset, build the hull from that | ||
655 | if (allHulls != null && BSParam.ShouldUseAssetHulls) | ||
656 | { | ||
657 | int hullCount = allHulls.Count; | ||
658 | int totalVertices = 1; // include one for the count of the hulls | ||
659 | // Using the structure described for HACD hulls, create the memory sturcture | ||
660 | // to pass the hull data to the creater. | ||
661 | foreach (List<OMV.Vector3> hullVerts in allHulls) | ||
662 | { | ||
663 | totalVertices += 4; // add four for the vertex count and centroid | ||
664 | totalVertices += hullVerts.Count * 3; // one vertex is three dimensions | ||
665 | } | ||
666 | float[] convHulls = new float[totalVertices]; | ||
667 | |||
668 | convHulls[0] = (float)hullCount; | ||
669 | int jj = 1; | ||
670 | foreach (List<OMV.Vector3> hullVerts in allHulls) | ||
671 | { | ||
672 | convHulls[jj + 0] = hullVerts.Count; | ||
673 | convHulls[jj + 1] = 0f; // centroid x,y,z | ||
674 | convHulls[jj + 2] = 0f; | ||
675 | convHulls[jj + 3] = 0f; | ||
676 | jj += 4; | ||
677 | foreach (OMV.Vector3 oneVert in hullVerts) | ||
678 | { | ||
679 | convHulls[jj + 0] = oneVert.X; | ||
680 | convHulls[jj + 1] = oneVert.Y; | ||
681 | convHulls[jj + 2] = oneVert.Z; | ||
682 | jj += 3; | ||
683 | } | ||
684 | } | ||
685 | |||
686 | // create the hull data structure in Bullet | ||
687 | newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); | ||
688 | |||
689 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}", | ||
690 | prim.LocalID, hullCount, totalVertices, newShape); | ||
691 | } | ||
692 | |||
693 | // If no hull specified in the asset and we should use Bullet's HACD approximation... | ||
694 | if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD) | ||
695 | { | ||
696 | // Build the hull shape from an existing mesh shape. | ||
697 | // The mesh should have already been created in Bullet. | ||
698 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID); | ||
699 | BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); | ||
700 | |||
701 | if (meshShape.physShapeInfo.HasPhysicalShape) | ||
702 | { | ||
703 | HACDParams parms; | ||
704 | parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; | ||
705 | parms.minClusters = BSParam.BHullMinClusters; | ||
706 | parms.compacityWeight = BSParam.BHullCompacityWeight; | ||
707 | parms.volumeWeight = BSParam.BHullVolumeWeight; | ||
708 | parms.concavity = BSParam.BHullConcavity; | ||
709 | parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); | ||
710 | parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); | ||
711 | parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); | ||
712 | parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); | ||
713 | |||
714 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); | ||
715 | newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); | ||
716 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape); | ||
717 | |||
718 | // Now done with the mesh shape. | ||
719 | meshShape.Dereference(physicsScene); | ||
720 | } | ||
721 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); | ||
722 | } | ||
723 | |||
724 | // If no other hull specifications, use our HACD hull approximation. | ||
725 | if (!newShape.HasPhysicalShape && meshData != null) | ||
726 | { | ||
727 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
728 | { | ||
729 | // Release the fetched asset data once it has been used. | ||
730 | pbs.SculptData = new byte[0]; | ||
731 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; | ||
732 | } | ||
733 | |||
734 | int[] indices = meshData.getIndexListAsInt(); | ||
735 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
736 | |||
737 | //format conversion from IMesh format to DecompDesc format | ||
738 | List<int> convIndices = new List<int>(); | ||
739 | List<float3> convVertices = new List<float3>(); | ||
740 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
741 | { | ||
742 | convIndices.Add(indices[ii]); | ||
743 | } | ||
744 | foreach (OMV.Vector3 vv in vertices) | ||
745 | { | ||
746 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
747 | } | ||
748 | |||
749 | uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; | ||
750 | if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) | ||
751 | { | ||
752 | // Simple primitive shapes we know are convex so they are better implemented with | ||
753 | // fewer hulls. | ||
754 | // Check for simple shape (prim without cuts) and reduce split parameter if so. | ||
755 | if (BSShapeCollection.PrimHasNoCuts(pbs)) | ||
756 | { | ||
757 | maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; | ||
758 | } | ||
759 | } | ||
760 | |||
761 | // setup and do convex hull conversion | ||
762 | m_hulls = new List<ConvexResult>(); | ||
763 | DecompDesc dcomp = new DecompDesc(); | ||
764 | dcomp.mIndices = convIndices; | ||
765 | dcomp.mVertices = convVertices; | ||
766 | dcomp.mDepth = maxDepthSplit; | ||
767 | dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; | ||
768 | dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; | ||
769 | dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; | ||
770 | dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; | ||
771 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
772 | // create the hull into the _hulls variable | ||
773 | convexBuilder.process(dcomp); | ||
774 | |||
775 | physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", | ||
776 | BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); | ||
777 | |||
778 | // Convert the vertices and indices for passing to unmanaged. | ||
779 | // The hull information is passed as a large floating point array. | ||
780 | // The format is: | ||
781 | // convHulls[0] = number of hulls | ||
782 | // convHulls[1] = number of vertices in first hull | ||
783 | // convHulls[2] = hull centroid X coordinate | ||
784 | // convHulls[3] = hull centroid Y coordinate | ||
785 | // convHulls[4] = hull centroid Z coordinate | ||
786 | // convHulls[5] = first hull vertex X | ||
787 | // convHulls[6] = first hull vertex Y | ||
788 | // convHulls[7] = first hull vertex Z | ||
789 | // convHulls[8] = second hull vertex X | ||
790 | // ... | ||
791 | // convHulls[n] = number of vertices in second hull | ||
792 | // convHulls[n+1] = second hull centroid X coordinate | ||
793 | // ... | ||
794 | // | ||
795 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
796 | // data structures that do not need to be converted in order to pass to Bullet. | ||
797 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
798 | int hullCount = m_hulls.Count; | ||
799 | int totalVertices = 1; // include one for the count of the hulls | ||
800 | foreach (ConvexResult cr in m_hulls) | ||
801 | { | ||
802 | totalVertices += 4; // add four for the vertex count and centroid | ||
803 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
804 | } | ||
805 | float[] convHulls = new float[totalVertices]; | ||
806 | |||
807 | convHulls[0] = (float)hullCount; | ||
808 | int jj = 1; | ||
809 | foreach (ConvexResult cr in m_hulls) | ||
810 | { | ||
811 | // copy vertices for index access | ||
812 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
813 | int kk = 0; | ||
814 | foreach (float3 ff in cr.HullVertices) | ||
815 | { | ||
816 | verts[kk++] = ff; | ||
817 | } | ||
818 | |||
819 | // add to the array one hull's worth of data | ||
820 | convHulls[jj++] = cr.HullIndices.Count; | ||
821 | convHulls[jj++] = 0f; // centroid x,y,z | ||
822 | convHulls[jj++] = 0f; | ||
823 | convHulls[jj++] = 0f; | ||
824 | foreach (int ind in cr.HullIndices) | ||
825 | { | ||
826 | convHulls[jj++] = verts[ind].x; | ||
827 | convHulls[jj++] = verts[ind].y; | ||
828 | convHulls[jj++] = verts[ind].z; | ||
829 | } | ||
830 | } | ||
831 | // create the hull data structure in Bullet | ||
832 | newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); | ||
833 | } | ||
834 | newShape.shapeKey = newHullKey; | ||
835 | return newShape; | ||
836 | } | ||
837 | // Callback from convex hull creater with a newly created hull. | ||
838 | // Just add it to our collection of hulls for this shape. | ||
839 | private void HullReturn(ConvexResult result) | ||
840 | { | ||
841 | m_hulls.Add(result); | ||
842 | return; | ||
843 | } | ||
844 | // Loop through all the known hulls and return the description based on the physical address. | ||
845 | public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull) | ||
846 | { | ||
847 | bool ret = false; | ||
848 | BSShapeHull foundDesc = null; | ||
849 | lock (Hulls) | ||
850 | { | ||
851 | foreach (BSShapeHull sh in Hulls.Values) | ||
852 | { | ||
853 | if (sh.physShapeInfo.ReferenceSame(pShape)) | ||
854 | { | ||
855 | foundDesc = sh; | ||
856 | ret = true; | ||
857 | break; | ||
858 | } | ||
859 | |||
860 | } | ||
861 | } | ||
862 | outHull = foundDesc; | ||
863 | return ret; | ||
864 | } | ||
204 | } | 865 | } |
205 | 866 | ||
867 | // ============================================================================================================ | ||
206 | public class BSShapeCompound : BSShape | 868 | public class BSShapeCompound : BSShape |
207 | { | 869 | { |
208 | private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; | 870 | private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; |
209 | public BSShapeCompound() : base() | 871 | public BSShapeCompound(BulletShape pShape) : base(pShape) |
210 | { | 872 | { |
211 | } | 873 | } |
212 | public static BSShape GetReference(BSPhysObject prim) | 874 | public static BSShape GetReference(BSScene physicsScene) |
213 | { | 875 | { |
214 | return new BSShapeNull(); | 876 | // Base compound shapes are not shared so this returns a raw shape. |
877 | // A built compound shape can be reused in linksets. | ||
878 | return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene)); | ||
879 | } | ||
880 | public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) | ||
881 | { | ||
882 | // Calling this reference means we want another handle to an existing compound shape | ||
883 | // (usually linksets) so return this copy. | ||
884 | IncrementReference(); | ||
885 | return this; | ||
886 | } | ||
887 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
888 | public override void Dereference(BSScene physicsScene) | ||
889 | { | ||
890 | lock (physShapeInfo) | ||
891 | { | ||
892 | this.DecrementReference(); | ||
893 | physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
894 | if (referenceCount <= 0) | ||
895 | { | ||
896 | if (!physicsScene.PE.IsCompound(physShapeInfo)) | ||
897 | { | ||
898 | // Failed the sanity check!! | ||
899 | physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | ||
900 | LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString); | ||
901 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | ||
902 | BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString); | ||
903 | return; | ||
904 | } | ||
905 | |||
906 | int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo); | ||
907 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", | ||
908 | BSScene.DetailLogZero, physShapeInfo, numChildren); | ||
909 | |||
910 | // Loop through all the children dereferencing each. | ||
911 | for (int ii = numChildren - 1; ii >= 0; ii--) | ||
912 | { | ||
913 | BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii); | ||
914 | DereferenceAnonCollisionShape(physicsScene, childShape); | ||
915 | } | ||
916 | physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); | ||
917 | } | ||
918 | } | ||
919 | } | ||
920 | private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene) | ||
921 | { | ||
922 | BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false); | ||
923 | return cShape; | ||
924 | } | ||
925 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | ||
926 | // Figure out type and call the correct dereference routine. | ||
927 | // Called at taint-time. | ||
928 | private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape) | ||
929 | { | ||
930 | // TODO: figure a better way to go through all the shape types and find a possible instance. | ||
931 | BSShapeMesh meshDesc; | ||
932 | if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc)) | ||
933 | { | ||
934 | meshDesc.Dereference(physicsScene); | ||
935 | } | ||
936 | else | ||
937 | { | ||
938 | BSShapeHull hullDesc; | ||
939 | if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc)) | ||
940 | { | ||
941 | hullDesc.Dereference(physicsScene); | ||
942 | } | ||
943 | else | ||
944 | { | ||
945 | BSShapeConvexHull chullDesc; | ||
946 | if (BSShapeConvexHull.TryGetHullByPtr(pShape, out chullDesc)) | ||
947 | { | ||
948 | chullDesc.Dereference(physicsScene); | ||
949 | } | ||
950 | else | ||
951 | { | ||
952 | BSShapeGImpact gImpactDesc; | ||
953 | if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc)) | ||
954 | { | ||
955 | gImpactDesc.Dereference(physicsScene); | ||
956 | } | ||
957 | else | ||
958 | { | ||
959 | // Didn't find it in the lists of specific types. It could be compound. | ||
960 | if (physicsScene.PE.IsCompound(pShape)) | ||
961 | { | ||
962 | BSShapeCompound recursiveCompound = new BSShapeCompound(pShape); | ||
963 | recursiveCompound.Dereference(physicsScene); | ||
964 | } | ||
965 | else | ||
966 | { | ||
967 | // If none of the above, maybe it is a simple native shape. | ||
968 | if (physicsScene.PE.IsNativeShape(pShape)) | ||
969 | { | ||
970 | BSShapeNative nativeShape = new BSShapeNative(pShape); | ||
971 | nativeShape.Dereference(physicsScene); | ||
972 | } | ||
973 | } | ||
974 | } | ||
975 | } | ||
976 | } | ||
977 | } | ||
215 | } | 978 | } |
216 | public override void Dereference(BSScene physicsScene) { } | ||
217 | } | 979 | } |
218 | 980 | ||
981 | // ============================================================================================================ | ||
982 | public class BSShapeConvexHull : BSShape | ||
983 | { | ||
984 | private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]"; | ||
985 | public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>(); | ||
986 | |||
987 | public BSShapeConvexHull(BulletShape pShape) : base(pShape) | ||
988 | { | ||
989 | } | ||
990 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
991 | { | ||
992 | float lod; | ||
993 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
994 | |||
995 | physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}", | ||
996 | prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); | ||
997 | |||
998 | BSShapeConvexHull retConvexHull = null; | ||
999 | lock (ConvexHulls) | ||
1000 | { | ||
1001 | if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull)) | ||
1002 | { | ||
1003 | // The mesh has already been created. Return a new reference to same. | ||
1004 | retConvexHull.IncrementReference(); | ||
1005 | } | ||
1006 | else | ||
1007 | { | ||
1008 | retConvexHull = new BSShapeConvexHull(new BulletShape()); | ||
1009 | BulletShape convexShape = null; | ||
1010 | |||
1011 | // Get a handle to a mesh to build the hull from | ||
1012 | BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim); | ||
1013 | if (baseMesh.physShapeInfo.isNativeShape) | ||
1014 | { | ||
1015 | // We get here if the mesh was not creatable. Could be waiting for an asset from the disk. | ||
1016 | // In the short term, we return the native shape and a later ForceBodyShapeRebuild should | ||
1017 | // get back to this code with a buildable mesh. | ||
1018 | // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed? | ||
1019 | convexShape = baseMesh.physShapeInfo; | ||
1020 | } | ||
1021 | else | ||
1022 | { | ||
1023 | convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo); | ||
1024 | convexShape.shapeKey = newMeshKey; | ||
1025 | ConvexHulls.Add(convexShape.shapeKey, retConvexHull); | ||
1026 | } | ||
1027 | |||
1028 | // Done with the base mesh | ||
1029 | baseMesh.Dereference(physicsScene); | ||
1030 | |||
1031 | retConvexHull.physShapeInfo = convexShape; | ||
1032 | } | ||
1033 | } | ||
1034 | return retConvexHull; | ||
1035 | } | ||
1036 | public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) | ||
1037 | { | ||
1038 | // Calling this reference means we want another handle to an existing shape | ||
1039 | // (usually linksets) so return this copy. | ||
1040 | IncrementReference(); | ||
1041 | return this; | ||
1042 | } | ||
1043 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
1044 | public override void Dereference(BSScene physicsScene) | ||
1045 | { | ||
1046 | lock (ConvexHulls) | ||
1047 | { | ||
1048 | this.DecrementReference(); | ||
1049 | physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
1050 | // TODO: schedule aging and destruction of unused meshes. | ||
1051 | } | ||
1052 | } | ||
1053 | // Loop through all the known hulls and return the description based on the physical address. | ||
1054 | public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull) | ||
1055 | { | ||
1056 | bool ret = false; | ||
1057 | BSShapeConvexHull foundDesc = null; | ||
1058 | lock (ConvexHulls) | ||
1059 | { | ||
1060 | foreach (BSShapeConvexHull sh in ConvexHulls.Values) | ||
1061 | { | ||
1062 | if (sh.physShapeInfo.ReferenceSame(pShape)) | ||
1063 | { | ||
1064 | foundDesc = sh; | ||
1065 | ret = true; | ||
1066 | break; | ||
1067 | } | ||
1068 | |||
1069 | } | ||
1070 | } | ||
1071 | outHull = foundDesc; | ||
1072 | return ret; | ||
1073 | } | ||
1074 | } | ||
1075 | // ============================================================================================================ | ||
1076 | public class BSShapeGImpact : BSShape | ||
1077 | { | ||
1078 | private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]"; | ||
1079 | public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>(); | ||
1080 | |||
1081 | public BSShapeGImpact(BulletShape pShape) : base(pShape) | ||
1082 | { | ||
1083 | } | ||
1084 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
1085 | { | ||
1086 | float lod; | ||
1087 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
1088 | |||
1089 | physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}", | ||
1090 | prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); | ||
1091 | |||
1092 | BSShapeGImpact retGImpact = null; | ||
1093 | lock (GImpacts) | ||
1094 | { | ||
1095 | if (GImpacts.TryGetValue(newMeshKey, out retGImpact)) | ||
1096 | { | ||
1097 | // The mesh has already been created. Return a new reference to same. | ||
1098 | retGImpact.IncrementReference(); | ||
1099 | } | ||
1100 | else | ||
1101 | { | ||
1102 | retGImpact = new BSShapeGImpact(new BulletShape()); | ||
1103 | BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); | ||
1104 | |||
1105 | // Check to see if mesh was created (might require an asset). | ||
1106 | newShape = VerifyMeshCreated(physicsScene, newShape, prim); | ||
1107 | newShape.shapeKey = newMeshKey; | ||
1108 | if (!newShape.isNativeShape | ||
1109 | || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing | ||
1110 | || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) | ||
1111 | { | ||
1112 | // If a mesh was what was created, remember the built shape for later sharing. | ||
1113 | // Also note that if meshing failed we put it in the mesh list as there is nothing | ||
1114 | // else to do about the mesh. | ||
1115 | GImpacts.Add(newMeshKey, retGImpact); | ||
1116 | } | ||
1117 | |||
1118 | retGImpact.physShapeInfo = newShape; | ||
1119 | } | ||
1120 | } | ||
1121 | return retGImpact; | ||
1122 | } | ||
1123 | |||
1124 | private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, | ||
1125 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
1126 | { | ||
1127 | return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, | ||
1128 | (w, iC, i, vC, v) => physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v) ); | ||
1129 | } | ||
1130 | |||
1131 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
1132 | { | ||
1133 | BSShape ret = null; | ||
1134 | // If the underlying shape is native, the actual shape has not been build (waiting for asset) | ||
1135 | // and we must create a copy of the native shape since they are never shared. | ||
1136 | if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) | ||
1137 | { | ||
1138 | // TODO: decide when the native shapes should be freed. Check in Dereference? | ||
1139 | ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
1140 | } | ||
1141 | else | ||
1142 | { | ||
1143 | // Another reference to this shape is just counted. | ||
1144 | IncrementReference(); | ||
1145 | ret = this; | ||
1146 | } | ||
1147 | return ret; | ||
1148 | } | ||
1149 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
1150 | public override void Dereference(BSScene physicsScene) | ||
1151 | { | ||
1152 | lock (GImpacts) | ||
1153 | { | ||
1154 | this.DecrementReference(); | ||
1155 | physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
1156 | // TODO: schedule aging and destruction of unused meshes. | ||
1157 | } | ||
1158 | } | ||
1159 | // Loop through all the known hulls and return the description based on the physical address. | ||
1160 | public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull) | ||
1161 | { | ||
1162 | bool ret = false; | ||
1163 | BSShapeGImpact foundDesc = null; | ||
1164 | lock (GImpacts) | ||
1165 | { | ||
1166 | foreach (BSShapeGImpact sh in GImpacts.Values) | ||
1167 | { | ||
1168 | if (sh.physShapeInfo.ReferenceSame(pShape)) | ||
1169 | { | ||
1170 | foundDesc = sh; | ||
1171 | ret = true; | ||
1172 | break; | ||
1173 | } | ||
1174 | |||
1175 | } | ||
1176 | } | ||
1177 | outHull = foundDesc; | ||
1178 | return ret; | ||
1179 | } | ||
1180 | } | ||
1181 | |||
1182 | // ============================================================================================================ | ||
219 | public class BSShapeAvatar : BSShape | 1183 | public class BSShapeAvatar : BSShape |
220 | { | 1184 | { |
221 | private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; | 1185 | private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; |
222 | public BSShapeAvatar() : base() | 1186 | public BSShapeAvatar() : base() |
223 | { | 1187 | { |
224 | } | 1188 | } |
225 | public static BSShape GetReference(BSPhysObject prim) | 1189 | public static BSShape GetReference(BSPhysObject prim) |
226 | { | 1190 | { |
1191 | return new BSShapeNull(); | ||
1192 | } | ||
1193 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
1194 | { | ||
227 | return new BSShapeNull(); | 1195 | return new BSShapeNull(); |
228 | } | 1196 | } |
229 | public override void Dereference(BSScene physicsScene) { } | 1197 | public override void Dereference(BSScene physicsScene) { } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index e4fecc3..c7deb4e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs | |||
@@ -68,7 +68,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
68 | 68 | ||
69 | // This minCoords and maxCoords passed in give the size of the terrain (min and max Z | 69 | // This minCoords and maxCoords passed in give the size of the terrain (min and max Z |
70 | // are the high and low points of the heightmap). | 70 | // are the high and low points of the heightmap). |
71 | public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, | 71 | public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, |
72 | Vector3 minCoords, Vector3 maxCoords) | 72 | Vector3 minCoords, Vector3 maxCoords) |
73 | : base(physicsScene, regionBase, id) | 73 | : base(physicsScene, regionBase, id) |
74 | { | 74 | { |
@@ -92,7 +92,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
92 | private void BuildHeightmapTerrain() | 92 | private void BuildHeightmapTerrain() |
93 | { | 93 | { |
94 | // Create the terrain shape from the mapInfo | 94 | // Create the terrain shape from the mapInfo |
95 | m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID, | 95 | m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID, |
96 | new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, | 96 | new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, |
97 | m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); | 97 | m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); |
98 | 98 | ||
@@ -103,26 +103,26 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
103 | centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); | 103 | centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); |
104 | centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); | 104 | centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); |
105 | 105 | ||
106 | m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, | 106 | m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, |
107 | m_mapInfo.ID, centerPos, Quaternion.Identity); | 107 | m_mapInfo.ID, centerPos, Quaternion.Identity); |
108 | 108 | ||
109 | // Set current terrain attributes | 109 | // Set current terrain attributes |
110 | PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); | 110 | m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); |
111 | PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); | 111 | m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); |
112 | PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); | 112 | m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); |
113 | PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); | 113 | m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); |
114 | 114 | ||
115 | // Return the new terrain to the world of physical objects | 115 | // Return the new terrain to the world of physical objects |
116 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody); | 116 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody); |
117 | 117 | ||
118 | // redo its bounding box now that it is in the world | 118 | // redo its bounding box now that it is in the world |
119 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody); | 119 | m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody); |
120 | 120 | ||
121 | m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; | 121 | m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; |
122 | m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene); | 122 | m_mapInfo.terrainBody.ApplyCollisionMask(m_physicsScene); |
123 | 123 | ||
124 | // Make it so the terrain will not move or be considered for movement. | 124 | // Make it so the terrain will not move or be considered for movement. |
125 | PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); | 125 | m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); |
126 | 126 | ||
127 | return; | 127 | return; |
128 | } | 128 | } |
@@ -134,9 +134,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
134 | { | 134 | { |
135 | if (m_mapInfo.terrainBody.HasPhysicalBody) | 135 | if (m_mapInfo.terrainBody.HasPhysicalBody) |
136 | { | 136 | { |
137 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody); | 137 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody); |
138 | // Frees both the body and the shape. | 138 | // Frees both the body and the shape. |
139 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody); | 139 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody); |
140 | } | 140 | } |
141 | } | 141 | } |
142 | m_mapInfo = null; | 142 | m_mapInfo = null; |
@@ -155,7 +155,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
155 | catch | 155 | catch |
156 | { | 156 | { |
157 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. | 157 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. |
158 | PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", | 158 | m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", |
159 | LogHeader, m_mapInfo.terrainRegionBase, pos); | 159 | LogHeader, m_mapInfo.terrainRegionBase, pos); |
160 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | 160 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; |
161 | } | 161 | } |
@@ -165,7 +165,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
165 | // The passed position is relative to the base of the region. | 165 | // The passed position is relative to the base of the region. |
166 | public override float GetWaterLevelAtXYZ(Vector3 pos) | 166 | public override float GetWaterLevelAtXYZ(Vector3 pos) |
167 | { | 167 | { |
168 | return PhysicsScene.SimpleWaterLevel; | 168 | return m_physicsScene.SimpleWaterLevel; |
169 | } | 169 | } |
170 | } | 170 | } |
171 | } | 171 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index b2fb835..c4807c4 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -50,14 +50,14 @@ public abstract class BSTerrainPhys : IDisposable | |||
50 | Mesh = 1 | 50 | Mesh = 1 |
51 | } | 51 | } |
52 | 52 | ||
53 | public BSScene PhysicsScene { get; private set; } | 53 | protected BSScene m_physicsScene { get; private set; } |
54 | // Base of the region in world coordinates. Coordinates inside the region are relative to this. | 54 | // Base of the region in world coordinates. Coordinates inside the region are relative to this. |
55 | public Vector3 TerrainBase { get; private set; } | 55 | public Vector3 TerrainBase { get; private set; } |
56 | public uint ID { get; private set; } | 56 | public uint ID { get; private set; } |
57 | 57 | ||
58 | public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) | 58 | public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) |
59 | { | 59 | { |
60 | PhysicsScene = physicsScene; | 60 | m_physicsScene = physicsScene; |
61 | TerrainBase = regionBase; | 61 | TerrainBase = regionBase; |
62 | ID = id; | 62 | ID = id; |
63 | } | 63 | } |
@@ -86,7 +86,7 @@ public sealed class BSTerrainManager : IDisposable | |||
86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | 86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); |
87 | 87 | ||
88 | // The scene that I am part of | 88 | // The scene that I am part of |
89 | private BSScene PhysicsScene { get; set; } | 89 | private BSScene m_physicsScene { get; set; } |
90 | 90 | ||
91 | // The ground plane created to keep thing from falling to infinity. | 91 | // The ground plane created to keep thing from falling to infinity. |
92 | private BulletBody m_groundPlane; | 92 | private BulletBody m_groundPlane; |
@@ -113,7 +113,7 @@ public sealed class BSTerrainManager : IDisposable | |||
113 | 113 | ||
114 | public BSTerrainManager(BSScene physicsScene) | 114 | public BSTerrainManager(BSScene physicsScene) |
115 | { | 115 | { |
116 | PhysicsScene = physicsScene; | 116 | m_physicsScene = physicsScene; |
117 | m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); | 117 | m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); |
118 | 118 | ||
119 | // Assume one region of default size | 119 | // Assume one region of default size |
@@ -132,21 +132,21 @@ public sealed class BSTerrainManager : IDisposable | |||
132 | // safe to call Bullet in real time. We hope no one is moving prims around yet. | 132 | // safe to call Bullet in real time. We hope no one is moving prims around yet. |
133 | public void CreateInitialGroundPlaneAndTerrain() | 133 | public void CreateInitialGroundPlaneAndTerrain() |
134 | { | 134 | { |
135 | DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); | 135 | DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); |
136 | // The ground plane is here to catch things that are trying to drop to negative infinity | 136 | // The ground plane is here to catch things that are trying to drop to negative infinity |
137 | BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); | 137 | BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); |
138 | m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, | 138 | m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, |
139 | BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); | 139 | BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); |
140 | 140 | ||
141 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane); | 141 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane); |
142 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane); | 142 | m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane); |
143 | // Ground plane does not move | 143 | // Ground plane does not move |
144 | PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); | 144 | m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); |
145 | // Everything collides with the ground plane. | 145 | // Everything collides with the ground plane. |
146 | m_groundPlane.collisionType = CollisionType.Groundplane; | 146 | m_groundPlane.collisionType = CollisionType.Groundplane; |
147 | m_groundPlane.ApplyCollisionMask(PhysicsScene); | 147 | m_groundPlane.ApplyCollisionMask(m_physicsScene); |
148 | 148 | ||
149 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); | 149 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); |
150 | lock (m_terrains) | 150 | lock (m_terrains) |
151 | { | 151 | { |
152 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | 152 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. |
@@ -157,12 +157,12 @@ public sealed class BSTerrainManager : IDisposable | |||
157 | // Release all the terrain structures we might have allocated | 157 | // Release all the terrain structures we might have allocated |
158 | public void ReleaseGroundPlaneAndTerrain() | 158 | public void ReleaseGroundPlaneAndTerrain() |
159 | { | 159 | { |
160 | DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); | 160 | DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); |
161 | if (m_groundPlane.HasPhysicalBody) | 161 | if (m_groundPlane.HasPhysicalBody) |
162 | { | 162 | { |
163 | if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) | 163 | if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane)) |
164 | { | 164 | { |
165 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); | 165 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane); |
166 | } | 166 | } |
167 | m_groundPlane.Clear(); | 167 | m_groundPlane.Clear(); |
168 | } | 168 | } |
@@ -188,7 +188,7 @@ public sealed class BSTerrainManager : IDisposable | |||
188 | float[] localHeightMap = heightMap; | 188 | float[] localHeightMap = heightMap; |
189 | // If there are multiple requests for changes to the same terrain between ticks, | 189 | // If there are multiple requests for changes to the same terrain between ticks, |
190 | // only do that last one. | 190 | // only do that last one. |
191 | PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() | 191 | m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() |
192 | { | 192 | { |
193 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) | 193 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) |
194 | { | 194 | { |
@@ -199,15 +199,8 @@ public sealed class BSTerrainManager : IDisposable | |||
199 | if (MegaRegionParentPhysicsScene is BSScene) | 199 | if (MegaRegionParentPhysicsScene is BSScene) |
200 | { | 200 | { |
201 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); | 201 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); |
202 | // This looks really odd but this region is passing its terrain to its mega-region root region | 202 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain( |
203 | // and the creation of the terrain must happen on the root region's taint thread and not | 203 | BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); |
204 | // my taint thread. | ||
205 | ((BSScene)MegaRegionParentPhysicsScene).PostTaintObject("TerrainManager.SetTerrain.Mega-" + m_worldOffset.ToString(), 0, delegate() | ||
206 | { | ||
207 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( | ||
208 | BSScene.CHILDTERRAIN_ID, localHeightMap, | ||
209 | m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */); | ||
210 | }); | ||
211 | } | 204 | } |
212 | } | 205 | } |
213 | else | 206 | else |
@@ -215,12 +208,23 @@ public sealed class BSTerrainManager : IDisposable | |||
215 | // If not doing the mega-prim thing, just change the terrain | 208 | // If not doing the mega-prim thing, just change the terrain |
216 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); | 209 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); |
217 | 210 | ||
218 | UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, | 211 | UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); |
219 | m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */); | ||
220 | } | 212 | } |
221 | }); | 213 | }); |
222 | } | 214 | } |
223 | 215 | ||
216 | // Another region is calling this region and passing a terrain. | ||
217 | // A region that is not the mega-region root will pass its terrain to the root region so the root region | ||
218 | // physics engine will have all the terrains. | ||
219 | private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) | ||
220 | { | ||
221 | // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. | ||
222 | m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate() | ||
223 | { | ||
224 | UpdateTerrain(id, heightMap, minCoords, maxCoords); | ||
225 | }); | ||
226 | } | ||
227 | |||
224 | // If called for terrain has has not been previously allocated, a new terrain will be built | 228 | // If called for terrain has has not been previously allocated, a new terrain will be built |
225 | // based on the passed information. The 'id' should be either the terrain id or | 229 | // based on the passed information. The 'id' should be either the terrain id or |
226 | // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. | 230 | // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. |
@@ -230,11 +234,10 @@ public sealed class BSTerrainManager : IDisposable | |||
230 | // This call is most often used to update the heightMap and parameters of the terrain. | 234 | // This call is most often used to update the heightMap and parameters of the terrain. |
231 | // (The above does suggest that some simplification/refactoring is in order.) | 235 | // (The above does suggest that some simplification/refactoring is in order.) |
232 | // Called during taint-time. | 236 | // Called during taint-time. |
233 | private void UpdateTerrain(uint id, float[] heightMap, | 237 | private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) |
234 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | ||
235 | { | 238 | { |
236 | DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3},inTaintTime={4}", | 239 | DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}", |
237 | BSScene.DetailLogZero, id, minCoords, maxCoords, inTaintTime); | 240 | BSScene.DetailLogZero, id, minCoords, maxCoords); |
238 | 241 | ||
239 | // Find high and low points of passed heightmap. | 242 | // Find high and low points of passed heightmap. |
240 | // The min and max passed in is usually the area objects can be in (maximum | 243 | // The min and max passed in is usually the area objects can be in (maximum |
@@ -303,7 +306,7 @@ public sealed class BSTerrainManager : IDisposable | |||
303 | newTerrainID = ++m_terrainCount; | 306 | newTerrainID = ++m_terrainCount; |
304 | 307 | ||
305 | DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", | 308 | DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", |
306 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | 309 | BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords); |
307 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | 310 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
308 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | 311 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
309 | 312 | ||
@@ -315,26 +318,26 @@ public sealed class BSTerrainManager : IDisposable | |||
315 | // TODO: redo terrain implementation selection to allow other base types than heightMap. | 318 | // TODO: redo terrain implementation selection to allow other base types than heightMap. |
316 | private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) | 319 | private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) |
317 | { | 320 | { |
318 | PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", | 321 | m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", |
319 | LogHeader, PhysicsScene.RegionName, terrainRegionBase, | 322 | LogHeader, m_physicsScene.RegionName, terrainRegionBase, |
320 | (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); | 323 | (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); |
321 | BSTerrainPhys newTerrainPhys = null; | 324 | BSTerrainPhys newTerrainPhys = null; |
322 | switch ((int)BSParam.TerrainImplementation) | 325 | switch ((int)BSParam.TerrainImplementation) |
323 | { | 326 | { |
324 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: | 327 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: |
325 | newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, | 328 | newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id, |
326 | heightMap, minCoords, maxCoords); | 329 | heightMap, minCoords, maxCoords); |
327 | break; | 330 | break; |
328 | case (int)BSTerrainPhys.TerrainImplementation.Mesh: | 331 | case (int)BSTerrainPhys.TerrainImplementation.Mesh: |
329 | newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, | 332 | newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id, |
330 | heightMap, minCoords, maxCoords); | 333 | heightMap, minCoords, maxCoords); |
331 | break; | 334 | break; |
332 | default: | 335 | default: |
333 | PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", | 336 | m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", |
334 | LogHeader, | 337 | LogHeader, |
335 | (int)BSParam.TerrainImplementation, | 338 | (int)BSParam.TerrainImplementation, |
336 | BSParam.TerrainImplementation, | 339 | BSParam.TerrainImplementation, |
337 | PhysicsScene.RegionName, terrainRegionBase); | 340 | m_physicsScene.RegionName, terrainRegionBase); |
338 | break; | 341 | break; |
339 | } | 342 | } |
340 | return newTerrainPhys; | 343 | return newTerrainPhys; |
@@ -426,8 +429,8 @@ public sealed class BSTerrainManager : IDisposable | |||
426 | } | 429 | } |
427 | else | 430 | else |
428 | { | 431 | { |
429 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | 432 | m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", |
430 | LogHeader, PhysicsScene.RegionName, tX, tY); | 433 | LogHeader, m_physicsScene.RegionName, tX, tY); |
431 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", | 434 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", |
432 | BSScene.DetailLogZero, pos, terrainBaseXYZ); | 435 | BSScene.DetailLogZero, pos, terrainBaseXYZ); |
433 | } | 436 | } |
@@ -448,8 +451,8 @@ public sealed class BSTerrainManager : IDisposable | |||
448 | } | 451 | } |
449 | else | 452 | else |
450 | { | 453 | { |
451 | PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", | 454 | m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", |
452 | LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); | 455 | LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret); |
453 | } | 456 | } |
454 | return ret; | 457 | return ret; |
455 | } | 458 | } |
@@ -561,7 +564,7 @@ public sealed class BSTerrainManager : IDisposable | |||
561 | 564 | ||
562 | private void DetailLog(string msg, params Object[] args) | 565 | private void DetailLog(string msg, params Object[] args) |
563 | { | 566 | { |
564 | PhysicsScene.PhysicsLogging.Write(msg, args); | 567 | m_physicsScene.PhysicsLogging.Write(msg, args); |
565 | } | 568 | } |
566 | } | 569 | } |
567 | } | 570 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index 2ce1513..e4ca098 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs | |||
@@ -51,7 +51,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
51 | BulletShape m_terrainShape; | 51 | BulletShape m_terrainShape; |
52 | BulletBody m_terrainBody; | 52 | BulletBody m_terrainBody; |
53 | 53 | ||
54 | public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) | 54 | public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) |
55 | : base(physicsScene, regionBase, id) | 55 | : base(physicsScene, regionBase, id) |
56 | { | 56 | { |
57 | } | 57 | } |
@@ -62,7 +62,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
62 | } | 62 | } |
63 | 63 | ||
64 | // Create terrain mesh from a heightmap. | 64 | // Create terrain mesh from a heightmap. |
65 | public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, | 65 | public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, |
66 | Vector3 minCoords, Vector3 maxCoords) | 66 | Vector3 minCoords, Vector3 maxCoords) |
67 | : base(physicsScene, regionBase, id) | 67 | : base(physicsScene, regionBase, id) |
68 | { | 68 | { |
@@ -80,7 +80,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
80 | if (BSParam.TerrainMeshMagnification == 1) | 80 | if (BSParam.TerrainMeshMagnification == 1) |
81 | { | 81 | { |
82 | // If a magnification of one, use the old routine that is tried and true. | 82 | // If a magnification of one, use the old routine that is tried and true. |
83 | meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, | 83 | meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene, |
84 | initialMap, m_sizeX, m_sizeY, // input size | 84 | initialMap, m_sizeX, m_sizeY, // input size |
85 | Vector3.Zero, // base for mesh | 85 | Vector3.Zero, // base for mesh |
86 | out indicesCount, out indices, out verticesCount, out vertices); | 86 | out indicesCount, out indices, out verticesCount, out vertices); |
@@ -88,7 +88,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
88 | else | 88 | else |
89 | { | 89 | { |
90 | // Other magnifications use the newer routine | 90 | // Other magnifications use the newer routine |
91 | meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene, | 91 | meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene, |
92 | initialMap, m_sizeX, m_sizeY, // input size | 92 | initialMap, m_sizeX, m_sizeY, // input size |
93 | BSParam.TerrainMeshMagnification, | 93 | BSParam.TerrainMeshMagnification, |
94 | physicsScene.TerrainManager.DefaultRegionSize, | 94 | physicsScene.TerrainManager.DefaultRegionSize, |
@@ -98,21 +98,21 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
98 | if (!meshCreationSuccess) | 98 | if (!meshCreationSuccess) |
99 | { | 99 | { |
100 | // DISASTER!! | 100 | // DISASTER!! |
101 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); | 101 | m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); |
102 | PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); | 102 | m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); |
103 | // Something is very messed up and a crash is in our future. | 103 | // Something is very messed up and a crash is in our future. |
104 | return; | 104 | return; |
105 | } | 105 | } |
106 | 106 | ||
107 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", | 107 | m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", |
108 | BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); | 108 | BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); |
109 | 109 | ||
110 | m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); | 110 | m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices); |
111 | if (!m_terrainShape.HasPhysicalShape) | 111 | if (!m_terrainShape.HasPhysicalShape) |
112 | { | 112 | { |
113 | // DISASTER!! | 113 | // DISASTER!! |
114 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); | 114 | m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); |
115 | PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); | 115 | m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); |
116 | // Something is very messed up and a crash is in our future. | 116 | // Something is very messed up and a crash is in our future. |
117 | return; | 117 | return; |
118 | } | 118 | } |
@@ -120,52 +120,52 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
120 | Vector3 pos = regionBase; | 120 | Vector3 pos = regionBase; |
121 | Quaternion rot = Quaternion.Identity; | 121 | Quaternion rot = Quaternion.Identity; |
122 | 122 | ||
123 | m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); | 123 | m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); |
124 | if (!m_terrainBody.HasPhysicalBody) | 124 | if (!m_terrainBody.HasPhysicalBody) |
125 | { | 125 | { |
126 | // DISASTER!! | 126 | // DISASTER!! |
127 | PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); | 127 | m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); |
128 | // Something is very messed up and a crash is in our future. | 128 | // Something is very messed up and a crash is in our future. |
129 | return; | 129 | return; |
130 | } | 130 | } |
131 | physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); | 131 | physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); |
132 | 132 | ||
133 | // Set current terrain attributes | 133 | // Set current terrain attributes |
134 | PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); | 134 | m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); |
135 | PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); | 135 | m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); |
136 | PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); | 136 | m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); |
137 | PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); | 137 | m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); |
138 | PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); | 138 | m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); |
139 | 139 | ||
140 | // Static objects are not very massive. | 140 | // Static objects are not very massive. |
141 | PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); | 141 | m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); |
142 | 142 | ||
143 | // Put the new terrain to the world of physical objects | 143 | // Put the new terrain to the world of physical objects |
144 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody); | 144 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody); |
145 | 145 | ||
146 | // Redo its bounding box now that it is in the world | 146 | // Redo its bounding box now that it is in the world |
147 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody); | 147 | m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody); |
148 | 148 | ||
149 | m_terrainBody.collisionType = CollisionType.Terrain; | 149 | m_terrainBody.collisionType = CollisionType.Terrain; |
150 | m_terrainBody.ApplyCollisionMask(PhysicsScene); | 150 | m_terrainBody.ApplyCollisionMask(m_physicsScene); |
151 | 151 | ||
152 | if (BSParam.UseSingleSidedMeshes) | 152 | if (BSParam.UseSingleSidedMeshes) |
153 | { | 153 | { |
154 | PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); | 154 | m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); |
155 | PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); | 155 | m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); |
156 | } | 156 | } |
157 | 157 | ||
158 | // Make it so the terrain will not move or be considered for movement. | 158 | // Make it so the terrain will not move or be considered for movement. |
159 | PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); | 159 | m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); |
160 | } | 160 | } |
161 | 161 | ||
162 | public override void Dispose() | 162 | public override void Dispose() |
163 | { | 163 | { |
164 | if (m_terrainBody.HasPhysicalBody) | 164 | if (m_terrainBody.HasPhysicalBody) |
165 | { | 165 | { |
166 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody); | 166 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody); |
167 | // Frees both the body and the shape. | 167 | // Frees both the body and the shape. |
168 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody); | 168 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody); |
169 | m_terrainBody.Clear(); | 169 | m_terrainBody.Clear(); |
170 | m_terrainShape.Clear(); | 170 | m_terrainShape.Clear(); |
171 | } | 171 | } |
@@ -185,7 +185,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
185 | catch | 185 | catch |
186 | { | 186 | { |
187 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. | 187 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. |
188 | PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", | 188 | m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", |
189 | LogHeader, TerrainBase, pos); | 189 | LogHeader, TerrainBase, pos); |
190 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | 190 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; |
191 | } | 191 | } |
@@ -195,7 +195,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
195 | // The passed position is relative to the base of the region. | 195 | // The passed position is relative to the base of the region. |
196 | public override float GetWaterLevelAtXYZ(Vector3 pos) | 196 | public override float GetWaterLevelAtXYZ(Vector3 pos) |
197 | { | 197 | { |
198 | return PhysicsScene.SimpleWaterLevel; | 198 | return m_physicsScene.SimpleWaterLevel; |
199 | } | 199 | } |
200 | 200 | ||
201 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | 201 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs index 8012d91..d5060e3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs | |||
@@ -104,11 +104,11 @@ public class BulletShape | |||
104 | { | 104 | { |
105 | public BulletShape() | 105 | public BulletShape() |
106 | { | 106 | { |
107 | type = BSPhysicsShapeType.SHAPE_UNKNOWN; | 107 | shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN; |
108 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; | 108 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; |
109 | isNativeShape = false; | 109 | isNativeShape = false; |
110 | } | 110 | } |
111 | public BSPhysicsShapeType type; | 111 | public BSPhysicsShapeType shapeType; |
112 | public System.UInt64 shapeKey; | 112 | public System.UInt64 shapeKey; |
113 | public bool isNativeShape; | 113 | public bool isNativeShape; |
114 | 114 | ||
@@ -133,7 +133,7 @@ public class BulletShape | |||
133 | buff.Append("<p="); | 133 | buff.Append("<p="); |
134 | buff.Append(AddrString); | 134 | buff.Append(AddrString); |
135 | buff.Append(",s="); | 135 | buff.Append(",s="); |
136 | buff.Append(type.ToString()); | 136 | buff.Append(shapeType.ToString()); |
137 | buff.Append(",k="); | 137 | buff.Append(",k="); |
138 | buff.Append(shapeKey.ToString("X")); | 138 | buff.Append(shapeKey.ToString("X")); |
139 | buff.Append(",n="); | 139 | buff.Append(",n="); |
@@ -224,42 +224,42 @@ public static class BulletSimData | |||
224 | // As mentioned above, don't use the CollisionFilterGroups definitions directly in the code | 224 | // As mentioned above, don't use the CollisionFilterGroups definitions directly in the code |
225 | // but, instead, use references to this dictionary. Finding and debugging | 225 | // but, instead, use references to this dictionary. Finding and debugging |
226 | // collision flag problems will be made easier. | 226 | // collision flag problems will be made easier. |
227 | public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks | 227 | public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks |
228 | = new Dictionary<CollisionType, CollisionTypeFilterGroup>() | 228 | = new Dictionary<CollisionType, CollisionTypeFilterGroup>() |
229 | { | 229 | { |
230 | { CollisionType.Avatar, | 230 | { CollisionType.Avatar, |
231 | new CollisionTypeFilterGroup(CollisionType.Avatar, | 231 | new CollisionTypeFilterGroup(CollisionType.Avatar, |
232 | (uint)CollisionFilterGroups.BCharacterGroup, | 232 | (uint)CollisionFilterGroups.BCharacterGroup, |
233 | (uint)CollisionFilterGroups.BAllGroup) | 233 | (uint)CollisionFilterGroups.BAllGroup) |
234 | }, | 234 | }, |
235 | { CollisionType.Groundplane, | 235 | { CollisionType.Groundplane, |
236 | new CollisionTypeFilterGroup(CollisionType.Groundplane, | 236 | new CollisionTypeFilterGroup(CollisionType.Groundplane, |
237 | (uint)CollisionFilterGroups.BGroundPlaneGroup, | 237 | (uint)CollisionFilterGroups.BGroundPlaneGroup, |
238 | (uint)CollisionFilterGroups.BAllGroup) | 238 | (uint)CollisionFilterGroups.BAllGroup) |
239 | }, | 239 | }, |
240 | { CollisionType.Terrain, | 240 | { CollisionType.Terrain, |
241 | new CollisionTypeFilterGroup(CollisionType.Terrain, | 241 | new CollisionTypeFilterGroup(CollisionType.Terrain, |
242 | (uint)CollisionFilterGroups.BTerrainGroup, | 242 | (uint)CollisionFilterGroups.BTerrainGroup, |
243 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) | 243 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) |
244 | }, | 244 | }, |
245 | { CollisionType.Static, | 245 | { CollisionType.Static, |
246 | new CollisionTypeFilterGroup(CollisionType.Static, | 246 | new CollisionTypeFilterGroup(CollisionType.Static, |
247 | (uint)CollisionFilterGroups.BStaticGroup, | 247 | (uint)CollisionFilterGroups.BStaticGroup, |
248 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | 248 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) |
249 | }, | 249 | }, |
250 | { CollisionType.Dynamic, | 250 | { CollisionType.Dynamic, |
251 | new CollisionTypeFilterGroup(CollisionType.Dynamic, | 251 | new CollisionTypeFilterGroup(CollisionType.Dynamic, |
252 | (uint)CollisionFilterGroups.BSolidGroup, | 252 | (uint)CollisionFilterGroups.BSolidGroup, |
253 | (uint)(CollisionFilterGroups.BAllGroup)) | 253 | (uint)(CollisionFilterGroups.BAllGroup)) |
254 | }, | 254 | }, |
255 | { CollisionType.VolumeDetect, | 255 | { CollisionType.VolumeDetect, |
256 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, | 256 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, |
257 | (uint)CollisionFilterGroups.BSensorTrigger, | 257 | (uint)CollisionFilterGroups.BSensorTrigger, |
258 | (uint)(~CollisionFilterGroups.BSensorTrigger)) | 258 | (uint)(~CollisionFilterGroups.BSensorTrigger)) |
259 | }, | 259 | }, |
260 | { CollisionType.LinksetChild, | 260 | { CollisionType.LinksetChild, |
261 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, | 261 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, |
262 | (uint)CollisionFilterGroups.BLinksetChildGroup, | 262 | (uint)CollisionFilterGroups.BLinksetChildGroup, |
263 | (uint)(CollisionFilterGroups.BNoneGroup)) | 263 | (uint)(CollisionFilterGroups.BNoneGroup)) |
264 | // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | 264 | // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) |
265 | }, | 265 | }, |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index 8a15abe..4357ef1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | |||
@@ -1,41 +1,38 @@ | |||
1 | CURRENT PRIORITIES | 1 | CURRENT PROBLEMS TO FIX AND/OR LOOK AT |
2 | ================================================= | 2 | ================================================= |
3 | Use the HACD convex hull routine in Bullet rather than the C# version. | 3 | Vehicle buoyancy. Computed correctly? Possibly creating very large effective mass. |
4 | Speed up hullifying large meshes. | 4 | Interaction of llSetBuoyancy and vehicle buoyancy. Should be additive? |
5 | Negative buoyancy computed correctly | ||
6 | Computation of mesh mass. How done? How should it be done? | ||
7 | Script changing rotation of child prim while vehicle moving (eg turning wheel) causes | ||
8 | the wheel to appear to jump back. Looks like sending position from previous update. | ||
5 | Enable vehicle border crossings (at least as poorly as ODE) | 9 | Enable vehicle border crossings (at least as poorly as ODE) |
6 | Terrain skirts | 10 | Terrain skirts |
7 | Avatar created in previous region and not new region when crossing border | 11 | Avatar created in previous region and not new region when crossing border |
8 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) | 12 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) |
9 | Lock axis | ||
10 | Deleting a linkset while standing on the root will leave the physical shape of the root behind. | 13 | Deleting a linkset while standing on the root will leave the physical shape of the root behind. |
11 | Not sure if it is because standing on it. Done with large prim linksets. | 14 | Not sure if it is because standing on it. Done with large prim linksets. |
12 | Linkset child rotations. | 15 | Linkset child rotations. |
13 | Nebadon spiral tube has middle sections which are rotated wrong. | 16 | Nebadon spiral tube has middle sections which are rotated wrong. |
14 | Select linked spiral tube. Delink and note where the middle section ends up. | 17 | Select linked spiral tube. Delink and note where the middle section ends up. |
18 | Refarb compound linkset creation to create a pseudo-root for center-of-mass | ||
19 | Let children change their shape to physical indendently and just add shapes to compound | ||
15 | Vehicle angular vertical attraction | 20 | Vehicle angular vertical attraction |
16 | vehicle angular banking | 21 | vehicle angular banking |
17 | Center-of-gravity | 22 | Center-of-gravity |
18 | Vehicle angular deflection | 23 | Vehicle angular deflection |
19 | Preferred orientation angular correction fix | 24 | Preferred orientation angular correction fix |
20 | when should angular and linear motor targets be zeroed? when selected? | ||
21 | Need a vehicle.clear()? Or an 'else' in prestep if not physical. | ||
22 | Teravus llMoveToTarget script debug | 25 | Teravus llMoveToTarget script debug |
23 | Mixing of hover, buoyancy/gravity, moveToTarget, into one force | 26 | Mixing of hover, buoyancy/gravity, moveToTarget, into one force |
24 | Setting hover height to zero disables hover even if hover flags are on (from SL wiki) | 27 | Setting hover height to zero disables hover even if hover flags are on (from SL wiki) |
25 | limitMotorUp calibration (more down?) | 28 | limitMotorUp calibration (more down?) |
26 | llRotLookAt | 29 | llRotLookAt |
27 | llLookAt | 30 | llLookAt |
28 | Avatars walking up stairs (HALF DONE) | 31 | Convert to avatar mesh capsule. Include rotation of capsule. |
29 | Avatar movement | ||
30 | flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) | ||
31 | walking up stairs is not calibrated correctly (stairs out of Kepler cabin) | ||
32 | avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) | ||
33 | Vehicle script tuning/debugging | 32 | Vehicle script tuning/debugging |
34 | Avanti speed script | 33 | Avanti speed script |
35 | Weapon shooter script | 34 | Weapon shooter script |
36 | Move material definitions (friction, ...) into simulator. | 35 | Move material definitions (friction, ...) into simulator. |
37 | Add material densities to the material types. | ||
38 | Terrain detail: double terrain mesh detail | ||
39 | One sided meshes? Should terrain be built into a closed shape? | 36 | One sided meshes? Should terrain be built into a closed shape? |
40 | When meshes get partially wedged into the terrain, they cannot push themselves out. | 37 | When meshes get partially wedged into the terrain, they cannot push themselves out. |
41 | It is possible that Bullet processes collisions whether entering or leaving a mesh. | 38 | It is possible that Bullet processes collisions whether entering or leaving a mesh. |
@@ -43,12 +40,13 @@ One sided meshes? Should terrain be built into a closed shape? | |||
43 | 40 | ||
44 | VEHICLES TODO LIST: | 41 | VEHICLES TODO LIST: |
45 | ================================================= | 42 | ================================================= |
46 | Border crossing with linked vehicle causes crash | 43 | LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers. |
47 | 20121129.1411: editting/moving phys object across region boundries causes crash | 44 | What are the limits in SL? |
48 | getPos-> btRigidBody::upcast -> getBodyType -> BOOM | 45 | Same for other velocity settings. |
46 | UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims: | ||
47 | https://github.com/UbitUmarov/Ubit-opensim | ||
49 | Vehicles (Move smoothly) | 48 | Vehicles (Move smoothly) |
50 | Some vehicles should not be able to turn if no speed or off ground. | 49 | Some vehicles should not be able to turn if no speed or off ground. |
51 | What to do if vehicle and prim buoyancy differ? | ||
52 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. | 50 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. |
53 | Neb car jiggling left and right | 51 | Neb car jiggling left and right |
54 | Happens on terrain and any other mesh object. Flat cubes are much smoother. | 52 | Happens on terrain and any other mesh object. Flat cubes are much smoother. |
@@ -58,8 +56,6 @@ For limitMotorUp, use raycast down to find if vehicle is in the air. | |||
58 | Verify llGetVel() is returning a smooth and good value for vehicle movement. | 56 | Verify llGetVel() is returning a smooth and good value for vehicle movement. |
59 | llGetVel() should return the root's velocity if requested in a child prim. | 57 | llGetVel() should return the root's velocity if requested in a child prim. |
60 | Implement function efficiency for lineaar and angular motion. | 58 | Implement function efficiency for lineaar and angular motion. |
61 | After getting off a vehicle, the root prim is phantom (can be walked through) | ||
62 | Need to force a position update for the root prim after compound shape destruction | ||
63 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) | 59 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) |
64 | Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). | 60 | Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). |
65 | A kludge that isn't fixing the real problem of Bullet adding extra motion. | 61 | A kludge that isn't fixing the real problem of Bullet adding extra motion. |
@@ -68,11 +64,10 @@ Incorporate inter-relationship of angular corrections. For instance, angularDefl | |||
68 | creates over-correction and over-shoot and wabbling. | 64 | creates over-correction and over-shoot and wabbling. |
69 | Vehicle attributes are not restored when a vehicle is rezzed on region creation | 65 | Vehicle attributes are not restored when a vehicle is rezzed on region creation |
70 | Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized. | 66 | Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized. |
67 | What to do if vehicle and prim buoyancy differ? | ||
71 | 68 | ||
72 | GENERAL TODO LIST: | 69 | GENERAL TODO LIST: |
73 | ================================================= | 70 | ================================================= |
74 | Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. | ||
75 | Regular triangle meshes don't do physical collisions. | ||
76 | Resitution of a prim works on another prim but not on terrain. | 71 | Resitution of a prim works on another prim but not on terrain. |
77 | The dropped prim doesn't bounce properly on the terrain. | 72 | The dropped prim doesn't bounce properly on the terrain. |
78 | Add a sanity check for PIDTarget location. | 73 | Add a sanity check for PIDTarget location. |
@@ -168,6 +163,7 @@ Eliminate collisions between objects in a linkset. (LinksetConstraint) | |||
168 | 163 | ||
169 | MORE | 164 | MORE |
170 | ====================================================== | 165 | ====================================================== |
166 | Compute avatar size and scale correctly. Now it is a bit off from the capsule size. | ||
171 | Create tests for different interface components | 167 | Create tests for different interface components |
172 | Have test objects/scripts measure themselves and turn color if correct/bad | 168 | Have test objects/scripts measure themselves and turn color if correct/bad |
173 | Test functions in SL and calibrate correctness there | 169 | Test functions in SL and calibrate correctness there |
@@ -344,3 +340,29 @@ Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. | |||
344 | Verify that angular motion specified around Z moves in the vehicle coordinates. | 340 | Verify that angular motion specified around Z moves in the vehicle coordinates. |
345 | DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. | 341 | DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. |
346 | Nebadon vehicles turning funny in arena (DONE) | 342 | Nebadon vehicles turning funny in arena (DONE) |
343 | Lock axis (DONE 20130401) | ||
344 | Terrain detail: double terrain mesh detail (DONE) | ||
345 | Use the HACD convex hull routine in Bullet rather than the C# version. | ||
346 | Speed up hullifying large meshes. (DONE) | ||
347 | Vehicle ride, get up, ride again. Second time vehicle does not act correctly. | ||
348 | Have to rez new vehicle and delete the old to fix situation. | ||
349 | (DONE 20130520: normalize rotations) | ||
350 | Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd | ||
351 | position state where it will not settle onto ground properly, etc | ||
352 | (DONE 20130520: normalize rotations) | ||
353 | Two of Nebadon vehicles in a sim max the CPU. This is new. | ||
354 | (DONE 20130520: two problems: if asset failed to mesh, constantly refetched | ||
355 | asset; vehicle was sending too many messages to all linkset members) | ||
356 | Add material densities to the material types. (WILL NOT BE DONE: not how it is done) | ||
357 | Avatars walking up stairs (DONE) | ||
358 | Avatar movement | ||
359 | flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) | ||
360 | walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE) | ||
361 | avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) | ||
362 | After getting off a vehicle, the root prim is phantom (can be walked through) | ||
363 | Need to force a position update for the root prim after compound shape destruction | ||
364 | (DONE) | ||
365 | Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. | ||
366 | Regular triangle meshes don't do physical collisions. | ||
367 | (DONE: discovered GImpact is VERY CPU intensive) | ||
368 | |||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs index 33232bd..b040e21 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs | |||
@@ -114,9 +114,9 @@ public class BasicVehicles : OpenSimTestCase | |||
114 | // Instead the appropriate values are set and calls are made just the parts of the | 114 | // Instead the appropriate values are set and calls are made just the parts of the |
115 | // controller we want to exercise. Stepping the physics engine then applies | 115 | // controller we want to exercise. Stepping the physics engine then applies |
116 | // the actions of that one feature. | 116 | // the actions of that one feature. |
117 | TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); | 117 | TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); |
118 | TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); | 118 | TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); |
119 | TestVehicle.VehicleController.enableAngularVerticalAttraction = true; | 119 | TestVehicle.VehicleActor.enableAngularVerticalAttraction = true; |
120 | 120 | ||
121 | TestVehicle.IsPhysical = true; | 121 | TestVehicle.IsPhysical = true; |
122 | PhysicsScene.ProcessTaints(); | 122 | PhysicsScene.ProcessTaints(); |
@@ -124,9 +124,9 @@ public class BasicVehicles : OpenSimTestCase | |||
124 | // Step the simulator a bunch of times and vertical attraction should orient the vehicle up | 124 | // Step the simulator a bunch of times and vertical attraction should orient the vehicle up |
125 | for (int ii = 0; ii < simSteps; ii++) | 125 | for (int ii = 0; ii < simSteps; ii++) |
126 | { | 126 | { |
127 | TestVehicle.VehicleController.ForgetKnownVehicleProperties(); | 127 | TestVehicle.VehicleActor.ForgetKnownVehicleProperties(); |
128 | TestVehicle.VehicleController.ComputeAngularVerticalAttraction(); | 128 | TestVehicle.VehicleActor.ComputeAngularVerticalAttraction(); |
129 | TestVehicle.VehicleController.PushKnownChanged(); | 129 | TestVehicle.VehicleActor.PushKnownChanged(); |
130 | 130 | ||
131 | PhysicsScene.Simulate(simulationTimeStep); | 131 | PhysicsScene.Simulate(simulationTimeStep); |
132 | } | 132 | } |
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index d181b78..16d65eb 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -64,6 +64,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
64 | public class Meshmerizer : IMesher | 64 | public class Meshmerizer : IMesher |
65 | { | 65 | { |
66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
67 | private static string LogHeader = "[MESH]"; | ||
67 | 68 | ||
68 | // Setting baseDir to a path will enable the dumping of raw files | 69 | // Setting baseDir to a path will enable the dumping of raw files |
69 | // raw files can be imported by blender so a visual inspection of the results can be done | 70 | // raw files can be imported by blender so a visual inspection of the results can be done |
@@ -72,6 +73,8 @@ namespace OpenSim.Region.Physics.Meshing | |||
72 | #else | 73 | #else |
73 | private const string baseDir = null; //"rawFiles"; | 74 | private const string baseDir = null; //"rawFiles"; |
74 | #endif | 75 | #endif |
76 | // If 'true', lots of DEBUG logging of asset parsing details | ||
77 | private bool debugDetail = false; | ||
75 | 78 | ||
76 | private bool cacheSculptMaps = true; | 79 | private bool cacheSculptMaps = true; |
77 | private string decodedSculptMapPath = null; | 80 | private string decodedSculptMapPath = null; |
@@ -79,6 +82,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
79 | 82 | ||
80 | private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh | 83 | private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh |
81 | 84 | ||
85 | private List<List<Vector3>> mConvexHulls = null; | ||
86 | private List<Vector3> mBoundingHull = null; | ||
87 | |||
82 | private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); | 88 | private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); |
83 | 89 | ||
84 | public Meshmerizer(IConfigSource config) | 90 | public Meshmerizer(IConfigSource config) |
@@ -88,8 +94,11 @@ namespace OpenSim.Region.Physics.Meshing | |||
88 | 94 | ||
89 | decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); | 95 | decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); |
90 | cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); | 96 | cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); |
91 | if(mesh_config != null) | 97 | if (mesh_config != null) |
98 | { | ||
92 | useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); | 99 | useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); |
100 | debugDetail = mesh_config.GetBoolean("LogMeshDetails", debugDetail); | ||
101 | } | ||
93 | 102 | ||
94 | try | 103 | try |
95 | { | 104 | { |
@@ -319,6 +328,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
319 | faces = new List<Face>(); | 328 | faces = new List<Face>(); |
320 | OSD meshOsd = null; | 329 | OSD meshOsd = null; |
321 | 330 | ||
331 | mConvexHulls = null; | ||
332 | mBoundingHull = null; | ||
333 | |||
322 | if (primShape.SculptData.Length <= 0) | 334 | if (primShape.SculptData.Length <= 0) |
323 | { | 335 | { |
324 | // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this | 336 | // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this |
@@ -355,9 +367,139 @@ namespace OpenSim.Region.Physics.Meshing | |||
355 | OSDMap physicsParms = null; | 367 | OSDMap physicsParms = null; |
356 | OSDMap map = (OSDMap)meshOsd; | 368 | OSDMap map = (OSDMap)meshOsd; |
357 | if (map.ContainsKey("physics_shape")) | 369 | if (map.ContainsKey("physics_shape")) |
370 | { | ||
358 | physicsParms = (OSDMap)map["physics_shape"]; // old asset format | 371 | physicsParms = (OSDMap)map["physics_shape"]; // old asset format |
372 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}': using 'physics_shape' mesh data", LogHeader, primName); | ||
373 | } | ||
359 | else if (map.ContainsKey("physics_mesh")) | 374 | else if (map.ContainsKey("physics_mesh")) |
375 | { | ||
360 | physicsParms = (OSDMap)map["physics_mesh"]; // new asset format | 376 | physicsParms = (OSDMap)map["physics_mesh"]; // new asset format |
377 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'physics_mesh' mesh data", LogHeader, primName); | ||
378 | } | ||
379 | else if (map.ContainsKey("medium_lod")) | ||
380 | { | ||
381 | physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh | ||
382 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'medium_lod' mesh data", LogHeader, primName); | ||
383 | } | ||
384 | else if (map.ContainsKey("high_lod")) | ||
385 | { | ||
386 | physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :) | ||
387 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'high_lod' mesh data", LogHeader, primName); | ||
388 | } | ||
389 | |||
390 | if (map.ContainsKey("physics_convex")) | ||
391 | { // pull this out also in case physics engine can use it | ||
392 | OSD convexBlockOsd = null; | ||
393 | try | ||
394 | { | ||
395 | OSDMap convexBlock = (OSDMap)map["physics_convex"]; | ||
396 | { | ||
397 | int convexOffset = convexBlock["offset"].AsInteger() + (int)start; | ||
398 | int convexSize = convexBlock["size"].AsInteger(); | ||
399 | |||
400 | byte[] convexBytes = new byte[convexSize]; | ||
401 | |||
402 | System.Buffer.BlockCopy(primShape.SculptData, convexOffset, convexBytes, 0, convexSize); | ||
403 | |||
404 | try | ||
405 | { | ||
406 | convexBlockOsd = DecompressOsd(convexBytes); | ||
407 | } | ||
408 | catch (Exception e) | ||
409 | { | ||
410 | m_log.ErrorFormat("{0} prim='{1}': exception decoding convex block: {2}", LogHeader, primName, e); | ||
411 | //return false; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | if (convexBlockOsd != null && convexBlockOsd is OSDMap) | ||
416 | { | ||
417 | convexBlock = convexBlockOsd as OSDMap; | ||
418 | |||
419 | if (debugDetail) | ||
420 | { | ||
421 | string keys = LogHeader + " keys found in convexBlock: "; | ||
422 | foreach (KeyValuePair<string, OSD> kvp in convexBlock) | ||
423 | keys += "'" + kvp.Key + "' "; | ||
424 | m_log.Debug(keys); | ||
425 | } | ||
426 | |||
427 | Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f); | ||
428 | if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3(); | ||
429 | Vector3 max = new Vector3(0.5f, 0.5f, 0.5f); | ||
430 | if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3(); | ||
431 | |||
432 | List<Vector3> boundingHull = null; | ||
433 | |||
434 | if (convexBlock.ContainsKey("BoundingVerts")) | ||
435 | { | ||
436 | byte[] boundingVertsBytes = convexBlock["BoundingVerts"].AsBinary(); | ||
437 | boundingHull = new List<Vector3>(); | ||
438 | for (int i = 0; i < boundingVertsBytes.Length; ) | ||
439 | { | ||
440 | ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; | ||
441 | ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; | ||
442 | ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; | ||
443 | |||
444 | Vector3 pos = new Vector3( | ||
445 | Utils.UInt16ToFloat(uX, min.X, max.X), | ||
446 | Utils.UInt16ToFloat(uY, min.Y, max.Y), | ||
447 | Utils.UInt16ToFloat(uZ, min.Z, max.Z) | ||
448 | ); | ||
449 | |||
450 | boundingHull.Add(pos); | ||
451 | } | ||
452 | |||
453 | mBoundingHull = boundingHull; | ||
454 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nVerts={2}", LogHeader, primName, mBoundingHull.Count); | ||
455 | } | ||
456 | |||
457 | if (convexBlock.ContainsKey("HullList")) | ||
458 | { | ||
459 | byte[] hullList = convexBlock["HullList"].AsBinary(); | ||
460 | |||
461 | byte[] posBytes = convexBlock["Positions"].AsBinary(); | ||
462 | |||
463 | List<List<Vector3>> hulls = new List<List<Vector3>>(); | ||
464 | int posNdx = 0; | ||
465 | |||
466 | foreach (byte cnt in hullList) | ||
467 | { | ||
468 | int count = cnt == 0 ? 256 : cnt; | ||
469 | List<Vector3> hull = new List<Vector3>(); | ||
470 | |||
471 | for (int i = 0; i < count; i++) | ||
472 | { | ||
473 | ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; | ||
474 | ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; | ||
475 | ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; | ||
476 | |||
477 | Vector3 pos = new Vector3( | ||
478 | Utils.UInt16ToFloat(uX, min.X, max.X), | ||
479 | Utils.UInt16ToFloat(uY, min.Y, max.Y), | ||
480 | Utils.UInt16ToFloat(uZ, min.Z, max.Z) | ||
481 | ); | ||
482 | |||
483 | hull.Add(pos); | ||
484 | } | ||
485 | |||
486 | hulls.Add(hull); | ||
487 | } | ||
488 | |||
489 | mConvexHulls = hulls; | ||
490 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count); | ||
491 | } | ||
492 | else | ||
493 | { | ||
494 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName); | ||
495 | } | ||
496 | } | ||
497 | } | ||
498 | catch (Exception e) | ||
499 | { | ||
500 | m_log.WarnFormat("{0} exception decoding convex block: {1}", LogHeader, e); | ||
501 | } | ||
502 | } | ||
361 | 503 | ||
362 | if (physicsParms == null) | 504 | if (physicsParms == null) |
363 | { | 505 | { |
@@ -374,34 +516,14 @@ namespace OpenSim.Region.Physics.Meshing | |||
374 | OSD decodedMeshOsd = new OSD(); | 516 | OSD decodedMeshOsd = new OSD(); |
375 | byte[] meshBytes = new byte[physSize]; | 517 | byte[] meshBytes = new byte[physSize]; |
376 | System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); | 518 | System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); |
377 | // byte[] decompressed = new byte[physSize * 5]; | 519 | // byte[] decompressed = new byte[physSize * 5]; |
378 | try | 520 | try |
379 | { | 521 | { |
380 | using (MemoryStream inMs = new MemoryStream(meshBytes)) | 522 | decodedMeshOsd = DecompressOsd(meshBytes); |
381 | { | ||
382 | using (MemoryStream outMs = new MemoryStream()) | ||
383 | { | ||
384 | using (ZOutputStream zOut = new ZOutputStream(outMs)) | ||
385 | { | ||
386 | byte[] readBuffer = new byte[2048]; | ||
387 | int readLen = 0; | ||
388 | while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) | ||
389 | { | ||
390 | zOut.Write(readBuffer, 0, readLen); | ||
391 | } | ||
392 | zOut.Flush(); | ||
393 | outMs.Seek(0, SeekOrigin.Begin); | ||
394 | |||
395 | byte[] decompressedBuf = outMs.GetBuffer(); | ||
396 | |||
397 | decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | } | 523 | } |
402 | catch (Exception e) | 524 | catch (Exception e) |
403 | { | 525 | { |
404 | m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); | 526 | m_log.ErrorFormat("{0} prim='{1}': exception decoding physical mesh: {2}", LogHeader, primName, e); |
405 | return false; | 527 | return false; |
406 | } | 528 | } |
407 | 529 | ||
@@ -410,7 +532,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
410 | // physics_shape is an array of OSDMaps, one for each submesh | 532 | // physics_shape is an array of OSDMaps, one for each submesh |
411 | if (decodedMeshOsd is OSDArray) | 533 | if (decodedMeshOsd is OSDArray) |
412 | { | 534 | { |
413 | // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); | 535 | // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); |
414 | 536 | ||
415 | decodedMeshOsdArray = (OSDArray)decodedMeshOsd; | 537 | decodedMeshOsdArray = (OSDArray)decodedMeshOsd; |
416 | foreach (OSD subMeshOsd in decodedMeshOsdArray) | 538 | foreach (OSD subMeshOsd in decodedMeshOsdArray) |
@@ -418,12 +540,50 @@ namespace OpenSim.Region.Physics.Meshing | |||
418 | if (subMeshOsd is OSDMap) | 540 | if (subMeshOsd is OSDMap) |
419 | AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); | 541 | AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); |
420 | } | 542 | } |
543 | if (debugDetail) | ||
544 | m_log.DebugFormat("{0} {1}: mesh decoded. offset={2}, size={3}, nCoords={4}, nFaces={5}", | ||
545 | LogHeader, primName, physOffset, physSize, coords.Count, faces.Count); | ||
421 | } | 546 | } |
422 | } | 547 | } |
423 | 548 | ||
424 | return true; | 549 | return true; |
425 | } | 550 | } |
426 | 551 | ||
552 | |||
553 | /// <summary> | ||
554 | /// decompresses a gzipped OSD object | ||
555 | /// </summary> | ||
556 | /// <param name="decodedOsd"></param> the OSD object | ||
557 | /// <param name="meshBytes"></param> | ||
558 | /// <returns></returns> | ||
559 | private static OSD DecompressOsd(byte[] meshBytes) | ||
560 | { | ||
561 | OSD decodedOsd = null; | ||
562 | |||
563 | using (MemoryStream inMs = new MemoryStream(meshBytes)) | ||
564 | { | ||
565 | using (MemoryStream outMs = new MemoryStream()) | ||
566 | { | ||
567 | using (ZOutputStream zOut = new ZOutputStream(outMs)) | ||
568 | { | ||
569 | byte[] readBuffer = new byte[2048]; | ||
570 | int readLen = 0; | ||
571 | while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) | ||
572 | { | ||
573 | zOut.Write(readBuffer, 0, readLen); | ||
574 | } | ||
575 | zOut.Flush(); | ||
576 | outMs.Seek(0, SeekOrigin.Begin); | ||
577 | |||
578 | byte[] decompressedBuf = outMs.GetBuffer(); | ||
579 | |||
580 | decodedOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf); | ||
581 | } | ||
582 | } | ||
583 | } | ||
584 | return decodedOsd; | ||
585 | } | ||
586 | |||
427 | /// <summary> | 587 | /// <summary> |
428 | /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim. | 588 | /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim. |
429 | /// </summary> | 589 | /// </summary> |
@@ -700,6 +860,45 @@ namespace OpenSim.Region.Physics.Meshing | |||
700 | return true; | 860 | return true; |
701 | } | 861 | } |
702 | 862 | ||
863 | /// <summary> | ||
864 | /// temporary prototype code - please do not use until the interface has been finalized! | ||
865 | /// </summary> | ||
866 | /// <param name="size">value to scale the hull points by</param> | ||
867 | /// <returns>a list of vertices in the bounding hull if it exists and has been successfully decoded, otherwise null</returns> | ||
868 | public List<Vector3> GetBoundingHull(Vector3 size) | ||
869 | { | ||
870 | if (mBoundingHull == null) | ||
871 | return null; | ||
872 | |||
873 | List<Vector3> verts = new List<Vector3>(); | ||
874 | foreach (var vert in mBoundingHull) | ||
875 | verts.Add(vert * size); | ||
876 | |||
877 | return verts; | ||
878 | } | ||
879 | |||
880 | /// <summary> | ||
881 | /// temporary prototype code - please do not use until the interface has been finalized! | ||
882 | /// </summary> | ||
883 | /// <param name="size">value to scale the hull points by</param> | ||
884 | /// <returns>a list of hulls if they exist and have been successfully decoded, otherwise null</returns> | ||
885 | public List<List<Vector3>> GetConvexHulls(Vector3 size) | ||
886 | { | ||
887 | if (mConvexHulls == null) | ||
888 | return null; | ||
889 | |||
890 | List<List<Vector3>> hulls = new List<List<Vector3>>(); | ||
891 | foreach (var hull in mConvexHulls) | ||
892 | { | ||
893 | List<Vector3> verts = new List<Vector3>(); | ||
894 | foreach (var vert in hull) | ||
895 | verts.Add(vert * size); | ||
896 | hulls.Add(verts); | ||
897 | } | ||
898 | |||
899 | return hulls; | ||
900 | } | ||
901 | |||
703 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 902 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
704 | { | 903 | { |
705 | return CreateMesh(primName, primShape, size, lod, false, true); | 904 | return CreateMesh(primName, primShape, size, lod, false, true); |
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs index b4abc1d..4bf2a82 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerLargeLandChannel.cs | |||
@@ -27,6 +27,8 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | ||
31 | using log4net; | ||
30 | using OpenMetaverse; | 32 | using OpenMetaverse; |
31 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
32 | using OpenSim.Region.Framework.Interfaces; | 34 | using OpenSim.Region.Framework.Interfaces; |
@@ -34,10 +36,10 @@ using OpenSim.Region.CoreModules.World.Land; | |||
34 | 36 | ||
35 | namespace OpenSim.Region.RegionCombinerModule | 37 | namespace OpenSim.Region.RegionCombinerModule |
36 | { | 38 | { |
37 | public class RegionCombinerLargeLandChannel : ILandChannel | 39 | public class RegionCombinerLargeLandChannel : ILandChannel |
38 | { | 40 | { |
39 | // private static readonly ILog m_log = | 41 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
40 | // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 42 | |
41 | private RegionData RegData; | 43 | private RegionData RegData; |
42 | private ILandChannel RootRegionLandChannel; | 44 | private ILandChannel RootRegionLandChannel; |
43 | private readonly List<RegionData> RegionConnections; | 45 | private readonly List<RegionData> RegionConnections; |
@@ -75,40 +77,51 @@ public class RegionCombinerLargeLandChannel : ILandChannel | |||
75 | 77 | ||
76 | public ILandObject GetLandObject(int x, int y) | 78 | public ILandObject GetLandObject(int x, int y) |
77 | { | 79 | { |
78 | //m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); | 80 | return GetLandObject((float)x, (float)y); |
79 | 81 | ||
80 | if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) | 82 | // m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y); |
81 | { | 83 | // |
82 | return RootRegionLandChannel.GetLandObject(x, y); | 84 | // if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) |
83 | } | 85 | // { |
84 | else | 86 | // return RootRegionLandChannel.GetLandObject(x, y); |
85 | { | 87 | // } |
86 | int offsetX = (x / (int)Constants.RegionSize); | 88 | // else |
87 | int offsetY = (y / (int)Constants.RegionSize); | 89 | // { |
88 | offsetX *= (int)Constants.RegionSize; | 90 | // int offsetX = (x / (int)Constants.RegionSize); |
89 | offsetY *= (int)Constants.RegionSize; | 91 | // int offsetY = (y / (int)Constants.RegionSize); |
90 | 92 | // offsetX *= (int)Constants.RegionSize; | |
91 | foreach (RegionData regionData in RegionConnections) | 93 | // offsetY *= (int)Constants.RegionSize; |
92 | { | 94 | // |
93 | if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) | 95 | // foreach (RegionData regionData in RegionConnections) |
94 | { | 96 | // { |
95 | return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); | 97 | // if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) |
96 | } | 98 | // { |
97 | } | 99 | // m_log.DebugFormat( |
98 | ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); | 100 | // "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}", |
99 | obj.LandData.Name = "NO LAND"; | 101 | // regionData.RegionScene.Name, offsetX, offsetY); |
100 | return obj; | 102 | // |
101 | } | 103 | // return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); |
104 | // } | ||
105 | // } | ||
106 | // //ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); | ||
107 | // //obj.LandData.Name = "NO LAND"; | ||
108 | // //return obj; | ||
109 | // } | ||
110 | // | ||
111 | // m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y); | ||
112 | // | ||
113 | // return null; | ||
102 | } | 114 | } |
103 | 115 | ||
104 | public ILandObject GetLandObject(int localID) | 116 | public ILandObject GetLandObject(int localID) |
105 | { | 117 | { |
118 | // XXX: Possibly should be looking in every land channel, not just the root. | ||
106 | return RootRegionLandChannel.GetLandObject(localID); | 119 | return RootRegionLandChannel.GetLandObject(localID); |
107 | } | 120 | } |
108 | 121 | ||
109 | public ILandObject GetLandObject(float x, float y) | 122 | public ILandObject GetLandObject(float x, float y) |
110 | { | 123 | { |
111 | //m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y); | 124 | // m_log.DebugFormat("[BIGLANDTESTFLOAT]: <{0},{1}>", x, y); |
112 | 125 | ||
113 | if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) | 126 | if (x > 0 && x <= (int)Constants.RegionSize && y > 0 && y <= (int)Constants.RegionSize) |
114 | { | 127 | { |
@@ -125,14 +138,22 @@ public class RegionCombinerLargeLandChannel : ILandChannel | |||
125 | { | 138 | { |
126 | if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) | 139 | if (regionData.Offset.X == offsetX && regionData.Offset.Y == offsetY) |
127 | { | 140 | { |
141 | // m_log.DebugFormat( | ||
142 | // "[REGION COMBINER LARGE LAND CHANNEL]: Found region {0} at offset {1},{2}", | ||
143 | // regionData.RegionScene.Name, offsetX, offsetY); | ||
144 | |||
128 | return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); | 145 | return regionData.RegionScene.LandChannel.GetLandObject(x - offsetX, y - offsetY); |
129 | } | 146 | } |
130 | } | 147 | } |
131 | 148 | ||
132 | ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); | 149 | // ILandObject obj = new LandObject(UUID.Zero, false, RegData.RegionScene); |
133 | obj.LandData.Name = "NO LAND"; | 150 | // obj.LandData.Name = "NO LAND"; |
134 | return obj; | 151 | // return obj; |
135 | } | 152 | } |
153 | |||
154 | // m_log.DebugFormat("[REGION COMBINER LARGE LAND CHANNEL]: No region found at {0},{1}, returning null", x, y); | ||
155 | |||
156 | return null; | ||
136 | } | 157 | } |
137 | 158 | ||
138 | public bool IsForcefulBansAllowed() | 159 | public bool IsForcefulBansAllowed() |
diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index 35ae44c..b9a217b 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs | |||
@@ -51,7 +51,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces | |||
51 | public interface IScriptWorkItem | 51 | public interface IScriptWorkItem |
52 | { | 52 | { |
53 | bool Cancel(); | 53 | bool Cancel(); |
54 | void Abort(); | 54 | bool Abort(); |
55 | 55 | ||
56 | /// <summary> | 56 | /// <summary> |
57 | /// Wait for the work item to complete. | 57 | /// Wait for the work item to complete. |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs index 6879ebb..1e19032 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs | |||
@@ -37,6 +37,8 @@ using OpenSim.Region.ScriptEngine.Interfaces; | |||
37 | using OpenSim.Region.ScriptEngine.Shared; | 37 | using OpenSim.Region.ScriptEngine.Shared; |
38 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; | 38 | using OpenSim.Region.ScriptEngine.Shared.Api.Plugins; |
39 | using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; | 39 | using Timer=OpenSim.Region.ScriptEngine.Shared.Api.Plugins.Timer; |
40 | using System.Reflection; | ||
41 | using log4net; | ||
40 | 42 | ||
41 | namespace OpenSim.Region.ScriptEngine.Shared.Api | 43 | namespace OpenSim.Region.ScriptEngine.Shared.Api |
42 | { | 44 | { |
@@ -45,15 +47,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
45 | /// </summary> | 47 | /// </summary> |
46 | public class AsyncCommandManager | 48 | public class AsyncCommandManager |
47 | { | 49 | { |
50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | |||
48 | private static Thread cmdHandlerThread; | 52 | private static Thread cmdHandlerThread; |
49 | private static int cmdHandlerThreadCycleSleepms; | 53 | private static int cmdHandlerThreadCycleSleepms; |
50 | 54 | ||
51 | private static List<IScene> m_Scenes = new List<IScene>(); | 55 | /// <summary> |
56 | /// Lock for reading/writing static components of AsyncCommandManager. | ||
57 | /// </summary> | ||
58 | /// <remarks> | ||
59 | /// This lock exists so that multiple threads from different engines and/or different copies of the same engine | ||
60 | /// are prevented from running non-thread safe code (e.g. read/write of lists) concurrently. | ||
61 | /// </remarks> | ||
62 | private static object staticLock = new object(); | ||
63 | |||
52 | private static List<IScriptEngine> m_ScriptEngines = | 64 | private static List<IScriptEngine> m_ScriptEngines = |
53 | new List<IScriptEngine>(); | 65 | new List<IScriptEngine>(); |
54 | 66 | ||
55 | public IScriptEngine m_ScriptEngine; | 67 | public IScriptEngine m_ScriptEngine; |
56 | private IScene m_Scene; | ||
57 | 68 | ||
58 | private static Dictionary<IScriptEngine, Dataserver> m_Dataserver = | 69 | private static Dictionary<IScriptEngine, Dataserver> m_Dataserver = |
59 | new Dictionary<IScriptEngine, Dataserver>(); | 70 | new Dictionary<IScriptEngine, Dataserver>(); |
@@ -70,67 +81,99 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
70 | 81 | ||
71 | public Dataserver DataserverPlugin | 82 | public Dataserver DataserverPlugin |
72 | { | 83 | { |
73 | get { return m_Dataserver[m_ScriptEngine]; } | 84 | get |
85 | { | ||
86 | lock (staticLock) | ||
87 | return m_Dataserver[m_ScriptEngine]; | ||
88 | } | ||
74 | } | 89 | } |
75 | 90 | ||
76 | public Timer TimerPlugin | 91 | public Timer TimerPlugin |
77 | { | 92 | { |
78 | get { return m_Timer[m_ScriptEngine]; } | 93 | get |
94 | { | ||
95 | lock (staticLock) | ||
96 | return m_Timer[m_ScriptEngine]; | ||
97 | } | ||
79 | } | 98 | } |
80 | 99 | ||
81 | public HttpRequest HttpRequestPlugin | 100 | public HttpRequest HttpRequestPlugin |
82 | { | 101 | { |
83 | get { return m_HttpRequest[m_ScriptEngine]; } | 102 | get |
103 | { | ||
104 | lock (staticLock) | ||
105 | return m_HttpRequest[m_ScriptEngine]; | ||
106 | } | ||
84 | } | 107 | } |
85 | 108 | ||
86 | public Listener ListenerPlugin | 109 | public Listener ListenerPlugin |
87 | { | 110 | { |
88 | get { return m_Listener[m_ScriptEngine]; } | 111 | get |
112 | { | ||
113 | lock (staticLock) | ||
114 | return m_Listener[m_ScriptEngine]; | ||
115 | } | ||
89 | } | 116 | } |
90 | 117 | ||
91 | public SensorRepeat SensorRepeatPlugin | 118 | public SensorRepeat SensorRepeatPlugin |
92 | { | 119 | { |
93 | get { return m_SensorRepeat[m_ScriptEngine]; } | 120 | get |
121 | { | ||
122 | lock (staticLock) | ||
123 | return m_SensorRepeat[m_ScriptEngine]; | ||
124 | } | ||
94 | } | 125 | } |
95 | 126 | ||
96 | public XmlRequest XmlRequestPlugin | 127 | public XmlRequest XmlRequestPlugin |
97 | { | 128 | { |
98 | get { return m_XmlRequest[m_ScriptEngine]; } | 129 | get |
130 | { | ||
131 | lock (staticLock) | ||
132 | return m_XmlRequest[m_ScriptEngine]; | ||
133 | } | ||
99 | } | 134 | } |
100 | 135 | ||
101 | public IScriptEngine[] ScriptEngines | 136 | public IScriptEngine[] ScriptEngines |
102 | { | 137 | { |
103 | get { return m_ScriptEngines.ToArray(); } | 138 | get |
139 | { | ||
140 | lock (staticLock) | ||
141 | return m_ScriptEngines.ToArray(); | ||
142 | } | ||
104 | } | 143 | } |
105 | 144 | ||
106 | public AsyncCommandManager(IScriptEngine _ScriptEngine) | 145 | public AsyncCommandManager(IScriptEngine _ScriptEngine) |
107 | { | 146 | { |
108 | m_ScriptEngine = _ScriptEngine; | 147 | m_ScriptEngine = _ScriptEngine; |
109 | m_Scene = m_ScriptEngine.World; | 148 | |
110 | 149 | // If there is more than one scene in the simulator or multiple script engines are used on the same region | |
111 | if (m_Scenes.Count == 0) | 150 | // then more than one thread could arrive at this block of code simultaneously. However, it cannot be |
112 | ReadConfig(); | 151 | // executed concurrently both because concurrent list operations are not thread-safe and because of other |
113 | 152 | // race conditions such as the later check of cmdHandlerThread == null. | |
114 | if (!m_Scenes.Contains(m_Scene)) | 153 | lock (staticLock) |
115 | m_Scenes.Add(m_Scene); | 154 | { |
116 | if (!m_ScriptEngines.Contains(m_ScriptEngine)) | 155 | if (m_ScriptEngines.Count == 0) |
117 | m_ScriptEngines.Add(m_ScriptEngine); | 156 | ReadConfig(); |
118 | 157 | ||
119 | // Create instances of all plugins | 158 | if (!m_ScriptEngines.Contains(m_ScriptEngine)) |
120 | if (!m_Dataserver.ContainsKey(m_ScriptEngine)) | 159 | m_ScriptEngines.Add(m_ScriptEngine); |
121 | m_Dataserver[m_ScriptEngine] = new Dataserver(this); | 160 | |
122 | if (!m_Timer.ContainsKey(m_ScriptEngine)) | 161 | // Create instances of all plugins |
123 | m_Timer[m_ScriptEngine] = new Timer(this); | 162 | if (!m_Dataserver.ContainsKey(m_ScriptEngine)) |
124 | if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) | 163 | m_Dataserver[m_ScriptEngine] = new Dataserver(this); |
125 | m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); | 164 | if (!m_Timer.ContainsKey(m_ScriptEngine)) |
126 | if (!m_Listener.ContainsKey(m_ScriptEngine)) | 165 | m_Timer[m_ScriptEngine] = new Timer(this); |
127 | m_Listener[m_ScriptEngine] = new Listener(this); | 166 | if (!m_HttpRequest.ContainsKey(m_ScriptEngine)) |
128 | if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) | 167 | m_HttpRequest[m_ScriptEngine] = new HttpRequest(this); |
129 | m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); | 168 | if (!m_Listener.ContainsKey(m_ScriptEngine)) |
130 | if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) | 169 | m_Listener[m_ScriptEngine] = new Listener(this); |
131 | m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); | 170 | if (!m_SensorRepeat.ContainsKey(m_ScriptEngine)) |
132 | 171 | m_SensorRepeat[m_ScriptEngine] = new SensorRepeat(this); | |
133 | StartThread(); | 172 | if (!m_XmlRequest.ContainsKey(m_ScriptEngine)) |
173 | m_XmlRequest[m_ScriptEngine] = new XmlRequest(this); | ||
174 | |||
175 | StartThread(); | ||
176 | } | ||
134 | } | 177 | } |
135 | 178 | ||
136 | private static void StartThread() | 179 | private static void StartThread() |
@@ -179,42 +222,43 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
179 | { | 222 | { |
180 | try | 223 | try |
181 | { | 224 | { |
182 | while (true) | 225 | Thread.Sleep(cmdHandlerThreadCycleSleepms); |
183 | { | ||
184 | Thread.Sleep(cmdHandlerThreadCycleSleepms); | ||
185 | 226 | ||
186 | DoOneCmdHandlerPass(); | 227 | DoOneCmdHandlerPass(); |
187 | 228 | ||
188 | Watchdog.UpdateThread(); | 229 | Watchdog.UpdateThread(); |
189 | } | ||
190 | } | 230 | } |
191 | catch | 231 | catch (Exception e) |
192 | { | 232 | { |
233 | m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e); | ||
193 | } | 234 | } |
194 | } | 235 | } |
195 | } | 236 | } |
196 | 237 | ||
197 | private static void DoOneCmdHandlerPass() | 238 | private static void DoOneCmdHandlerPass() |
198 | { | 239 | { |
199 | // Check HttpRequests | 240 | lock (staticLock) |
200 | m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); | 241 | { |
242 | // Check HttpRequests | ||
243 | m_HttpRequest[m_ScriptEngines[0]].CheckHttpRequests(); | ||
201 | 244 | ||
202 | // Check XMLRPCRequests | 245 | // Check XMLRPCRequests |
203 | m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); | 246 | m_XmlRequest[m_ScriptEngines[0]].CheckXMLRPCRequests(); |
204 | 247 | ||
205 | foreach (IScriptEngine s in m_ScriptEngines) | 248 | foreach (IScriptEngine s in m_ScriptEngines) |
206 | { | 249 | { |
207 | // Check Listeners | 250 | // Check Listeners |
208 | m_Listener[s].CheckListeners(); | 251 | m_Listener[s].CheckListeners(); |
209 | 252 | ||
210 | // Check timers | 253 | // Check timers |
211 | m_Timer[s].CheckTimerEvents(); | 254 | m_Timer[s].CheckTimerEvents(); |
212 | 255 | ||
213 | // Check Sensors | 256 | // Check Sensors |
214 | m_SensorRepeat[s].CheckSenseRepeaterEvents(); | 257 | m_SensorRepeat[s].CheckSenseRepeaterEvents(); |
215 | 258 | ||
216 | // Check dataserver | 259 | // Check dataserver |
217 | m_Dataserver[s].ExpireRequests(); | 260 | m_Dataserver[s].ExpireRequests(); |
261 | } | ||
218 | } | 262 | } |
219 | } | 263 | } |
220 | 264 | ||
@@ -226,31 +270,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
226 | public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID) | 270 | public static void RemoveScript(IScriptEngine engine, uint localID, UUID itemID) |
227 | { | 271 | { |
228 | // Remove a specific script | 272 | // Remove a specific script |
273 | // m_log.DebugFormat("[ASYNC COMMAND MANAGER]: Removing facilities for script {0}", itemID); | ||
229 | 274 | ||
230 | // Remove dataserver events | 275 | lock (staticLock) |
231 | m_Dataserver[engine].RemoveEvents(localID, itemID); | 276 | { |
277 | // Remove dataserver events | ||
278 | m_Dataserver[engine].RemoveEvents(localID, itemID); | ||
232 | 279 | ||
233 | // Remove from: Timers | 280 | // Remove from: Timers |
234 | m_Timer[engine].UnSetTimerEvents(localID, itemID); | 281 | m_Timer[engine].UnSetTimerEvents(localID, itemID); |
235 | 282 | ||
236 | // Remove from: HttpRequest | 283 | // Remove from: HttpRequest |
237 | IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>(); | 284 | IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface<IHttpRequestModule>(); |
238 | if (iHttpReq != null) | 285 | if (iHttpReq != null) |
239 | iHttpReq.StopHttpRequest(localID, itemID); | 286 | iHttpReq.StopHttpRequest(localID, itemID); |
240 | 287 | ||
241 | IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>(); | 288 | IWorldComm comms = engine.World.RequestModuleInterface<IWorldComm>(); |
242 | if (comms != null) | 289 | if (comms != null) |
243 | comms.DeleteListener(itemID); | 290 | comms.DeleteListener(itemID); |
244 | 291 | ||
245 | IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>(); | 292 | IXMLRPC xmlrpc = engine.World.RequestModuleInterface<IXMLRPC>(); |
246 | if (xmlrpc != null) | 293 | if (xmlrpc != null) |
247 | { | 294 | { |
248 | xmlrpc.DeleteChannels(itemID); | 295 | xmlrpc.DeleteChannels(itemID); |
249 | xmlrpc.CancelSRDRequests(itemID); | 296 | xmlrpc.CancelSRDRequests(itemID); |
250 | } | 297 | } |
251 | 298 | ||
252 | // Remove Sensors | 299 | // Remove Sensors |
253 | m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); | 300 | m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); |
301 | } | ||
254 | } | 302 | } |
255 | 303 | ||
256 | /// <summary> | 304 | /// <summary> |
@@ -260,10 +308,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
260 | /// <returns></returns> | 308 | /// <returns></returns> |
261 | public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine) | 309 | public static SensorRepeat GetSensorRepeatPlugin(IScriptEngine engine) |
262 | { | 310 | { |
263 | if (m_SensorRepeat.ContainsKey(engine)) | 311 | lock (staticLock) |
264 | return m_SensorRepeat[engine]; | 312 | { |
265 | else | 313 | if (m_SensorRepeat.ContainsKey(engine)) |
266 | return null; | 314 | return m_SensorRepeat[engine]; |
315 | else | ||
316 | return null; | ||
317 | } | ||
267 | } | 318 | } |
268 | 319 | ||
269 | /// <summary> | 320 | /// <summary> |
@@ -273,10 +324,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
273 | /// <returns></returns> | 324 | /// <returns></returns> |
274 | public static Dataserver GetDataserverPlugin(IScriptEngine engine) | 325 | public static Dataserver GetDataserverPlugin(IScriptEngine engine) |
275 | { | 326 | { |
276 | if (m_Dataserver.ContainsKey(engine)) | 327 | lock (staticLock) |
277 | return m_Dataserver[engine]; | 328 | { |
278 | else | 329 | if (m_Dataserver.ContainsKey(engine)) |
279 | return null; | 330 | return m_Dataserver[engine]; |
331 | else | ||
332 | return null; | ||
333 | } | ||
280 | } | 334 | } |
281 | 335 | ||
282 | /// <summary> | 336 | /// <summary> |
@@ -286,10 +340,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
286 | /// <returns></returns> | 340 | /// <returns></returns> |
287 | public static Timer GetTimerPlugin(IScriptEngine engine) | 341 | public static Timer GetTimerPlugin(IScriptEngine engine) |
288 | { | 342 | { |
289 | if (m_Timer.ContainsKey(engine)) | 343 | lock (staticLock) |
290 | return m_Timer[engine]; | 344 | { |
291 | else | 345 | if (m_Timer.ContainsKey(engine)) |
292 | return null; | 346 | return m_Timer[engine]; |
347 | else | ||
348 | return null; | ||
349 | } | ||
293 | } | 350 | } |
294 | 351 | ||
295 | /// <summary> | 352 | /// <summary> |
@@ -299,10 +356,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
299 | /// <returns></returns> | 356 | /// <returns></returns> |
300 | public static Listener GetListenerPlugin(IScriptEngine engine) | 357 | public static Listener GetListenerPlugin(IScriptEngine engine) |
301 | { | 358 | { |
302 | if (m_Listener.ContainsKey(engine)) | 359 | lock (staticLock) |
303 | return m_Listener[engine]; | 360 | { |
304 | else | 361 | if (m_Listener.ContainsKey(engine)) |
305 | return null; | 362 | return m_Listener[engine]; |
363 | else | ||
364 | return null; | ||
365 | } | ||
306 | } | 366 | } |
307 | 367 | ||
308 | public static void StateChange(IScriptEngine engine, uint localID, UUID itemID) | 368 | public static void StateChange(IScriptEngine engine, uint localID, UUID itemID) |
@@ -332,28 +392,31 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
332 | { | 392 | { |
333 | List<Object> data = new List<Object>(); | 393 | List<Object> data = new List<Object>(); |
334 | 394 | ||
335 | Object[] listeners = m_Listener[engine].GetSerializationData(itemID); | 395 | lock (staticLock) |
336 | if (listeners.Length > 0) | ||
337 | { | 396 | { |
338 | data.Add("listener"); | 397 | Object[] listeners = m_Listener[engine].GetSerializationData(itemID); |
339 | data.Add(listeners.Length); | 398 | if (listeners.Length > 0) |
340 | data.AddRange(listeners); | 399 | { |
341 | } | 400 | data.Add("listener"); |
401 | data.Add(listeners.Length); | ||
402 | data.AddRange(listeners); | ||
403 | } | ||
342 | 404 | ||
343 | Object[] timers=m_Timer[engine].GetSerializationData(itemID); | 405 | Object[] timers=m_Timer[engine].GetSerializationData(itemID); |
344 | if (timers.Length > 0) | 406 | if (timers.Length > 0) |
345 | { | 407 | { |
346 | data.Add("timer"); | 408 | data.Add("timer"); |
347 | data.Add(timers.Length); | 409 | data.Add(timers.Length); |
348 | data.AddRange(timers); | 410 | data.AddRange(timers); |
349 | } | 411 | } |
350 | 412 | ||
351 | Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); | 413 | Object[] sensors = m_SensorRepeat[engine].GetSerializationData(itemID); |
352 | if (sensors.Length > 0) | 414 | if (sensors.Length > 0) |
353 | { | 415 | { |
354 | data.Add("sensor"); | 416 | data.Add("sensor"); |
355 | data.Add(sensors.Length); | 417 | data.Add(sensors.Length); |
356 | data.AddRange(sensors); | 418 | data.AddRange(sensors); |
419 | } | ||
357 | } | 420 | } |
358 | 421 | ||
359 | return data.ToArray(); | 422 | return data.ToArray(); |
@@ -378,41 +441,26 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
378 | 441 | ||
379 | idx+=len; | 442 | idx+=len; |
380 | 443 | ||
444 | lock (staticLock) | ||
445 | { | ||
381 | switch (type) | 446 | switch (type) |
382 | { | 447 | { |
383 | case "listener": | 448 | case "listener": |
384 | m_Listener[engine].CreateFromData(localID, itemID, | 449 | m_Listener[engine].CreateFromData(localID, itemID, |
385 | hostID, item); | 450 | hostID, item); |
386 | break; | 451 | break; |
387 | case "timer": | 452 | case "timer": |
388 | m_Timer[engine].CreateFromData(localID, itemID, | 453 | m_Timer[engine].CreateFromData(localID, itemID, |
389 | hostID, item); | 454 | hostID, item); |
390 | break; | 455 | break; |
391 | case "sensor": | 456 | case "sensor": |
392 | m_SensorRepeat[engine].CreateFromData(localID, | 457 | m_SensorRepeat[engine].CreateFromData(localID, |
393 | itemID, hostID, item); | 458 | itemID, hostID, item); |
394 | break; | 459 | break; |
460 | } | ||
395 | } | 461 | } |
396 | } | 462 | } |
397 | } | 463 | } |
398 | } | 464 | } |
399 | |||
400 | #region Check llRemoteData channels | ||
401 | |||
402 | #endregion | ||
403 | |||
404 | #region Check llListeners | ||
405 | |||
406 | #endregion | ||
407 | |||
408 | /// <summary> | ||
409 | /// If set to true then threads and stuff should try to make a graceful exit | ||
410 | /// </summary> | ||
411 | public bool PleaseShutdown | ||
412 | { | ||
413 | get { return _PleaseShutdown; } | ||
414 | set { _PleaseShutdown = value; } | ||
415 | } | ||
416 | private bool _PleaseShutdown = false; | ||
417 | } | 465 | } |
418 | } | 466 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index e8502ac..f05aaa9 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | |||
@@ -1664,6 +1664,75 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
1664 | m_host.SetFaceColorAlpha(face, color, null); | 1664 | m_host.SetFaceColorAlpha(face, color, null); |
1665 | } | 1665 | } |
1666 | 1666 | ||
1667 | /* | ||
1668 | public void llSetContentType(LSL_Key id, LSL_Integer type) | ||
1669 | { | ||
1670 | m_host.AddScriptLPS(1); | ||
1671 | |||
1672 | if (m_UrlModule == null) | ||
1673 | return; | ||
1674 | |||
1675 | // Make sure the content type is text/plain to start with | ||
1676 | m_UrlModule.HttpContentType(new UUID(id), "text/plain"); | ||
1677 | |||
1678 | // Is the object owner online and in the region | ||
1679 | ScenePresence agent = World.GetScenePresence(m_host.ParentGroup.OwnerID); | ||
1680 | if (agent == null || agent.IsChildAgent) | ||
1681 | return; // Fail if the owner is not in the same region | ||
1682 | |||
1683 | // Is it the embeded browser? | ||
1684 | string userAgent = m_UrlModule.GetHttpHeader(new UUID(id), "user-agent"); | ||
1685 | if (userAgent.IndexOf("SecondLife") < 0) | ||
1686 | return; // Not the embedded browser. Is this check good enough? | ||
1687 | |||
1688 | // Use the IP address of the client and check against the request | ||
1689 | // seperate logins from the same IP will allow all of them to get non-text/plain as long | ||
1690 | // as the owner is in the region. Same as SL! | ||
1691 | string logonFromIPAddress = agent.ControllingClient.RemoteEndPoint.Address.ToString(); | ||
1692 | string requestFromIPAddress = m_UrlModule.GetHttpHeader(new UUID(id), "remote_addr"); | ||
1693 | //m_log.Debug("IP from header='" + requestFromIPAddress + "' IP from endpoint='" + logonFromIPAddress + "'"); | ||
1694 | if (requestFromIPAddress == null || requestFromIPAddress.Trim() == "") | ||
1695 | return; | ||
1696 | if (logonFromIPAddress == null || logonFromIPAddress.Trim() == "") | ||
1697 | return; | ||
1698 | |||
1699 | // If the request isnt from the same IP address then the request cannot be from the owner | ||
1700 | if (!requestFromIPAddress.Trim().Equals(logonFromIPAddress.Trim())) | ||
1701 | return; | ||
1702 | |||
1703 | switch (type) | ||
1704 | { | ||
1705 | case ScriptBaseClass.CONTENT_TYPE_HTML: | ||
1706 | m_UrlModule.HttpContentType(new UUID(id), "text/html"); | ||
1707 | break; | ||
1708 | case ScriptBaseClass.CONTENT_TYPE_XML: | ||
1709 | m_UrlModule.HttpContentType(new UUID(id), "application/xml"); | ||
1710 | break; | ||
1711 | case ScriptBaseClass.CONTENT_TYPE_XHTML: | ||
1712 | m_UrlModule.HttpContentType(new UUID(id), "application/xhtml+xml"); | ||
1713 | break; | ||
1714 | case ScriptBaseClass.CONTENT_TYPE_ATOM: | ||
1715 | m_UrlModule.HttpContentType(new UUID(id), "application/atom+xml"); | ||
1716 | break; | ||
1717 | case ScriptBaseClass.CONTENT_TYPE_JSON: | ||
1718 | m_UrlModule.HttpContentType(new UUID(id), "application/json"); | ||
1719 | break; | ||
1720 | case ScriptBaseClass.CONTENT_TYPE_LLSD: | ||
1721 | m_UrlModule.HttpContentType(new UUID(id), "application/llsd+xml"); | ||
1722 | break; | ||
1723 | case ScriptBaseClass.CONTENT_TYPE_FORM: | ||
1724 | m_UrlModule.HttpContentType(new UUID(id), "application/x-www-form-urlencoded"); | ||
1725 | break; | ||
1726 | case ScriptBaseClass.CONTENT_TYPE_RSS: | ||
1727 | m_UrlModule.HttpContentType(new UUID(id), "application/rss+xml"); | ||
1728 | break; | ||
1729 | default: | ||
1730 | m_UrlModule.HttpContentType(new UUID(id), "text/plain"); | ||
1731 | break; | ||
1732 | } | ||
1733 | } | ||
1734 | */ | ||
1735 | |||
1667 | public void SetTexGen(SceneObjectPart part, int face,int style) | 1736 | public void SetTexGen(SceneObjectPart part, int face,int style) |
1668 | { | 1737 | { |
1669 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) | 1738 | if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) |
@@ -2772,9 +2841,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
2772 | // send the sound, once, to all clients in range | 2841 | // send the sound, once, to all clients in range |
2773 | if (m_SoundModule != null) | 2842 | if (m_SoundModule != null) |
2774 | { | 2843 | { |
2775 | m_SoundModule.SendSound(m_host.UUID, | 2844 | m_SoundModule.SendSound( |
2776 | ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), volume, false, 0, | 2845 | m_host.UUID, |
2777 | 0, false, false); | 2846 | ScriptUtils.GetAssetIdFromKeyOrItemName(m_host, sound, AssetType.Sound), |
2847 | volume, false, m_host.SoundQueueing ? (byte)SoundFlags.Queue : (byte)SoundFlags.None, | ||
2848 | 0, false, false); | ||
2778 | } | 2849 | } |
2779 | } | 2850 | } |
2780 | 2851 | ||
@@ -5108,6 +5179,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
5108 | 5179 | ||
5109 | s = Math.Cos(angle * 0.5); | 5180 | s = Math.Cos(angle * 0.5); |
5110 | t = Math.Sin(angle * 0.5); // temp value to avoid 2 more sin() calcs | 5181 | t = Math.Sin(angle * 0.5); // temp value to avoid 2 more sin() calcs |
5182 | axis = LSL_Vector.Norm(axis); | ||
5111 | x = axis.x * t; | 5183 | x = axis.x * t; |
5112 | y = axis.y * t; | 5184 | y = axis.y * t; |
5113 | z = axis.z * t; | 5185 | z = axis.z * t; |
@@ -5115,41 +5187,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
5115 | return new LSL_Rotation(x,y,z,s); | 5187 | return new LSL_Rotation(x,y,z,s); |
5116 | } | 5188 | } |
5117 | 5189 | ||
5118 | 5190 | /// <summary> | |
5119 | // Xantor 29/apr/2008 | 5191 | /// Returns the axis of rotation for a quaternion |
5120 | // converts a Quaternion to X,Y,Z axis rotations | 5192 | /// </summary> |
5193 | /// <returns></returns> | ||
5194 | /// <param name='rot'></param> | ||
5121 | public LSL_Vector llRot2Axis(LSL_Rotation rot) | 5195 | public LSL_Vector llRot2Axis(LSL_Rotation rot) |
5122 | { | 5196 | { |
5123 | m_host.AddScriptLPS(1); | 5197 | m_host.AddScriptLPS(1); |
5124 | double x,y,z; | ||
5125 | 5198 | ||
5126 | if (rot.s > 1) // normalization needed | 5199 | if (Math.Abs(rot.s) > 1) // normalization needed |
5127 | { | 5200 | rot.Normalize(); |
5128 | double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y + | ||
5129 | rot.z * rot.z + rot.s * rot.s); | ||
5130 | |||
5131 | rot.x /= length; | ||
5132 | rot.y /= length; | ||
5133 | rot.z /= length; | ||
5134 | rot.s /= length; | ||
5135 | 5201 | ||
5136 | } | ||
5137 | |||
5138 | // double angle = 2 * Math.Acos(rot.s); | ||
5139 | double s = Math.Sqrt(1 - rot.s * rot.s); | 5202 | double s = Math.Sqrt(1 - rot.s * rot.s); |
5140 | if (s < 0.001) | 5203 | if (s < 0.001) |
5141 | { | 5204 | { |
5142 | x = 1; | 5205 | return new LSL_Vector(1, 0, 0); |
5143 | y = z = 0; | ||
5144 | } | 5206 | } |
5145 | else | 5207 | else |
5146 | { | 5208 | { |
5147 | x = rot.x / s; // normalise axis | 5209 | double invS = 1.0 / s; |
5148 | y = rot.y / s; | 5210 | if (rot.s < 0) invS = -invS; |
5149 | z = rot.z / s; | 5211 | return new LSL_Vector(rot.x * invS, rot.y * invS, rot.z * invS); |
5150 | } | 5212 | } |
5151 | |||
5152 | return new LSL_Vector(x,y,z); | ||
5153 | } | 5213 | } |
5154 | 5214 | ||
5155 | 5215 | ||
@@ -5158,18 +5218,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
5158 | { | 5218 | { |
5159 | m_host.AddScriptLPS(1); | 5219 | m_host.AddScriptLPS(1); |
5160 | 5220 | ||
5161 | if (rot.s > 1) // normalization needed | 5221 | if (Math.Abs(rot.s) > 1) // normalization needed |
5162 | { | 5222 | rot.Normalize(); |
5163 | double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y + | ||
5164 | rot.z * rot.z + rot.s * rot.s); | ||
5165 | |||
5166 | rot.x /= length; | ||
5167 | rot.y /= length; | ||
5168 | rot.z /= length; | ||
5169 | rot.s /= length; | ||
5170 | } | ||
5171 | 5223 | ||
5172 | double angle = 2 * Math.Acos(rot.s); | 5224 | double angle = 2 * Math.Acos(rot.s); |
5225 | if (angle > Math.PI) | ||
5226 | angle = 2 * Math.PI - angle; | ||
5173 | 5227 | ||
5174 | return angle; | 5228 | return angle; |
5175 | } | 5229 | } |
@@ -8255,7 +8309,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8255 | return null; | 8309 | return null; |
8256 | 8310 | ||
8257 | string ph = rules.Data[idx++].ToString(); | 8311 | string ph = rules.Data[idx++].ToString(); |
8258 | parentgrp.ScriptSetPhantomStatus(ph.Equals("1")); | 8312 | part.ParentGroup.ScriptSetPhantomStatus(ph.Equals("1")); |
8259 | 8313 | ||
8260 | break; | 8314 | break; |
8261 | 8315 | ||
@@ -8308,7 +8362,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
8308 | return null; | 8362 | return null; |
8309 | string temp = rules.Data[idx++].ToString(); | 8363 | string temp = rules.Data[idx++].ToString(); |
8310 | 8364 | ||
8311 | parentgrp.ScriptSetTemporaryStatus(temp.Equals("1")); | 8365 | part.ParentGroup.ScriptSetTemporaryStatus(temp.Equals("1")); |
8312 | 8366 | ||
8313 | break; | 8367 | break; |
8314 | 8368 | ||
@@ -12673,6 +12727,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api | |||
12673 | public void llSetSoundQueueing(int queue) | 12727 | public void llSetSoundQueueing(int queue) |
12674 | { | 12728 | { |
12675 | m_host.AddScriptLPS(1); | 12729 | m_host.AddScriptLPS(1); |
12730 | |||
12731 | if (m_SoundModule != null) | ||
12732 | m_SoundModule.SetSoundQueueing(m_host.UUID, queue == ScriptBaseClass.TRUE.value); | ||
12676 | } | 12733 | } |
12677 | 12734 | ||
12678 | public void llCollisionSprite(string impact_sprite) | 12735 | public void llCollisionSprite(string impact_sprite) |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index daf89e5..2260ec8 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs | |||
@@ -340,6 +340,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces | |||
340 | void llSetCameraParams(LSL_List rules); | 340 | void llSetCameraParams(LSL_List rules); |
341 | void llSetClickAction(int action); | 341 | void llSetClickAction(int action); |
342 | void llSetColor(LSL_Vector color, int face); | 342 | void llSetColor(LSL_Vector color, int face); |
343 | void llSetContentType(LSL_Key id, LSL_Integer type); | ||
343 | void llSetDamage(double damage); | 344 | void llSetDamage(double damage); |
344 | void llSetForce(LSL_Vector force, int local); | 345 | void llSetForce(LSL_Vector force, int local); |
345 | void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local); | 346 | void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local); |
@@ -434,6 +435,5 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces | |||
434 | void llSetKeyframedMotion(LSL_List frames, LSL_List options); | 435 | void llSetKeyframedMotion(LSL_List frames, LSL_List options); |
435 | LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); | 436 | LSL_List GetPrimitiveParamsEx(LSL_Key prim, LSL_List rules); |
436 | LSL_List llGetPhysicsMaterial(); | 437 | LSL_List llGetPhysicsMaterial(); |
437 | void llSetContentType(LSL_Key id, LSL_Integer content_type); | ||
438 | } | 438 | } |
439 | } | 439 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index 6efa73f..15b21ac 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs | |||
@@ -361,6 +361,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
361 | public const int HTTP_CUSTOM_HEADER = 5; | 361 | public const int HTTP_CUSTOM_HEADER = 5; |
362 | public const int HTTP_PRAGMA_NO_CACHE = 6; | 362 | public const int HTTP_PRAGMA_NO_CACHE = 6; |
363 | 363 | ||
364 | // llSetContentType | ||
365 | public const int CONTENT_TYPE_TEXT = 0; //text/plain | ||
366 | public const int CONTENT_TYPE_HTML = 1; //text/html | ||
367 | public const int CONTENT_TYPE_XML = 2; //application/xml | ||
368 | public const int CONTENT_TYPE_XHTML = 3; //application/xhtml+xml | ||
369 | public const int CONTENT_TYPE_ATOM = 4; //application/atom+xml | ||
370 | public const int CONTENT_TYPE_JSON = 5; //application/json | ||
371 | public const int CONTENT_TYPE_LLSD = 6; //application/llsd+xml | ||
372 | public const int CONTENT_TYPE_FORM = 7; //application/x-www-form-urlencoded | ||
373 | public const int CONTENT_TYPE_RSS = 8; //application/rss+xml | ||
374 | |||
364 | public const int PRIM_MATERIAL = 2; | 375 | public const int PRIM_MATERIAL = 2; |
365 | public const int PRIM_PHYSICS = 3; | 376 | public const int PRIM_PHYSICS = 3; |
366 | public const int PRIM_TEMP_ON_REZ = 4; | 377 | public const int PRIM_TEMP_ON_REZ = 4; |
@@ -772,8 +783,5 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
772 | /// process message parameter as regex | 783 | /// process message parameter as regex |
773 | /// </summary> | 784 | /// </summary> |
774 | public const int OS_LISTEN_REGEX_MESSAGE = 0x2; | 785 | public const int OS_LISTEN_REGEX_MESSAGE = 0x2; |
775 | |||
776 | public const int CONTENT_TYPE_TEXT = 0; | ||
777 | public const int CONTENT_TYPE_HTML = 1; | ||
778 | } | 786 | } |
779 | } | 787 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 6f3677c..b58686b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs | |||
@@ -1535,6 +1535,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
1535 | m_LSL_Functions.llSetColor(color, face); | 1535 | m_LSL_Functions.llSetColor(color, face); |
1536 | } | 1536 | } |
1537 | 1537 | ||
1538 | public void llSetContentType(LSL_Key id, LSL_Integer type) | ||
1539 | { | ||
1540 | m_LSL_Functions.llSetContentType(id, type); | ||
1541 | } | ||
1542 | |||
1538 | public void llSetDamage(double damage) | 1543 | public void llSetDamage(double damage) |
1539 | { | 1544 | { |
1540 | m_LSL_Functions.llSetDamage(damage); | 1545 | m_LSL_Functions.llSetDamage(damage); |
@@ -2014,10 +2019,5 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase | |||
2014 | { | 2019 | { |
2015 | return m_LSL_Functions.llGetPhysicsMaterial(); | 2020 | return m_LSL_Functions.llGetPhysicsMaterial(); |
2016 | } | 2021 | } |
2017 | |||
2018 | public void llSetContentType(LSL_Key id, LSL_Integer content_type) | ||
2019 | { | ||
2020 | m_LSL_Functions.llSetContentType(id, content_type); | ||
2021 | } | ||
2022 | } | 2022 | } |
2023 | } | 2023 | } |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 26850c4..8da06d1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs | |||
@@ -528,8 +528,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
528 | { | 528 | { |
529 | File.Delete(savedState); | 529 | File.Delete(savedState); |
530 | } | 530 | } |
531 | catch(Exception) | 531 | catch (Exception e) |
532 | { | 532 | { |
533 | m_log.Warn( | ||
534 | string.Format( | ||
535 | "[SCRIPT INSTANCE]: Could not delete script state {0} for script {1} (id {2}) in part {3} (id {4}) in object {5} in {6}. Exception ", | ||
536 | ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name), | ||
537 | e); | ||
533 | } | 538 | } |
534 | } | 539 | } |
535 | 540 | ||
@@ -567,9 +572,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance | |||
567 | 572 | ||
568 | public bool Stop(int timeout) | 573 | public bool Stop(int timeout) |
569 | { | 574 | { |
570 | // m_log.DebugFormat( | 575 | if (DebugLevel >= 1) |
571 | // "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}", | 576 | m_log.DebugFormat( |
572 | // ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks); | 577 | "[SCRIPT INSTANCE]: Stopping script {0} {1} in {2} {3} with timeout {4} {5} {6}", |
578 | ScriptName, ItemID, PrimName, ObjectID, timeout, m_InSelfDelete, DateTime.Now.Ticks); | ||
573 | 579 | ||
574 | IScriptWorkItem workItem; | 580 | IScriptWorkItem workItem; |
575 | 581 | ||
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index b524a18..4ba0e64 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs | |||
@@ -371,6 +371,31 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
371 | 371 | ||
372 | #endregion | 372 | #endregion |
373 | 373 | ||
374 | #region Methods | ||
375 | public Quaternion Normalize() | ||
376 | { | ||
377 | double length = Math.Sqrt(x * x + y * y + z * z + s * s); | ||
378 | if (length < float.Epsilon) | ||
379 | { | ||
380 | x = 0; | ||
381 | y = 0; | ||
382 | z = 0; | ||
383 | s = 1; | ||
384 | } | ||
385 | else | ||
386 | { | ||
387 | |||
388 | double invLength = 1.0 / length; | ||
389 | x *= invLength; | ||
390 | y *= invLength; | ||
391 | z *= invLength; | ||
392 | s *= invLength; | ||
393 | } | ||
394 | |||
395 | return this; | ||
396 | } | ||
397 | #endregion | ||
398 | |||
374 | #region Overriders | 399 | #region Overriders |
375 | 400 | ||
376 | public override int GetHashCode() | 401 | public override int GetHashCode() |
@@ -546,21 +571,33 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
546 | 571 | ||
547 | set {m_data = value; } | 572 | set {m_data = value; } |
548 | } | 573 | } |
549 | // Function to obtain LSL type from an index. This is needed | 574 | |
550 | // because LSL lists allow for multiple types, and safely | 575 | /// <summary> |
551 | // iterating in them requires a type check. | 576 | /// Obtain LSL type from an index. |
577 | /// </summary> | ||
578 | /// <remarks> | ||
579 | /// This is needed because LSL lists allow for multiple types, and safely | ||
580 | /// iterating in them requires a type check. | ||
581 | /// </remarks> | ||
582 | /// <returns></returns> | ||
583 | /// <param name='itemIndex'></param> | ||
552 | public Type GetLSLListItemType(int itemIndex) | 584 | public Type GetLSLListItemType(int itemIndex) |
553 | { | 585 | { |
554 | return m_data[itemIndex].GetType(); | 586 | return m_data[itemIndex].GetType(); |
555 | } | 587 | } |
556 | 588 | ||
557 | // Member functions to obtain item as specific types. | 589 | /// <summary> |
558 | // For cases where implicit conversions would apply if items | 590 | /// Obtain float from an index. |
559 | // were not in a list (e.g. integer to float, but not float | 591 | /// </summary> |
560 | // to integer) functions check for alternate types so as to | 592 | /// <remarks> |
561 | // down-cast from Object to the correct type. | 593 | /// For cases where implicit conversions would apply if items |
562 | // Note: no checks for item index being valid are performed | 594 | /// were not in a list (e.g. integer to float, but not float |
563 | 595 | /// to integer) functions check for alternate types so as to | |
596 | /// down-cast from Object to the correct type. | ||
597 | /// Note: no checks for item index being valid are performed | ||
598 | /// </remarks> | ||
599 | /// <returns></returns> | ||
600 | /// <param name='itemIndex'></param> | ||
564 | public LSL_Types.LSLFloat GetLSLFloatItem(int itemIndex) | 601 | public LSL_Types.LSLFloat GetLSLFloatItem(int itemIndex) |
565 | { | 602 | { |
566 | if (m_data[itemIndex] is LSL_Types.LSLInteger) | 603 | if (m_data[itemIndex] is LSL_Types.LSLInteger) |
@@ -591,26 +628,14 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
591 | 628 | ||
592 | public LSL_Types.LSLString GetLSLStringItem(int itemIndex) | 629 | public LSL_Types.LSLString GetLSLStringItem(int itemIndex) |
593 | { | 630 | { |
594 | if (m_data[itemIndex] is LSL_Types.key) | 631 | if (m_data[itemIndex] is LSL_Types.key) |
595 | { | 632 | { |
596 | return (LSL_Types.key)m_data[itemIndex]; | 633 | return (LSL_Types.key)m_data[itemIndex]; |
597 | } | 634 | } |
598 | else if (m_data[itemIndex] is String) | 635 | else |
599 | { | 636 | { |
600 | return new LSL_Types.LSLString((string)m_data[itemIndex]); | 637 | return new LSL_Types.LSLString(m_data[itemIndex].ToString()); |
601 | } | 638 | } |
602 | else if (m_data[itemIndex] is LSL_Types.LSLFloat) | ||
603 | { | ||
604 | return new LSL_Types.LSLString((LSLFloat)m_data[itemIndex]); | ||
605 | } | ||
606 | else if (m_data[itemIndex] is LSL_Types.LSLInteger) | ||
607 | { | ||
608 | return new LSL_Types.LSLString((LSLInteger)m_data[itemIndex]); | ||
609 | } | ||
610 | else | ||
611 | { | ||
612 | return (LSL_Types.LSLString)m_data[itemIndex]; | ||
613 | } | ||
614 | } | 639 | } |
615 | 640 | ||
616 | public LSL_Types.LSLInteger GetLSLIntegerItem(int itemIndex) | 641 | public LSL_Types.LSLInteger GetLSLIntegerItem(int itemIndex) |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 17243ab..9d1e143 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | |||
@@ -551,7 +551,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
551 | /// <param name="instance"></param> | 551 | /// <param name="instance"></param> |
552 | /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param> | 552 | /// <param name="keySelector">Basis on which to sort output. Can be null if no sort needs to take place</param> |
553 | private void HandleScriptsAction<TKey>( | 553 | private void HandleScriptsAction<TKey>( |
554 | string[] cmdparams, Action<IScriptInstance> action, Func<IScriptInstance, TKey> keySelector) | 554 | string[] cmdparams, Action<IScriptInstance> action, System.Func<IScriptInstance, TKey> keySelector) |
555 | { | 555 | { |
556 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) | 556 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) |
557 | return; | 557 | return; |
@@ -609,7 +609,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
609 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) | 609 | if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_Scene)) |
610 | return; | 610 | return; |
611 | 611 | ||
612 | MainConsole.Instance.OutputFormat(GetStatusReport()); | 612 | MainConsole.Instance.Output(GetStatusReport()); |
613 | } | 613 | } |
614 | 614 | ||
615 | public string GetStatusReport() | 615 | public string GetStatusReport() |
@@ -708,7 +708,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
708 | sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); | 708 | sb.AppendFormat("Containing part UUID: {0}\n", instance.ObjectID); |
709 | sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); | 709 | sb.AppendFormat("Position : {0}\n", sop.AbsolutePosition); |
710 | 710 | ||
711 | MainConsole.Instance.OutputFormat(sb.ToString()); | 711 | MainConsole.Instance.Output(sb.ToString()); |
712 | } | 712 | } |
713 | 713 | ||
714 | private void HandleSuspendScript(IScriptInstance instance) | 714 | private void HandleSuspendScript(IScriptInstance instance) |
@@ -1599,7 +1599,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
1599 | startInfo.MaxWorkerThreads = maxThreads; | 1599 | startInfo.MaxWorkerThreads = maxThreads; |
1600 | startInfo.MinWorkerThreads = minThreads; | 1600 | startInfo.MinWorkerThreads = minThreads; |
1601 | startInfo.ThreadPriority = threadPriority;; | 1601 | startInfo.ThreadPriority = threadPriority;; |
1602 | startInfo.StackSize = stackSize; | 1602 | startInfo.MaxStackSize = stackSize; |
1603 | startInfo.StartSuspended = true; | 1603 | startInfo.StartSuspended = true; |
1604 | 1604 | ||
1605 | m_ThreadPool = new SmartThreadPool(startInfo); | 1605 | m_ThreadPool = new SmartThreadPool(startInfo); |
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs index 8dd7677..9d9dee1 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XWorkItem.cs | |||
@@ -52,16 +52,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
52 | return wr.Cancel(); | 52 | return wr.Cancel(); |
53 | } | 53 | } |
54 | 54 | ||
55 | public void Abort() | 55 | public bool Abort() |
56 | { | 56 | { |
57 | wr.Abort(); | 57 | return wr.Cancel(true); |
58 | } | 58 | } |
59 | 59 | ||
60 | public bool Wait(int t) | 60 | public bool Wait(int t) |
61 | { | 61 | { |
62 | // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the | 62 | // We use the integer version of WaitAll because the current version of SmartThreadPool has a bug with the |
63 | // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an | 63 | // TimeSpan version. The number of milliseconds in TimeSpan is an int64 so when STP casts it down to an |
64 | // int (32-bit) we can end up with bad values. This occurs on Windows though curious not on Mono 2.10.8 | 64 | // int (32-bit) we can end up with bad values. This occurs on Windows though curiously not on Mono 2.10.8 |
65 | // (or very likely other versions of Mono at least up until 3.0.3). | 65 | // (or very likely other versions of Mono at least up until 3.0.3). |
66 | return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); | 66 | return SmartThreadPool.WaitAll(new IWorkItemResult[] {wr}, t, false); |
67 | } | 67 | } |