clockwerk-opensim-stable – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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 using System;
28 using System.IO;
29 using System.Collections.Generic;
30 using System.Reflection;
31  
32 using Nini.Config;
33 using OpenMetaverse;
34 using log4net;
35 using Mono.Addins;
36  
37 using OpenSim.Framework;
38 using OpenSim.Region.Framework.Interfaces;
39 using OpenSim.Region.Framework.Scenes;
40  
41 namespace OpenSim.Region.CoreModules.World.Sound
42 {
43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SoundModule")]
44 public class SoundModule : INonSharedRegionModule, ISoundModule
45 {
46 // private static readonly ILog m_log = LogManager.GetLogger(
47 // MethodBase.GetCurrentMethod().DeclaringType);
48  
49 private Scene m_scene;
50  
51 public bool Enabled { get; private set; }
52  
53 public float MaxDistance { get; private set; }
54  
55 #region INonSharedRegionModule
56  
57 public void Initialise(IConfigSource configSource)
58 {
59 IConfig config = configSource.Configs["Sounds"];
60  
61 if (config == null)
62 {
63 Enabled = true;
64 MaxDistance = 100.0f;
65 }
66 else
67 {
68 Enabled = config.GetString("Module", "OpenSim.Region.CoreModules.dll:SoundModule") ==
69 Path.GetFileName(Assembly.GetExecutingAssembly().Location)
70 + ":" + MethodBase.GetCurrentMethod().DeclaringType.Name;
71 MaxDistance = config.GetFloat("MaxDistance", 100.0f);
72 }
73 }
74  
75 public void AddRegion(Scene scene) { }
76  
77 public void RemoveRegion(Scene scene)
78 {
79 m_scene.EventManager.OnNewClient -= OnNewClient;
80 }
81  
82 public void RegionLoaded(Scene scene)
83 {
84 if (!Enabled)
85 return;
86  
87 m_scene = scene;
88 m_scene.EventManager.OnNewClient += OnNewClient;
89  
90 m_scene.RegisterModuleInterface<ISoundModule>(this);
91 }
92  
93 public void Close() { }
94  
95 public Type ReplaceableInterface
96 {
97 get { return typeof(ISoundModule); }
98 }
99  
100 public string Name { get { return "Sound Module"; } }
101  
102 #endregion
103  
104 #region Event Handlers
105  
106 private void OnNewClient(IClientAPI client)
107 {
108 client.OnSoundTrigger += TriggerSound;
109 }
110  
111 #endregion
112  
113 #region ISoundModule
114  
115 public virtual void PlayAttachedSound(
116 UUID soundID, UUID ownerID, UUID objectID, double gain, Vector3 position, byte flags, float radius)
117 {
118 SceneObjectPart part;
119 if (!m_scene.TryGetSceneObjectPart(objectID, out part))
120 return;
121  
122 SceneObjectGroup grp = part.ParentGroup;
123  
124 if (radius == 0)
125 radius = MaxDistance;
126  
127 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
128 {
129 double dis = Util.GetDistanceTo(sp.AbsolutePosition, position);
130 if (dis > MaxDistance) // Max audio distance
131 return;
132  
133 if (grp.IsAttachment)
134 {
135 if (grp.HasPrivateAttachmentPoint && sp.ControllingClient.AgentId != grp.OwnerID)
136 return;
137  
138 if (sp.ControllingClient.AgentId == grp.OwnerID)
139 dis = 0;
140 }
141  
142 // Scale by distance
143 double thisSpGain = gain * ((radius - dis) / radius);
144  
145 sp.ControllingClient.SendPlayAttachedSound(soundID, objectID,
146 ownerID, (float)thisSpGain, flags);
147 });
148 }
149  
150 public virtual void TriggerSound(
151 UUID soundId, UUID ownerID, UUID objectID, UUID parentID, double gain, Vector3 position, UInt64 handle, float radius)
152 {
153 SceneObjectPart part;
154 if (!m_scene.TryGetSceneObjectPart(objectID, out part))
155 {
156 ScenePresence sp;
157 if (!m_scene.TryGetScenePresence(ownerID, out sp))
158 return;
159 }
160 else
161 {
162 SceneObjectGroup grp = part.ParentGroup;
163  
164 if (grp.IsAttachment && grp.AttachmentPoint > 30)
165 {
166 objectID = ownerID;
167 parentID = ownerID;
168 }
169 }
170  
171 if (radius == 0)
172 radius = MaxDistance;
173  
174 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
175 {
176 double dis = Util.GetDistanceTo(sp.AbsolutePosition, position);
177  
178 if (dis > MaxDistance) // Max audio distance
179 return;
180  
181 // Scale by distance
182 double thisSpGain = gain * ((radius - dis) / radius);
183  
184 sp.ControllingClient.SendTriggeredSound(soundId, ownerID,
185 objectID, parentID, handle, position,
186 (float)thisSpGain);
187 });
188 }
189  
190 public virtual void StopSound(UUID objectID)
191 {
192 SceneObjectPart m_host;
193 if (!m_scene.TryGetSceneObjectPart(objectID, out m_host))
194 return;
195  
196 StopSound(m_host);
197 }
198  
199 private static void StopSound(SceneObjectPart m_host)
200 {
201 m_host.AdjustSoundGain(0);
202 // Xantor 20080528: Clear prim data of sound instead
203 if (m_host.ParentGroup.LoopSoundSlavePrims.Contains(m_host))
204 {
205 if (m_host.ParentGroup.LoopSoundMasterPrim == m_host)
206 {
207 foreach (SceneObjectPart part in m_host.ParentGroup.LoopSoundSlavePrims)
208 {
209 part.Sound = UUID.Zero;
210 part.SoundFlags = 1 << 5;
211 part.SoundRadius = 0;
212 part.ScheduleFullUpdate();
213 part.SendFullUpdateToAllClients();
214 }
215 m_host.ParentGroup.LoopSoundMasterPrim = null;
216 m_host.ParentGroup.LoopSoundSlavePrims.Clear();
217 }
218 else
219 {
220 m_host.Sound = UUID.Zero;
221 m_host.SoundFlags = 1 << 5;
222 m_host.SoundRadius = 0;
223 m_host.ScheduleFullUpdate();
224 m_host.SendFullUpdateToAllClients();
225 }
226 }
227 else
228 {
229 m_host.Sound = UUID.Zero;
230 m_host.SoundFlags = 1 << 5;
231 m_host.SoundRadius = 0;
232 m_host.ScheduleFullUpdate();
233 m_host.SendFullUpdateToAllClients();
234 }
235 }
236  
237 public virtual void PreloadSound(UUID objectID, UUID soundID, float radius)
238 {
239 SceneObjectPart part;
240 if (soundID == UUID.Zero
241 || !m_scene.TryGetSceneObjectPart(objectID, out part))
242 {
243 return;
244 }
245  
246 if (radius == 0)
247 radius = MaxDistance;
248  
249 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
250 {
251 if (!(Util.GetDistanceTo(sp.AbsolutePosition, part.AbsolutePosition) >= MaxDistance))
252 sp.ControllingClient.SendPreLoadSound(objectID, objectID, soundID);
253 });
254 }
255  
256 // Xantor 20080528 we should do this differently.
257 // 1) apply the sound to the object
258 // 2) schedule full update
259 // just sending the sound out once doesn't work so well when other avatars come in view later on
260 // or when the prim gets moved, changed, sat on, whatever
261 // see large number of mantises (mantes?)
262 // 20080530 Updated to remove code duplication
263 // 20080530 Stop sound if there is one, otherwise volume only changes don't work
264 public void LoopSound(UUID objectID, UUID soundID,
265 double volume, double radius, bool isMaster)
266 {
267 SceneObjectPart m_host;
268 if (!m_scene.TryGetSceneObjectPart(objectID, out m_host))
269 return;
270  
271 if (isMaster)
272 m_host.ParentGroup.LoopSoundMasterPrim = m_host;
273  
274 if (m_host.Sound != UUID.Zero)
275 StopSound(m_host);
276  
277 m_host.Sound = soundID;
278 m_host.SoundGain = volume;
279 m_host.SoundFlags = 1; // looping
280 m_host.SoundRadius = radius;
281  
282 m_host.ScheduleFullUpdate();
283 m_host.SendFullUpdateToAllClients();
284 }
285  
286 public void SendSound(UUID objectID, UUID soundID, double volume,
287 bool triggered, byte flags, float radius, bool useMaster,
288 bool isMaster)
289 {
290 if (soundID == UUID.Zero)
291 return;
292  
293 SceneObjectPart part;
294 if (!m_scene.TryGetSceneObjectPart(objectID, out part))
295 return;
296  
297 volume = Util.Clip((float)volume, 0, 1);
298  
299 UUID parentID = part.ParentGroup.UUID;
300  
301 Vector3 position = part.AbsolutePosition; // region local
302 ulong regionHandle = m_scene.RegionInfo.RegionHandle;
303  
304 if (useMaster)
305 {
306 if (isMaster)
307 {
308 if (triggered)
309 TriggerSound(soundID, part.OwnerID, part.UUID, parentID, volume, position, regionHandle, radius);
310 else
311 PlayAttachedSound(soundID, part.OwnerID, part.UUID, volume, position, flags, radius);
312 part.ParentGroup.PlaySoundMasterPrim = part;
313 if (triggered)
314 TriggerSound(soundID, part.OwnerID, part.UUID, parentID, volume, position, regionHandle, radius);
315 else
316 PlayAttachedSound(soundID, part.OwnerID, part.UUID, volume, position, flags, radius);
317 foreach (SceneObjectPart prim in part.ParentGroup.PlaySoundSlavePrims)
318 {
319 position = prim.AbsolutePosition; // region local
320 if (triggered)
321 TriggerSound(soundID, part.OwnerID, prim.UUID, parentID, volume, position, regionHandle, radius);
322 else
323 PlayAttachedSound(soundID, part.OwnerID, prim.UUID, volume, position, flags, radius);
324 }
325 part.ParentGroup.PlaySoundSlavePrims.Clear();
326 part.ParentGroup.PlaySoundMasterPrim = null;
327 }
328 else
329 {
330 part.ParentGroup.PlaySoundSlavePrims.Add(part);
331 }
332 }
333 else
334 {
335 if (triggered)
336 TriggerSound(soundID, part.OwnerID, part.UUID, parentID, volume, position, regionHandle, radius);
337 else
338 PlayAttachedSound(soundID, part.OwnerID, part.UUID, volume, position, flags, radius);
339 }
340 }
341  
342 public void TriggerSoundLimited(UUID objectID, UUID sound,
343 double volume, Vector3 min, Vector3 max)
344 {
345 if (sound == UUID.Zero)
346 return;
347  
348 SceneObjectPart part;
349 if (!m_scene.TryGetSceneObjectPart(objectID, out part))
350 return;
351  
352 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
353 {
354 double dis = Util.GetDistanceTo(sp.AbsolutePosition,
355 part.AbsolutePosition);
356  
357 if (dis > MaxDistance) // Max audio distance
358 return;
359 else if (!Util.IsInsideBox(sp.AbsolutePosition, min, max))
360 return;
361  
362 // Scale by distance
363 double thisSpGain = volume * ((MaxDistance - dis) / MaxDistance);
364  
365 sp.ControllingClient.SendTriggeredSound(sound, part.OwnerID,
366 part.UUID, part.ParentGroup.UUID,
367 m_scene.RegionInfo.RegionHandle,
368 part.AbsolutePosition, (float)thisSpGain);
369 });
370 }
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  
381 #endregion
382 }
383 }