diff options
author | Kitto Flora | 2009-12-31 16:07:36 -0500 |
---|---|---|
committer | Kitto Flora | 2009-12-31 16:07:36 -0500 |
commit | 3f901d313bfd11070d5260f867c8a73c14f2d109 (patch) | |
tree | 20ecdfa6538c48ee23f9ad155579a102dfdf3898 | |
parent | Merge branch 'master' into careminster (diff) | |
download | opensim-SC-3f901d313bfd11070d5260f867c8a73c14f2d109.zip opensim-SC-3f901d313bfd11070d5260f867c8a73c14f2d109.tar.gz opensim-SC-3f901d313bfd11070d5260f867c8a73c14f2d109.tar.bz2 opensim-SC-3f901d313bfd11070d5260f867c8a73c14f2d109.tar.xz |
Vehicle Linear parameter adjustments
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs | 40 | ||||
-rw-r--r-- | OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs | 12 | ||||
-rw-r--r-- | OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs | 61 |
3 files changed, 75 insertions, 38 deletions
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs index 78b15be..ef2dccc 100644 --- a/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs +++ b/OpenSim/Region/Physics/ChOdePlugin/ODEDynamics.cs | |||
@@ -83,6 +83,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
83 | // private IntPtr m_jointGroup = IntPtr.Zero; | 83 | // private IntPtr m_jointGroup = IntPtr.Zero; |
84 | // private IntPtr m_aMotor = IntPtr.Zero; | 84 | // private IntPtr m_aMotor = IntPtr.Zero; |
85 | 85 | ||
86 | // Correction factors, to match Sl | ||
87 | private static float m_linearVelocityFactor = 0.9f; | ||
88 | private static float m_linearAttackFactor = 0.4f; | ||
89 | private static float m_linearDecayFactor = 0.5f; | ||
90 | private static float m_linearFrictionFactor = 1.2f; | ||
91 | |||
86 | 92 | ||
87 | // Vehicle properties | 93 | // Vehicle properties |
88 | private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind | 94 | private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind |
@@ -98,7 +104,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
98 | 104 | ||
99 | // Linear properties | 105 | // Linear properties |
100 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | 106 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time |
101 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | 107 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL, for max limiting |
102 | private Vector3 m_dir = Vector3.Zero; // velocity applied to body | 108 | private Vector3 m_dir = Vector3.Zero; // velocity applied to body |
103 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | 109 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; |
104 | private float m_linearMotorDecayTimescale = 0; | 110 | private float m_linearMotorDecayTimescale = 0; |
@@ -267,8 +273,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
267 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 273 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
268 | break; | 274 | break; |
269 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 275 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
270 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 276 | pValue *= m_linearVelocityFactor; |
271 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | 277 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, decayed by time |
278 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); // velocity requested by LSL, for max limiting | ||
272 | break; | 279 | break; |
273 | case Vehicle.LINEAR_MOTOR_OFFSET: | 280 | case Vehicle.LINEAR_MOTOR_OFFSET: |
274 | // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | 281 | // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -453,6 +460,17 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
453 | MoveAngular(pTimestep); | 460 | MoveAngular(pTimestep); |
454 | }// end Step | 461 | }// end Step |
455 | 462 | ||
463 | internal void Halt() | ||
464 | { // Kill all motions, when non-physical | ||
465 | m_linearMotorDirection = Vector3.Zero; | ||
466 | m_linearMotorDirectionLASTSET = Vector3.Zero; | ||
467 | m_dir = Vector3.Zero; | ||
468 | m_lastLinearVelocityVector = Vector3.Zero; | ||
469 | m_angularMotorDirection = Vector3.Zero; | ||
470 | m_angularMotorVelocity = Vector3.Zero; | ||
471 | m_lastAngularVelocity = Vector3.Zero; | ||
472 | } | ||
473 | |||
456 | private void MoveLinear(float pTimestep, OdeScene _pParentScene) | 474 | private void MoveLinear(float pTimestep, OdeScene _pParentScene) |
457 | { | 475 | { |
458 | if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant | 476 | if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant |
@@ -460,9 +478,15 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
460 | if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); | 478 | if(!d.BodyIsEnabled (Body)) d.BodyEnable (Body); |
461 | 479 | ||
462 | // add drive to body | 480 | // add drive to body |
463 | Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); | 481 | float linfactor = m_linearMotorTimescale/pTimestep; |
464 | m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? | 482 | // Linear accel |
465 | 483 | Vector3 addAmount1 = (m_linearMotorDirection/linfactor) * 0.8f; | |
484 | // Differential accel | ||
485 | Vector3 addAmount2 = ((m_linearMotorDirection - m_lastLinearVelocityVector)/linfactor) * 1.6f; | ||
486 | // SL correction | ||
487 | Vector3 addAmount = (addAmount1 + addAmount2) * m_linearAttackFactor; | ||
488 | m_lastLinearVelocityVector += addAmount; // lastLinearVelocityVector is the current body velocity vector | ||
489 | //if(frcount == 0) Console.WriteLine("AL {0} + AD {1} AS{2} V {3}", addAmount1, addAmount2, addAmount, m_lastLinearVelocityVector); | ||
466 | // This will work temporarily, but we really need to compare speed on an axis | 490 | // This will work temporarily, but we really need to compare speed on an axis |
467 | // KF: Limit body velocity to applied velocity? | 491 | // KF: Limit body velocity to applied velocity? |
468 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) | 492 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) |
@@ -475,7 +499,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
475 | // decay applied velocity | 499 | // decay applied velocity |
476 | Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); | 500 | Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); |
477 | //Console.WriteLine("decay: " + decayfraction); | 501 | //Console.WriteLine("decay: " + decayfraction); |
478 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; | 502 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction * m_linearDecayFactor; |
479 | //Console.WriteLine("actual: " + m_linearMotorDirection); | 503 | //Console.WriteLine("actual: " + m_linearMotorDirection); |
480 | } | 504 | } |
481 | else | 505 | else |
@@ -560,7 +584,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
560 | 584 | ||
561 | // apply friction | 585 | // apply friction |
562 | Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); | 586 | Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); |
563 | m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; | 587 | m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount * m_linearFrictionFactor; |
564 | } // end MoveLinear() | 588 | } // end MoveLinear() |
565 | 589 | ||
566 | private void MoveAngular(float pTimestep) | 590 | private void MoveAngular(float pTimestep) |
diff --git a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs index 0179240..6e6b44f 100644 --- a/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/ChOdePlugin/ODEPrim.cs | |||
@@ -2296,11 +2296,15 @@ Console.WriteLine(" JointCreateFixed"); | |||
2296 | public override bool IsPhysical | 2296 | public override bool IsPhysical |
2297 | { | 2297 | { |
2298 | get { return m_isphysical; } | 2298 | get { return m_isphysical; } |
2299 | set { | 2299 | set |
2300 | { | ||
2300 | m_isphysical = value; | 2301 | m_isphysical = value; |
2301 | if (!m_isphysical) // Zero the remembered last velocity | 2302 | if (!m_isphysical) |
2302 | m_lastVelocity = Vector3.Zero; | 2303 | { // Zero the remembered last velocity |
2303 | } | 2304 | m_lastVelocity = Vector3.Zero; |
2305 | if (m_vehicle.Type != Vehicle.TYPE_NONE) m_vehicle.Halt(); | ||
2306 | } | ||
2307 | } | ||
2304 | } | 2308 | } |
2305 | 2309 | ||
2306 | public void setPrimForRemoval() | 2310 | public void setPrimForRemoval() |
diff --git a/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs index f48649e..60786d4 100644 --- a/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/ChOdePlugin/OdePlugin.cs | |||
@@ -229,7 +229,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
229 | 229 | ||
230 | public int bodyFramesAutoDisable = 20; | 230 | public int bodyFramesAutoDisable = 20; |
231 | 231 | ||
232 | 232 | protected DateTime m_lastframe = DateTime.UtcNow; | |
233 | 233 | ||
234 | private float[] _watermap; | 234 | private float[] _watermap; |
235 | private bool m_filterCollisions = true; | 235 | private bool m_filterCollisions = true; |
@@ -2639,13 +2639,20 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2639 | { | 2639 | { |
2640 | if (framecount >= int.MaxValue) | 2640 | if (framecount >= int.MaxValue) |
2641 | framecount = 0; | 2641 | framecount = 0; |
2642 | |||
2643 | //if (m_worldOffset != Vector3.Zero) | 2642 | //if (m_worldOffset != Vector3.Zero) |
2644 | // return 0; | 2643 | // return 0; |
2645 | 2644 | ||
2646 | framecount++; | 2645 | framecount++; |
2647 | 2646 | ||
2648 | float fps = 0; | 2647 | DateTime now = DateTime.UtcNow; |
2648 | TimeSpan SinceLastFrame = now - m_lastframe; | ||
2649 | m_lastframe = now; | ||
2650 | float realtime = (float)SinceLastFrame.TotalSeconds; | ||
2651 | // Console.WriteLine("ts={0} rt={1}", timeStep, realtime); | ||
2652 | timeStep = realtime; | ||
2653 | |||
2654 | // float fps = 1.0f / realtime; | ||
2655 | float fps = 0.0f; // number of ODE steps in this Simulate step | ||
2649 | //m_log.Info(timeStep.ToString()); | 2656 | //m_log.Info(timeStep.ToString()); |
2650 | step_time += timeStep; | 2657 | step_time += timeStep; |
2651 | 2658 | ||
@@ -2691,11 +2698,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2691 | // Figure out the Frames Per Second we're going at. | 2698 | // Figure out the Frames Per Second we're going at. |
2692 | //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size | 2699 | //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size |
2693 | 2700 | ||
2694 | fps = (step_time / ODE_STEPSIZE) * 1000; | 2701 | // fps = (step_time / ODE_STEPSIZE) * 1000; |
2695 | // HACK: Using a time dilation of 1.0 to debug rubberbanding issues | 2702 | // HACK: Using a time dilation of 1.0 to debug rubberbanding issues |
2696 | //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f); | 2703 | //m_timeDilation = Math.Min((step_time / ODE_STEPSIZE) / (0.09375f / ODE_STEPSIZE), 1.0f); |
2697 | 2704 | ||
2698 | step_time = 0.09375f; | 2705 | // step_time = 0.09375f; |
2699 | 2706 | ||
2700 | while (step_time > 0.0f) | 2707 | while (step_time > 0.0f) |
2701 | { | 2708 | { |
@@ -2716,7 +2723,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2716 | foreach (OdeCharacter character in _taintedActors) | 2723 | foreach (OdeCharacter character in _taintedActors) |
2717 | { | 2724 | { |
2718 | 2725 | ||
2719 | character.ProcessTaints(timeStep); | 2726 | character.ProcessTaints(ODE_STEPSIZE); |
2720 | 2727 | ||
2721 | processedtaints = true; | 2728 | processedtaints = true; |
2722 | //character.m_collisionscore = 0; | 2729 | //character.m_collisionscore = 0; |
@@ -2725,7 +2732,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2725 | if (processedtaints) | 2732 | if (processedtaints) |
2726 | _taintedActors.Clear(); | 2733 | _taintedActors.Clear(); |
2727 | } | 2734 | } |
2728 | } | 2735 | } // end lock _taintedActors |
2729 | 2736 | ||
2730 | // Modify other objects in the scene. | 2737 | // Modify other objects in the scene. |
2731 | processedtaints = false; | 2738 | processedtaints = false; |
@@ -2742,7 +2749,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2742 | else | 2749 | else |
2743 | { | 2750 | { |
2744 | //Console.WriteLine("Simulate calls ProcessTaints"); | 2751 | //Console.WriteLine("Simulate calls ProcessTaints"); |
2745 | prim.ProcessTaints(timeStep); | 2752 | prim.ProcessTaints(ODE_STEPSIZE); |
2746 | } | 2753 | } |
2747 | processedtaints = true; | 2754 | processedtaints = true; |
2748 | prim.m_collisionscore = 0; | 2755 | prim.m_collisionscore = 0; |
@@ -2767,7 +2774,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2767 | foreach (PhysicsJoint joint in pendingJoints) | 2774 | foreach (PhysicsJoint joint in pendingJoints) |
2768 | { | 2775 | { |
2769 | //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams); | 2776 | //DoJointErrorMessage(joint, "taint: time to create joint with parms: " + joint.RawParams); |
2770 | string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); | 2777 | string[] jointParams = joint.RawParams.Split(" ".ToCharArray(), |
2778 | System.StringSplitOptions.RemoveEmptyEntries); | ||
2771 | List<IntPtr> jointBodies = new List<IntPtr>(); | 2779 | List<IntPtr> jointBodies = new List<IntPtr>(); |
2772 | bool allJointBodiesAreReady = true; | 2780 | bool allJointBodiesAreReady = true; |
2773 | foreach (string jointParam in jointParams) | 2781 | foreach (string jointParam in jointParams) |
@@ -2934,13 +2942,13 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2934 | //DoJointErrorMessage(successfullyProcessedJoint, "done"); | 2942 | //DoJointErrorMessage(successfullyProcessedJoint, "done"); |
2935 | } | 2943 | } |
2936 | } | 2944 | } |
2937 | } | 2945 | } // end SupportsNINJAJoints |
2938 | 2946 | ||
2939 | if (processedtaints) | 2947 | if (processedtaints) |
2940 | //Console.WriteLine("Simulate calls Clear of _taintedPrim list"); | 2948 | //Console.WriteLine("Simulate calls Clear of _taintedPrim list"); |
2941 | _taintedPrimH.Clear(); | 2949 | _taintedPrimH.Clear(); // ??? if this only ??? |
2942 | _taintedPrimL.Clear(); | 2950 | _taintedPrimL.Clear(); |
2943 | } | 2951 | } // end lock _taintedPrimLock |
2944 | 2952 | ||
2945 | // Move characters | 2953 | // Move characters |
2946 | lock (_characters) | 2954 | lock (_characters) |
@@ -2949,7 +2957,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2949 | foreach (OdeCharacter actor in _characters) | 2957 | foreach (OdeCharacter actor in _characters) |
2950 | { | 2958 | { |
2951 | if (actor != null) | 2959 | if (actor != null) |
2952 | actor.Move(timeStep, defects); | 2960 | actor.Move(ODE_STEPSIZE, defects); |
2953 | } | 2961 | } |
2954 | if (0 != defects.Count) | 2962 | if (0 != defects.Count) |
2955 | { | 2963 | { |
@@ -2958,7 +2966,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2958 | RemoveCharacter(defect); | 2966 | RemoveCharacter(defect); |
2959 | } | 2967 | } |
2960 | } | 2968 | } |
2961 | } | 2969 | } // end lock _characters |
2962 | 2970 | ||
2963 | // Move other active objects | 2971 | // Move other active objects |
2964 | lock (_activeprims) | 2972 | lock (_activeprims) |
@@ -2966,9 +2974,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2966 | foreach (OdePrim prim in _activeprims) | 2974 | foreach (OdePrim prim in _activeprims) |
2967 | { | 2975 | { |
2968 | prim.m_collisionscore = 0; | 2976 | prim.m_collisionscore = 0; |
2969 | prim.Move(timeStep); | 2977 | prim.Move(ODE_STEPSIZE); |
2970 | } | 2978 | } |
2971 | } | 2979 | } // end lock _activeprims |
2972 | 2980 | ||
2973 | //if ((framecount % m_randomizeWater) == 0) | 2981 | //if ((framecount % m_randomizeWater) == 0) |
2974 | // randomizeWater(waterlevel); | 2982 | // randomizeWater(waterlevel); |
@@ -2976,7 +2984,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2976 | //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests(); | 2984 | //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests(); |
2977 | m_rayCastManager.ProcessQueuedRequests(); | 2985 | m_rayCastManager.ProcessQueuedRequests(); |
2978 | 2986 | ||
2979 | collision_optimized(timeStep); | 2987 | collision_optimized(ODE_STEPSIZE); |
2980 | 2988 | ||
2981 | lock (_collisionEventPrim) | 2989 | lock (_collisionEventPrim) |
2982 | { | 2990 | { |
@@ -2998,7 +3006,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
2998 | break; | 3006 | break; |
2999 | } | 3007 | } |
3000 | } | 3008 | } |
3001 | } | 3009 | } // end lock _collisionEventPrim |
3002 | 3010 | ||
3003 | //if (m_global_contactcount > 5) | 3011 | //if (m_global_contactcount > 5) |
3004 | //{ | 3012 | //{ |
@@ -3009,8 +3017,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3009 | 3017 | ||
3010 | d.WorldQuickStep(world, ODE_STEPSIZE); | 3018 | d.WorldQuickStep(world, ODE_STEPSIZE); |
3011 | d.JointGroupEmpty(contactgroup); | 3019 | d.JointGroupEmpty(contactgroup); |
3020 | fps++; | ||
3012 | //ode.dunlock(world); | 3021 | //ode.dunlock(world); |
3013 | } | 3022 | } // end try |
3014 | catch (Exception e) | 3023 | catch (Exception e) |
3015 | { | 3024 | { |
3016 | m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e); | 3025 | m_log.ErrorFormat("[PHYSICS]: {0}, {1}, {2}", e.Message, e.TargetSite, e); |
@@ -3025,7 +3034,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3025 | //fps = 0; | 3034 | //fps = 0; |
3026 | //} | 3035 | //} |
3027 | //} | 3036 | //} |
3028 | } | 3037 | } // end while (step_time > 0.0f) |
3029 | 3038 | ||
3030 | lock (_characters) | 3039 | lock (_characters) |
3031 | { | 3040 | { |
@@ -3090,7 +3099,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3090 | } | 3099 | } |
3091 | } | 3100 | } |
3092 | } | 3101 | } |
3093 | } | 3102 | } // end lock _activeprims |
3094 | 3103 | ||
3095 | //DumpJointInfo(); | 3104 | //DumpJointInfo(); |
3096 | 3105 | ||
@@ -3111,10 +3120,10 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
3111 | } | 3120 | } |
3112 | d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); | 3121 | d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); |
3113 | } | 3122 | } |
3114 | } | 3123 | } // end lock OdeLock |
3115 | 3124 | ||
3116 | return fps; | 3125 | return fps * 1000.0f; //NB This is a FRAME COUNT, not a time! AND is divide by 1000 in SimStatusReporter! |
3117 | } | 3126 | } // end Simulate |
3118 | 3127 | ||
3119 | public override void GetResults() | 3128 | public override void GetResults() |
3120 | { | 3129 | { |