diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/KeyframeMotion.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | 710 |
1 files changed, 710 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs new file mode 100644 index 0000000..5a1fd13 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/KeyframeMotion.cs | |||
@@ -0,0 +1,710 @@ | |||
1 | // Proprietary code of Avination Virtual Limited | ||
2 | // (c) 2012 Melanie Thielker | ||
3 | // | ||
4 | |||
5 | using System; | ||
6 | using System.Timers; | ||
7 | using System.Collections; | ||
8 | using System.Collections.Generic; | ||
9 | using System.IO; | ||
10 | using System.Diagnostics; | ||
11 | using System.Reflection; | ||
12 | using System.Threading; | ||
13 | using OpenMetaverse; | ||
14 | using OpenSim.Framework; | ||
15 | using OpenSim.Region.Framework.Interfaces; | ||
16 | using OpenSim.Region.Physics.Manager; | ||
17 | using OpenSim.Region.Framework.Scenes.Serialization; | ||
18 | using System.Runtime.Serialization.Formatters.Binary; | ||
19 | using System.Runtime.Serialization; | ||
20 | using Timer = System.Timers.Timer; | ||
21 | using log4net; | ||
22 | |||
23 | namespace OpenSim.Region.Framework.Scenes | ||
24 | { | ||
25 | public static class KeyframeTimer | ||
26 | { | ||
27 | private static Timer m_timer; | ||
28 | private static Dictionary<KeyframeMotion, object> m_motions = new Dictionary<KeyframeMotion, object>(); | ||
29 | private static object m_lockObject = new object(); | ||
30 | private static object m_timerLock = new object(); | ||
31 | public const double timerInterval = 50.0; | ||
32 | |||
33 | static KeyframeTimer() | ||
34 | { | ||
35 | m_timer = new Timer(); | ||
36 | m_timer.Interval = timerInterval; | ||
37 | m_timer.AutoReset = true; | ||
38 | m_timer.Elapsed += OnTimer; | ||
39 | |||
40 | m_timer.Start(); | ||
41 | } | ||
42 | |||
43 | private static void OnTimer(object sender, ElapsedEventArgs ea) | ||
44 | { | ||
45 | if (!Monitor.TryEnter(m_timerLock)) | ||
46 | return; | ||
47 | |||
48 | try | ||
49 | { | ||
50 | List<KeyframeMotion> motions; | ||
51 | |||
52 | lock (m_lockObject) | ||
53 | { | ||
54 | motions = new List<KeyframeMotion>(m_motions.Keys); | ||
55 | } | ||
56 | |||
57 | foreach (KeyframeMotion m in motions) | ||
58 | { | ||
59 | try | ||
60 | { | ||
61 | m.OnTimer(); | ||
62 | } | ||
63 | catch (Exception inner) | ||
64 | { | ||
65 | // Don't stop processing | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | catch (Exception e) | ||
70 | { | ||
71 | // Keep running no matter what | ||
72 | } | ||
73 | finally | ||
74 | { | ||
75 | Monitor.Exit(m_timerLock); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | public static void Add(KeyframeMotion motion) | ||
80 | { | ||
81 | lock (m_lockObject) | ||
82 | { | ||
83 | m_motions[motion] = null; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | public static void Remove(KeyframeMotion motion) | ||
88 | { | ||
89 | lock (m_lockObject) | ||
90 | { | ||
91 | m_motions.Remove(motion); | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | |||
96 | [Serializable] | ||
97 | public class KeyframeMotion | ||
98 | { | ||
99 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
100 | |||
101 | public enum PlayMode : int | ||
102 | { | ||
103 | Forward = 0, | ||
104 | Reverse = 1, | ||
105 | Loop = 2, | ||
106 | PingPong = 3 | ||
107 | }; | ||
108 | |||
109 | [Flags] | ||
110 | public enum DataFormat : int | ||
111 | { | ||
112 | Translation = 2, | ||
113 | Rotation = 1 | ||
114 | } | ||
115 | |||
116 | [Serializable] | ||
117 | public struct Keyframe | ||
118 | { | ||
119 | public Vector3? Position; | ||
120 | public Quaternion? Rotation; | ||
121 | public Quaternion StartRotation; | ||
122 | public int TimeMS; | ||
123 | public int TimeTotal; | ||
124 | public Vector3 AngularVelocity; | ||
125 | }; | ||
126 | |||
127 | private Vector3 m_serializedPosition; | ||
128 | private Vector3 m_basePosition; | ||
129 | private Quaternion m_baseRotation; | ||
130 | |||
131 | private Keyframe m_currentFrame; | ||
132 | |||
133 | private List<Keyframe> m_frames = new List<Keyframe>(); | ||
134 | |||
135 | private Keyframe[] m_keyframes; | ||
136 | |||
137 | // skip timer events. | ||
138 | //timer.stop doesn't assure there aren't event threads still being fired | ||
139 | [NonSerialized()] | ||
140 | private bool m_timerStopped; | ||
141 | |||
142 | [NonSerialized()] | ||
143 | private bool m_isCrossing; | ||
144 | |||
145 | [NonSerialized()] | ||
146 | private bool m_waitingCrossing; | ||
147 | |||
148 | // retry position for cross fail | ||
149 | [NonSerialized()] | ||
150 | private Vector3 m_nextPosition; | ||
151 | |||
152 | [NonSerialized()] | ||
153 | private SceneObjectGroup m_group; | ||
154 | |||
155 | private PlayMode m_mode = PlayMode.Forward; | ||
156 | private DataFormat m_data = DataFormat.Translation | DataFormat.Rotation; | ||
157 | |||
158 | private bool m_running = false; | ||
159 | [NonSerialized()] | ||
160 | private bool m_selected = false; | ||
161 | |||
162 | private int m_iterations = 0; | ||
163 | |||
164 | private int m_skipLoops = 0; | ||
165 | |||
166 | public DataFormat Data | ||
167 | { | ||
168 | get { return m_data; } | ||
169 | } | ||
170 | |||
171 | public bool Selected | ||
172 | { | ||
173 | set | ||
174 | { | ||
175 | if (m_group != null) | ||
176 | { | ||
177 | if (!value) | ||
178 | { | ||
179 | // Once we're let go, recompute positions | ||
180 | if (m_selected) | ||
181 | UpdateSceneObject(m_group); | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | // Save selection position in case we get moved | ||
186 | if (!m_selected) | ||
187 | { | ||
188 | StopTimer(); | ||
189 | m_serializedPosition = m_group.AbsolutePosition; | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | m_isCrossing = false; | ||
194 | m_waitingCrossing = false; | ||
195 | m_selected = value; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | private void StartTimer() | ||
200 | { | ||
201 | KeyframeTimer.Add(this); | ||
202 | m_timerStopped = false; | ||
203 | } | ||
204 | |||
205 | private void StopTimer() | ||
206 | { | ||
207 | m_timerStopped = true; | ||
208 | KeyframeTimer.Remove(this); | ||
209 | } | ||
210 | |||
211 | public static KeyframeMotion FromData(SceneObjectGroup grp, Byte[] data) | ||
212 | { | ||
213 | KeyframeMotion newMotion = null; | ||
214 | |||
215 | try | ||
216 | { | ||
217 | MemoryStream ms = new MemoryStream(data); | ||
218 | BinaryFormatter fmt = new BinaryFormatter(); | ||
219 | |||
220 | newMotion = (KeyframeMotion)fmt.Deserialize(ms); | ||
221 | |||
222 | newMotion.m_group = grp; | ||
223 | |||
224 | if (grp != null && grp.IsSelected) | ||
225 | newMotion.m_selected = true; | ||
226 | |||
227 | newMotion.m_timerStopped = false; | ||
228 | newMotion.m_isCrossing = false; | ||
229 | newMotion.m_waitingCrossing = false; | ||
230 | } | ||
231 | catch | ||
232 | { | ||
233 | newMotion = null; | ||
234 | } | ||
235 | |||
236 | return newMotion; | ||
237 | } | ||
238 | |||
239 | public void UpdateSceneObject(SceneObjectGroup grp) | ||
240 | { | ||
241 | m_isCrossing = false; | ||
242 | m_waitingCrossing = false; | ||
243 | StopTimer(); | ||
244 | |||
245 | if (grp == null) | ||
246 | return; | ||
247 | |||
248 | m_group = grp; | ||
249 | Vector3 grppos = grp.AbsolutePosition; | ||
250 | Vector3 offset = grppos - m_serializedPosition; | ||
251 | // avoid doing it more than once | ||
252 | // current this will happen draging a prim to other region | ||
253 | m_serializedPosition = grppos; | ||
254 | |||
255 | m_basePosition += offset; | ||
256 | m_currentFrame.Position += offset; | ||
257 | |||
258 | m_nextPosition += offset; | ||
259 | |||
260 | for (int i = 0; i < m_frames.Count; i++) | ||
261 | { | ||
262 | Keyframe k = m_frames[i]; | ||
263 | k.Position += offset; | ||
264 | m_frames[i]=k; | ||
265 | } | ||
266 | |||
267 | if (m_running) | ||
268 | Start(); | ||
269 | } | ||
270 | |||
271 | public KeyframeMotion(SceneObjectGroup grp, PlayMode mode, DataFormat data) | ||
272 | { | ||
273 | m_mode = mode; | ||
274 | m_data = data; | ||
275 | |||
276 | m_group = grp; | ||
277 | if (grp != null) | ||
278 | { | ||
279 | m_basePosition = grp.AbsolutePosition; | ||
280 | m_baseRotation = grp.GroupRotation; | ||
281 | } | ||
282 | |||
283 | m_timerStopped = true; | ||
284 | m_isCrossing = false; | ||
285 | m_waitingCrossing = false; | ||
286 | } | ||
287 | |||
288 | public void SetKeyframes(Keyframe[] frames) | ||
289 | { | ||
290 | m_keyframes = frames; | ||
291 | } | ||
292 | |||
293 | public KeyframeMotion Copy(SceneObjectGroup newgrp) | ||
294 | { | ||
295 | StopTimer(); | ||
296 | |||
297 | KeyframeMotion newmotion = new KeyframeMotion(null, m_mode, m_data); | ||
298 | |||
299 | newmotion.m_group = newgrp; | ||
300 | |||
301 | if (m_keyframes != null) | ||
302 | { | ||
303 | newmotion.m_keyframes = new Keyframe[m_keyframes.Length]; | ||
304 | m_keyframes.CopyTo(newmotion.m_keyframes, 0); | ||
305 | } | ||
306 | |||
307 | newmotion.m_frames = new List<Keyframe>(m_frames); | ||
308 | |||
309 | newmotion.m_basePosition = m_basePosition; | ||
310 | newmotion.m_baseRotation = m_baseRotation; | ||
311 | |||
312 | if (m_selected) | ||
313 | newmotion.m_serializedPosition = m_serializedPosition; | ||
314 | else | ||
315 | { | ||
316 | if (m_group != null) | ||
317 | newmotion.m_serializedPosition = m_group.AbsolutePosition; | ||
318 | else | ||
319 | newmotion.m_serializedPosition = m_serializedPosition; | ||
320 | } | ||
321 | |||
322 | newmotion.m_currentFrame = m_currentFrame; | ||
323 | |||
324 | newmotion.m_iterations = m_iterations; | ||
325 | newmotion.m_running = m_running; | ||
326 | |||
327 | if (m_running && !m_waitingCrossing) | ||
328 | StartTimer(); | ||
329 | |||
330 | return newmotion; | ||
331 | } | ||
332 | |||
333 | public void Delete() | ||
334 | { | ||
335 | m_running = false; | ||
336 | StopTimer(); | ||
337 | m_isCrossing = false; | ||
338 | m_waitingCrossing = false; | ||
339 | m_frames.Clear(); | ||
340 | m_keyframes = null; | ||
341 | } | ||
342 | |||
343 | public void Start() | ||
344 | { | ||
345 | m_isCrossing = false; | ||
346 | m_waitingCrossing = false; | ||
347 | if (m_keyframes != null && m_group != null && m_keyframes.Length > 0) | ||
348 | { | ||
349 | StartTimer(); | ||
350 | m_running = true; | ||
351 | } | ||
352 | else | ||
353 | { | ||
354 | m_running = false; | ||
355 | StopTimer(); | ||
356 | } | ||
357 | } | ||
358 | |||
359 | public void Stop() | ||
360 | { | ||
361 | m_running = false; | ||
362 | m_isCrossing = false; | ||
363 | m_waitingCrossing = false; | ||
364 | |||
365 | StopTimer(); | ||
366 | |||
367 | m_basePosition = m_group.AbsolutePosition; | ||
368 | m_baseRotation = m_group.GroupRotation; | ||
369 | |||
370 | m_group.RootPart.Velocity = Vector3.Zero; | ||
371 | m_group.RootPart.AngularVelocity = Vector3.Zero; | ||
372 | m_group.SendGroupRootTerseUpdate(); | ||
373 | // m_group.RootPart.ScheduleTerseUpdate(); | ||
374 | m_frames.Clear(); | ||
375 | } | ||
376 | |||
377 | public void Pause() | ||
378 | { | ||
379 | m_running = false; | ||
380 | StopTimer(); | ||
381 | |||
382 | m_group.RootPart.Velocity = Vector3.Zero; | ||
383 | m_group.RootPart.AngularVelocity = Vector3.Zero; | ||
384 | m_group.SendGroupRootTerseUpdate(); | ||
385 | // m_group.RootPart.ScheduleTerseUpdate(); | ||
386 | |||
387 | } | ||
388 | |||
389 | private void GetNextList() | ||
390 | { | ||
391 | m_frames.Clear(); | ||
392 | Vector3 pos = m_basePosition; | ||
393 | Quaternion rot = m_baseRotation; | ||
394 | |||
395 | if (m_mode == PlayMode.Loop || m_mode == PlayMode.PingPong || m_iterations == 0) | ||
396 | { | ||
397 | int direction = 1; | ||
398 | if (m_mode == PlayMode.Reverse || ((m_mode == PlayMode.PingPong) && ((m_iterations & 1) != 0))) | ||
399 | direction = -1; | ||
400 | |||
401 | int start = 0; | ||
402 | int end = m_keyframes.Length; | ||
403 | |||
404 | if (direction < 0) | ||
405 | { | ||
406 | start = m_keyframes.Length - 1; | ||
407 | end = -1; | ||
408 | } | ||
409 | |||
410 | for (int i = start; i != end ; i += direction) | ||
411 | { | ||
412 | Keyframe k = m_keyframes[i]; | ||
413 | |||
414 | if (k.Position.HasValue) | ||
415 | { | ||
416 | k.Position = (k.Position * direction); | ||
417 | // k.Velocity = (Vector3)k.Position / (k.TimeMS / 1000.0f); | ||
418 | k.Position += pos; | ||
419 | } | ||
420 | else | ||
421 | { | ||
422 | k.Position = pos; | ||
423 | // k.Velocity = Vector3.Zero; | ||
424 | } | ||
425 | |||
426 | k.StartRotation = rot; | ||
427 | if (k.Rotation.HasValue) | ||
428 | { | ||
429 | if (direction == -1) | ||
430 | k.Rotation = Quaternion.Conjugate((Quaternion)k.Rotation); | ||
431 | k.Rotation = rot * k.Rotation; | ||
432 | } | ||
433 | else | ||
434 | { | ||
435 | k.Rotation = rot; | ||
436 | } | ||
437 | |||
438 | /* ang vel not in use for now | ||
439 | |||
440 | float angle = 0; | ||
441 | |||
442 | float aa = k.StartRotation.X * k.StartRotation.X + k.StartRotation.Y * k.StartRotation.Y + k.StartRotation.Z * k.StartRotation.Z + k.StartRotation.W * k.StartRotation.W; | ||
443 | float bb = ((Quaternion)k.Rotation).X * ((Quaternion)k.Rotation).X + ((Quaternion)k.Rotation).Y * ((Quaternion)k.Rotation).Y + ((Quaternion)k.Rotation).Z * ((Quaternion)k.Rotation).Z + ((Quaternion)k.Rotation).W * ((Quaternion)k.Rotation).W; | ||
444 | float aa_bb = aa * bb; | ||
445 | |||
446 | if (aa_bb == 0) | ||
447 | { | ||
448 | angle = 0; | ||
449 | } | ||
450 | else | ||
451 | { | ||
452 | float ab = k.StartRotation.X * ((Quaternion)k.Rotation).X + | ||
453 | k.StartRotation.Y * ((Quaternion)k.Rotation).Y + | ||
454 | k.StartRotation.Z * ((Quaternion)k.Rotation).Z + | ||
455 | k.StartRotation.W * ((Quaternion)k.Rotation).W; | ||
456 | float q = (ab * ab) / aa_bb; | ||
457 | |||
458 | if (q > 1.0f) | ||
459 | { | ||
460 | angle = 0; | ||
461 | } | ||
462 | else | ||
463 | { | ||
464 | angle = (float)Math.Acos(2 * q - 1); | ||
465 | } | ||
466 | } | ||
467 | |||
468 | k.AngularVelocity = (new Vector3(0, 0, 1) * (Quaternion)k.Rotation) * (angle / (k.TimeMS / 1000)); | ||
469 | */ | ||
470 | k.TimeTotal = k.TimeMS; | ||
471 | |||
472 | m_frames.Add(k); | ||
473 | |||
474 | pos = (Vector3)k.Position; | ||
475 | rot = (Quaternion)k.Rotation; | ||
476 | } | ||
477 | |||
478 | m_basePosition = pos; | ||
479 | m_baseRotation = rot; | ||
480 | |||
481 | m_iterations++; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | public void OnTimer() | ||
486 | { | ||
487 | if (m_skipLoops > 0) | ||
488 | { | ||
489 | m_skipLoops--; | ||
490 | return; | ||
491 | } | ||
492 | |||
493 | if (m_timerStopped) // trap events still in air even after a timer.stop | ||
494 | return; | ||
495 | |||
496 | if (m_group == null) | ||
497 | return; | ||
498 | |||
499 | bool update = false; | ||
500 | |||
501 | if (m_selected) | ||
502 | { | ||
503 | if (m_group.RootPart.Velocity != Vector3.Zero) | ||
504 | { | ||
505 | m_group.RootPart.Velocity = Vector3.Zero; | ||
506 | m_group.SendGroupRootTerseUpdate(); | ||
507 | |||
508 | } | ||
509 | return; | ||
510 | } | ||
511 | |||
512 | if (m_isCrossing) | ||
513 | { | ||
514 | // if crossing and timer running then cross failed | ||
515 | // wait some time then | ||
516 | // retry to set the position that evtually caused the outbound | ||
517 | // if still outside region this will call startCrossing below | ||
518 | m_isCrossing = false; | ||
519 | m_group.AbsolutePosition = m_nextPosition; | ||
520 | if (!m_isCrossing) | ||
521 | { | ||
522 | StopTimer(); | ||
523 | StartTimer(); | ||
524 | } | ||
525 | return; | ||
526 | } | ||
527 | |||
528 | if (m_frames.Count == 0) | ||
529 | { | ||
530 | GetNextList(); | ||
531 | |||
532 | if (m_frames.Count == 0) | ||
533 | { | ||
534 | Stop(); | ||
535 | Scene scene = m_group.Scene; | ||
536 | |||
537 | IScriptModule[] scriptModules = scene.RequestModuleInterfaces<IScriptModule>(); | ||
538 | foreach (IScriptModule m in scriptModules) | ||
539 | { | ||
540 | if (m == null) | ||
541 | continue; | ||
542 | m.PostObjectEvent(m_group.RootPart.UUID, "moving_end", new object[0]); | ||
543 | } | ||
544 | |||
545 | return; | ||
546 | } | ||
547 | |||
548 | m_currentFrame = m_frames[0]; | ||
549 | m_currentFrame.TimeMS += (int)KeyframeTimer.timerInterval; | ||
550 | |||
551 | //force a update on a keyframe transition | ||
552 | update = true; | ||
553 | } | ||
554 | |||
555 | m_currentFrame.TimeMS -= (int)KeyframeTimer.timerInterval; | ||
556 | |||
557 | // Do the frame processing | ||
558 | double steps = (double)m_currentFrame.TimeMS / KeyframeTimer.timerInterval; | ||
559 | |||
560 | if (steps <= 0.0) | ||
561 | { | ||
562 | m_group.RootPart.Velocity = Vector3.Zero; | ||
563 | m_group.RootPart.AngularVelocity = Vector3.Zero; | ||
564 | |||
565 | m_nextPosition = (Vector3)m_currentFrame.Position; | ||
566 | m_group.AbsolutePosition = m_nextPosition; | ||
567 | |||
568 | // we are sending imediate updates, no doing force a extra terseUpdate | ||
569 | // m_group.UpdateGroupRotationR((Quaternion)m_currentFrame.Rotation); | ||
570 | |||
571 | m_group.RootPart.RotationOffset = (Quaternion)m_currentFrame.Rotation; | ||
572 | m_frames.RemoveAt(0); | ||
573 | if (m_frames.Count > 0) | ||
574 | m_currentFrame = m_frames[0]; | ||
575 | |||
576 | update = true; | ||
577 | } | ||
578 | else | ||
579 | { | ||
580 | float complete = ((float)m_currentFrame.TimeTotal - (float)m_currentFrame.TimeMS) / (float)m_currentFrame.TimeTotal; | ||
581 | |||
582 | Vector3 v = (Vector3)m_currentFrame.Position - m_group.AbsolutePosition; | ||
583 | Vector3 motionThisFrame = v / (float)steps; | ||
584 | v = v * 1000 / m_currentFrame.TimeMS; | ||
585 | |||
586 | if (Vector3.Mag(motionThisFrame) >= 0.05f) | ||
587 | { | ||
588 | // m_group.AbsolutePosition += motionThisFrame; | ||
589 | m_nextPosition = m_group.AbsolutePosition + motionThisFrame; | ||
590 | m_group.AbsolutePosition = m_nextPosition; | ||
591 | |||
592 | m_group.RootPart.Velocity = v; | ||
593 | update = true; | ||
594 | } | ||
595 | |||
596 | if ((Quaternion)m_currentFrame.Rotation != m_group.GroupRotation) | ||
597 | { | ||
598 | Quaternion current = m_group.GroupRotation; | ||
599 | |||
600 | Quaternion step = Quaternion.Slerp(m_currentFrame.StartRotation, (Quaternion)m_currentFrame.Rotation, complete); | ||
601 | step.Normalize(); | ||
602 | /* use simpler change detection | ||
603 | * float angle = 0; | ||
604 | |||
605 | float aa = current.X * current.X + current.Y * current.Y + current.Z * current.Z + current.W * current.W; | ||
606 | float bb = step.X * step.X + step.Y * step.Y + step.Z * step.Z + step.W * step.W; | ||
607 | float aa_bb = aa * bb; | ||
608 | |||
609 | if (aa_bb == 0) | ||
610 | { | ||
611 | angle = 0; | ||
612 | } | ||
613 | else | ||
614 | { | ||
615 | float ab = current.X * step.X + | ||
616 | current.Y * step.Y + | ||
617 | current.Z * step.Z + | ||
618 | current.W * step.W; | ||
619 | float q = (ab * ab) / aa_bb; | ||
620 | |||
621 | if (q > 1.0f) | ||
622 | { | ||
623 | angle = 0; | ||
624 | } | ||
625 | else | ||
626 | { | ||
627 | angle = (float)Math.Acos(2 * q - 1); | ||
628 | } | ||
629 | } | ||
630 | |||
631 | if (angle > 0.01f) | ||
632 | */ | ||
633 | if(Math.Abs(step.X - current.X) > 0.001f | ||
634 | || Math.Abs(step.Y - current.Y) > 0.001f | ||
635 | || Math.Abs(step.Z - current.Z) > 0.001f) | ||
636 | // assuming w is a dependente var | ||
637 | |||
638 | { | ||
639 | // m_group.UpdateGroupRotationR(step); | ||
640 | m_group.RootPart.RotationOffset = step; | ||
641 | |||
642 | //m_group.RootPart.UpdateAngularVelocity(m_currentFrame.AngularVelocity / 2); | ||
643 | update = true; | ||
644 | } | ||
645 | } | ||
646 | } | ||
647 | |||
648 | if (update) | ||
649 | { | ||
650 | m_group.SendGroupRootTerseUpdate(); | ||
651 | } | ||
652 | } | ||
653 | |||
654 | public Byte[] Serialize() | ||
655 | { | ||
656 | StopTimer(); | ||
657 | MemoryStream ms = new MemoryStream(); | ||
658 | |||
659 | BinaryFormatter fmt = new BinaryFormatter(); | ||
660 | SceneObjectGroup tmp = m_group; | ||
661 | m_group = null; | ||
662 | if (!m_selected && tmp != null) | ||
663 | m_serializedPosition = tmp.AbsolutePosition; | ||
664 | fmt.Serialize(ms, this); | ||
665 | m_group = tmp; | ||
666 | if (m_running && !m_waitingCrossing) | ||
667 | StartTimer(); | ||
668 | |||
669 | return ms.ToArray(); | ||
670 | } | ||
671 | |||
672 | public void StartCrossingCheck() | ||
673 | { | ||
674 | // timer will be restart by crossingFailure | ||
675 | // or never since crossing worked and this | ||
676 | // should be deleted | ||
677 | StopTimer(); | ||
678 | |||
679 | m_isCrossing = true; | ||
680 | m_waitingCrossing = true; | ||
681 | |||
682 | // to remove / retune to smoth crossings | ||
683 | if (m_group.RootPart.Velocity != Vector3.Zero) | ||
684 | { | ||
685 | m_group.RootPart.Velocity = Vector3.Zero; | ||
686 | m_group.SendGroupRootTerseUpdate(); | ||
687 | // m_group.RootPart.ScheduleTerseUpdate(); | ||
688 | } | ||
689 | } | ||
690 | |||
691 | public void CrossingFailure() | ||
692 | { | ||
693 | m_waitingCrossing = false; | ||
694 | |||
695 | if (m_group != null) | ||
696 | { | ||
697 | m_group.RootPart.Velocity = Vector3.Zero; | ||
698 | m_group.SendGroupRootTerseUpdate(); | ||
699 | // m_group.RootPart.ScheduleTerseUpdate(); | ||
700 | |||
701 | if (m_running) | ||
702 | { | ||
703 | StopTimer(); | ||
704 | m_skipLoops = 1200; // 60 seconds | ||
705 | StartTimer(); | ||
706 | } | ||
707 | } | ||
708 | } | ||
709 | } | ||
710 | } | ||