diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs | 315 |
1 files changed, 89 insertions, 226 deletions
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs index 2ba5940..f8d7195 100644 --- a/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/UbitOdePlugin/OdeScene.cs | |||
@@ -178,7 +178,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
178 | public changes what; | 178 | public changes what; |
179 | public Object arg; | 179 | public Object arg; |
180 | } | 180 | } |
181 | 181 | ||
182 | |||
183 | |||
182 | public class OdeScene : PhysicsScene | 184 | public class OdeScene : PhysicsScene |
183 | { | 185 | { |
184 | private readonly ILog m_log; | 186 | private readonly ILog m_log; |
@@ -301,6 +303,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
301 | public IntPtr StaticSpace; // space for the static things around | 303 | public IntPtr StaticSpace; // space for the static things around |
302 | public IntPtr GroundSpace; // space for ground | 304 | public IntPtr GroundSpace; // space for ground |
303 | 305 | ||
306 | public IntPtr SharedRay; | ||
307 | |||
304 | // some speedup variables | 308 | // some speedup variables |
305 | private int spaceGridMaxX; | 309 | private int spaceGridMaxX; |
306 | private int spaceGridMaxY; | 310 | private int spaceGridMaxY; |
@@ -428,6 +432,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
428 | contactgroup = d.JointGroupCreate(0); | 432 | contactgroup = d.JointGroupCreate(0); |
429 | //contactgroup | 433 | //contactgroup |
430 | 434 | ||
435 | SharedRay = d.CreateRay(TopSpace, 1.0f); | ||
436 | |||
431 | d.WorldSetAutoDisableFlag(world, false); | 437 | d.WorldSetAutoDisableFlag(world, false); |
432 | } | 438 | } |
433 | } | 439 | } |
@@ -733,35 +739,35 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
733 | 739 | ||
734 | if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) | 740 | if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) |
735 | return; | 741 | return; |
736 | /* | 742 | /* |
737 | // debug | 743 | // debug |
738 | PhysicsActor dp2; | 744 | PhysicsActor dp2; |
739 | if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass) | 745 | if (d.GeomGetClass(g1) == d.GeomClassID.HeightfieldClass) |
740 | { | 746 | { |
741 | d.AABB aabb; | 747 | d.AABB aabb; |
742 | d.GeomGetAABB(g2, out aabb); | 748 | d.GeomGetAABB(g2, out aabb); |
743 | float x = aabb.MaxX - aabb.MinX; | 749 | float x = aabb.MaxX - aabb.MinX; |
744 | float y = aabb.MaxY - aabb.MinY; | 750 | float y = aabb.MaxY - aabb.MinY; |
745 | float z = aabb.MaxZ - aabb.MinZ; | 751 | float z = aabb.MaxZ - aabb.MinZ; |
746 | if (x > 60.0f || y > 60.0f || z > 60.0f) | 752 | if (x > 60.0f || y > 60.0f || z > 60.0f) |
747 | { | 753 | { |
748 | if (!actor_name_map.TryGetValue(g2, out dp2)) | 754 | if (!actor_name_map.TryGetValue(g2, out dp2)) |
749 | m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2"); | 755 | m_log.WarnFormat("[PHYSICS]: failed actor mapping for geom 2"); |
750 | else | 756 | else |
751 | m_log.WarnFormat("[PHYSICS]: land versus large prim geo {0},size {1}, AABBsize <{2},{3},{4}>, at {5} ori {6},({7})", | 757 | m_log.WarnFormat("[PHYSICS]: land versus large prim geo {0},size {1}, AABBsize <{2},{3},{4}>, at {5} ori {6},({7})", |
752 | dp2.Name, dp2.Size, x, y, z, | 758 | dp2.Name, dp2.Size, x, y, z, |
753 | dp2.Position.ToString(), | 759 | dp2.Position.ToString(), |
754 | dp2.Orientation.ToString(), | 760 | dp2.Orientation.ToString(), |
755 | dp2.Orientation.Length()); | 761 | dp2.Orientation.Length()); |
756 | return; | 762 | return; |
757 | } | 763 | } |
758 | } | 764 | } |
759 | // | 765 | // |
760 | */ | 766 | */ |
761 | 767 | ||
762 | 768 | ||
763 | if(d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc || | 769 | if (d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc || |
764 | d.GeomGetCategoryBits(g1) == (uint)CollisionCategories.VolumeDtc) | 770 | d.GeomGetCategoryBits(g2) == (uint)CollisionCategories.VolumeDtc) |
765 | { | 771 | { |
766 | int cflags; | 772 | int cflags; |
767 | unchecked | 773 | unchecked |
@@ -776,7 +782,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
776 | catch (SEHException) | 782 | catch (SEHException) |
777 | { | 783 | { |
778 | m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim."); | 784 | m_log.Error("[PHYSICS]: The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim."); |
779 | // ode.drelease(world); | 785 | // ode.drelease(world); |
780 | base.TriggerPhysicsBasedRestart(); | 786 | base.TriggerPhysicsBasedRestart(); |
781 | } | 787 | } |
782 | catch (Exception e) | 788 | catch (Exception e) |
@@ -816,26 +822,25 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
816 | 822 | ||
817 | // get first contact | 823 | // get first contact |
818 | d.ContactGeom curContact = new d.ContactGeom(); | 824 | d.ContactGeom curContact = new d.ContactGeom(); |
825 | |||
819 | if (!GetCurContactGeom(0, ref curContact)) | 826 | if (!GetCurContactGeom(0, ref curContact)) |
820 | return; | 827 | return; |
821 | // for now it's the one with max depth | 828 | |
822 | ContactPoint maxDepthContact = new ContactPoint( | ||
823 | new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), | ||
824 | new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), | ||
825 | curContact.depth | ||
826 | ); | ||
827 | // do volume detection case | 829 | // do volume detection case |
828 | if ( | 830 | if ((p1.IsVolumeDtc || p2.IsVolumeDtc)) |
829 | (p1.IsVolumeDtc || p2.IsVolumeDtc)) | ||
830 | { | 831 | { |
832 | ContactPoint maxDepthContact = new ContactPoint( | ||
833 | new Vector3(curContact.pos.X, curContact.pos.Y, curContact.pos.Z), | ||
834 | new Vector3(curContact.normal.X, curContact.normal.Y, curContact.normal.Z), | ||
835 | curContact.depth, false | ||
836 | ); | ||
837 | |||
831 | collision_accounting_events(p1, p2, maxDepthContact); | 838 | collision_accounting_events(p1, p2, maxDepthContact); |
832 | return; | 839 | return; |
833 | } | 840 | } |
834 | 841 | ||
835 | // big messy collision analises | 842 | // big messy collision analises |
836 | 843 | ||
837 | Vector3 normoverride = Vector3.Zero; //damm c# | ||
838 | |||
839 | float mu = 0; | 844 | float mu = 0; |
840 | float bounce = 0; | 845 | float bounce = 0; |
841 | float cfm = 0.0001f; | 846 | float cfm = 0.0001f; |
@@ -846,36 +851,15 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
846 | ContactData contactdata1 = new ContactData(0, 0, false); | 851 | ContactData contactdata1 = new ContactData(0, 0, false); |
847 | ContactData contactdata2 = new ContactData(0, 0, false); | 852 | ContactData contactdata2 = new ContactData(0, 0, false); |
848 | 853 | ||
849 | bool dop1foot = false; | 854 | bool dop1ava = false; |
850 | bool dop2foot = false; | 855 | bool dop2ava = false; |
851 | bool ignore = false; | 856 | bool ignore = false; |
852 | bool AvanormOverride = false; | ||
853 | 857 | ||
854 | switch (p1.PhysicsActorType) | 858 | switch (p1.PhysicsActorType) |
855 | { | 859 | { |
856 | case (int)ActorTypes.Agent: | 860 | case (int)ActorTypes.Agent: |
857 | { | 861 | { |
858 | dop1foot = true; | 862 | dop1ava = true; |
859 | |||
860 | AvanormOverride = true; | ||
861 | Vector3 tmp = p2.Position - p1.Position; | ||
862 | normoverride = p2.Velocity - p1.Velocity; | ||
863 | mu = normoverride.LengthSquared(); | ||
864 | |||
865 | if (mu > 1e-6) | ||
866 | { | ||
867 | mu = 1.0f / (float)Math.Sqrt(mu); | ||
868 | normoverride *= mu; | ||
869 | mu = Vector3.Dot(tmp, normoverride); | ||
870 | if (mu > 0) | ||
871 | normoverride *= -1; | ||
872 | } | ||
873 | else | ||
874 | { | ||
875 | tmp.Normalize(); | ||
876 | normoverride = -tmp; | ||
877 | } | ||
878 | |||
879 | switch (p2.PhysicsActorType) | 863 | switch (p2.PhysicsActorType) |
880 | { | 864 | { |
881 | case (int)ActorTypes.Agent: | 865 | case (int)ActorTypes.Agent: |
@@ -886,7 +870,6 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
886 | case (int)ActorTypes.Prim: | 870 | case (int)ActorTypes.Prim: |
887 | if (p2.Velocity.LengthSquared() > 0.0f) | 871 | if (p2.Velocity.LengthSquared() > 0.0f) |
888 | p2.CollidingObj = true; | 872 | p2.CollidingObj = true; |
889 | dop1foot = true; | ||
890 | break; | 873 | break; |
891 | 874 | ||
892 | default: | 875 | default: |
@@ -901,33 +884,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
901 | { | 884 | { |
902 | case (int)ActorTypes.Agent: | 885 | case (int)ActorTypes.Agent: |
903 | 886 | ||
887 | dop2ava = true; | ||
904 | 888 | ||
905 | dop2foot = true; | ||
906 | |||
907 | AvanormOverride = true; | ||
908 | |||
909 | Vector3 tmp = p2.Position - p1.Position; | ||
910 | normoverride = p2.Velocity - p1.Velocity; | ||
911 | mu = normoverride.LengthSquared(); | ||
912 | if (mu > 1e-6) | ||
913 | { | ||
914 | mu = 1.0f / (float)Math.Sqrt(mu); | ||
915 | normoverride *= mu; | ||
916 | mu = Vector3.Dot(tmp, normoverride); | ||
917 | if (mu > 0) | ||
918 | normoverride *= -1; | ||
919 | } | ||
920 | else | ||
921 | { | ||
922 | tmp.Normalize(); | ||
923 | normoverride = -tmp; | ||
924 | } | ||
925 | |||
926 | bounce = 0; | ||
927 | mu = 0; | ||
928 | cfm = 0.0001f; | ||
929 | |||
930 | dop2foot = true; | ||
931 | if (p1.Velocity.LengthSquared() > 0.0f) | 889 | if (p1.Velocity.LengthSquared() > 0.0f) |
932 | p1.CollidingObj = true; | 890 | p1.CollidingObj = true; |
933 | break; | 891 | break; |
@@ -1032,170 +990,78 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1032 | default: | 990 | default: |
1033 | break; | 991 | break; |
1034 | } | 992 | } |
993 | |||
1035 | if (ignore) | 994 | if (ignore) |
1036 | return; | 995 | return; |
1037 | 996 | ||
1038 | IntPtr Joint; | ||
1039 | 997 | ||
1040 | bool FeetCollision = false; | 998 | d.ContactGeom maxContact = curContact; |
999 | // if (IgnoreNegSides && curContact.side1 < 0) | ||
1000 | // maxContact.depth = float.MinValue; | ||
1001 | |||
1002 | d.ContactGeom minContact = curContact; | ||
1003 | // if (IgnoreNegSides && curContact.side1 < 0) | ||
1004 | // minContact.depth = float.MaxValue; | ||
1041 | 1005 | ||
1042 | int i = 0; | 1006 | IntPtr Joint; |
1007 | bool FeetCollision = false; | ||
1043 | int ncontacts = 0; | 1008 | int ncontacts = 0; |
1044 | while(true) | ||
1045 | { | ||
1046 | 1009 | ||
1047 | if (IgnoreNegSides && curContact.side1 < 0) | ||
1048 | { | ||
1049 | if (++i >= count) | ||
1050 | break; | ||
1051 | 1010 | ||
1052 | if (!GetCurContactGeom(i, ref curContact)) | 1011 | int i = 0; |
1053 | break; | ||
1054 | } | ||
1055 | else | ||
1056 | 1012 | ||
1013 | while (true) | ||
1057 | { | 1014 | { |
1058 | if(dop1foot) | 1015 | if (m_global_contactcount >= maxContactsbeforedeath) |
1016 | break; | ||
1017 | |||
1018 | // if (!(IgnoreNegSides && curContact.side1 < 0)) | ||
1059 | { | 1019 | { |
1060 | if (!(((OdeCharacter)p1).Collide(g1, false, ref curContact, ref FeetCollision))) | 1020 | bool noskip = true; |
1021 | if (dop1ava) | ||
1061 | { | 1022 | { |
1062 | if (++i >= count) | 1023 | if (!(((OdeCharacter)p1).Collide(g1,false, ref curContact, ref FeetCollision))) |
1063 | break; | 1024 | |
1064 | else | 1025 | noskip = false; |
1065 | continue; | ||
1066 | } | 1026 | } |
1067 | } | 1027 | else if (dop2ava) |
1068 | else if(dop2foot) | ||
1069 | { | ||
1070 | if (!(((OdeCharacter)p2).Collide(g2, true, ref curContact, ref FeetCollision))) | ||
1071 | { | 1028 | { |
1072 | if (++i >= count) | 1029 | if (!(((OdeCharacter)p2).Collide(g2,true, ref curContact, ref FeetCollision))) |
1073 | break; | 1030 | noskip = false; |
1074 | else | ||
1075 | continue; | ||
1076 | } | 1031 | } |
1077 | } | ||
1078 | 1032 | ||
1079 | /* | 1033 | if (noskip) |
1080 | if (AvanormOverride) | ||
1081 | { | ||
1082 | if (curContact.depth > 0.3f) | ||
1083 | { | 1034 | { |
1084 | if (dop1foot && (p1.Position.Z - curContact.pos.Z) > (p1.Size.Z - avCapRadius) * 0.5f) | 1035 | m_global_contactcount++; |
1085 | p1.IsColliding = true; | 1036 | ncontacts++; |
1086 | if (dop2foot && (p2.Position.Z - curContact.pos.Z) > (p2.Size.Z - avCapRadius) * 0.5f) | ||
1087 | p2.IsColliding = true; | ||
1088 | curContact.normal.X = normoverride.X; | ||
1089 | curContact.normal.Y = normoverride.Y; | ||
1090 | curContact.normal.Z = normoverride.Z; | ||
1091 | } | ||
1092 | 1037 | ||
1093 | else | 1038 | Joint = CreateContacJoint(ref curContact, mu, bounce, cfm, erpscale, dscale); |
1094 | { | 1039 | d.JointAttach(Joint, b1, b2); |
1095 | if (dop1foot) | ||
1096 | { | ||
1097 | float sz = p1.Size.Z; | ||
1098 | Vector3 vtmp = p1.Position; | ||
1099 | float ppos = curContact.pos.Z - vtmp.Z + (sz - avCapRadius) * 0.5f; | ||
1100 | if (ppos > 0f) | ||
1101 | { | ||
1102 | if (!p1.Flying) | ||
1103 | { | ||
1104 | d.AABB aabb; | ||
1105 | d.GeomGetAABB(g2, out aabb); | ||
1106 | float tmp = vtmp.Z - sz * .18f; | ||
1107 | |||
1108 | if (aabb.MaxZ < tmp) | ||
1109 | { | ||
1110 | vtmp.X = curContact.pos.X - vtmp.X; | ||
1111 | vtmp.Y = curContact.pos.Y - vtmp.Y; | ||
1112 | vtmp.Z = -0.2f; | ||
1113 | vtmp.Normalize(); | ||
1114 | curContact.normal.X = vtmp.X; | ||
1115 | curContact.normal.Y = vtmp.Y; | ||
1116 | curContact.normal.Z = vtmp.Z; | ||
1117 | } | ||
1118 | } | ||
1119 | } | ||
1120 | else | ||
1121 | p1.IsColliding = true; | ||
1122 | 1040 | ||
1123 | } | 1041 | if (curContact.depth > maxContact.depth) |
1042 | maxContact = curContact; | ||
1124 | 1043 | ||
1125 | if (dop2foot) | 1044 | if (curContact.depth < minContact.depth) |
1126 | { | 1045 | minContact = curContact; |
1127 | float sz = p2.Size.Z; | ||
1128 | Vector3 vtmp = p2.Position; | ||
1129 | vtmp.Z -= sz * 0.5f; | ||
1130 | vtmp.Z += 0.5f; | ||
1131 | float ppos = vtmp.Z - curContact.pos.Z; | ||
1132 | if (ppos > 0f) | ||
1133 | { | ||
1134 | if (!p2.Flying) | ||
1135 | { | ||
1136 | float tmp = vtmp.Z - sz * .18f; | ||
1137 | vtmp.X = curContact.pos.X - vtmp.X; | ||
1138 | vtmp.Y = curContact.pos.Y - vtmp.Y; | ||
1139 | vtmp.Z = curContact.pos.Z - vtmp.Z; | ||
1140 | vtmp.Normalize(); | ||
1141 | curContact.normal.X = vtmp.X; | ||
1142 | curContact.normal.Y = vtmp.Y; | ||
1143 | curContact.normal.Z = vtmp.Z; | ||
1144 | } | ||
1145 | } | ||
1146 | // else | ||
1147 | p2.IsColliding = true; | ||
1148 | |||
1149 | } | ||
1150 | } | 1046 | } |
1151 | } | 1047 | } |
1152 | */ | ||
1153 | ncontacts++; | ||
1154 | Joint = CreateContacJoint(ref curContact, mu, bounce, cfm, erpscale, dscale); | ||
1155 | d.JointAttach(Joint, b1, b2); | ||
1156 | |||
1157 | if (++m_global_contactcount >= maxContactsbeforedeath) | ||
1158 | break; | ||
1159 | 1048 | ||
1160 | if (++i >= count) | 1049 | if (++i >= count) |
1161 | break; | 1050 | break; |
1162 | 1051 | ||
1163 | if (!GetCurContactGeom(i, ref curContact)) | 1052 | if (!GetCurContactGeom(i, ref curContact)) |
1164 | break; | 1053 | break; |
1165 | |||
1166 | if (curContact.depth > maxDepthContact.PenetrationDepth) | ||
1167 | { | ||
1168 | maxDepthContact.Position.X = curContact.pos.X; | ||
1169 | maxDepthContact.Position.Y = curContact.pos.Y; | ||
1170 | maxDepthContact.Position.Z = curContact.pos.Z; | ||
1171 | maxDepthContact.SurfaceNormal.X = curContact.normal.X; | ||
1172 | maxDepthContact.SurfaceNormal.Y = curContact.normal.Y; | ||
1173 | maxDepthContact.SurfaceNormal.Z = curContact.normal.Z; | ||
1174 | maxDepthContact.PenetrationDepth = curContact.depth; | ||
1175 | } | ||
1176 | } | 1054 | } |
1177 | } | ||
1178 | 1055 | ||
1179 | if (ncontacts > 0) | 1056 | if (ncontacts > 0) |
1180 | { | 1057 | { |
1181 | maxDepthContact.CharacterFeet = FeetCollision; | 1058 | ContactPoint maxDepthContact = new ContactPoint( |
1059 | new Vector3(maxContact.pos.X, maxContact.pos.Y, maxContact.pos.Z), | ||
1060 | new Vector3(minContact.normal.X, minContact.normal.Y, minContact.normal.Z), | ||
1061 | maxContact.depth, FeetCollision | ||
1062 | ); | ||
1182 | collision_accounting_events(p1, p2, maxDepthContact); | 1063 | collision_accounting_events(p1, p2, maxDepthContact); |
1183 | } | 1064 | } |
1184 | /* | ||
1185 | if (notskipedcount > geomContactPointsStartthrottle) | ||
1186 | { | ||
1187 | // If there are more then 3 contact points, it's likely | ||
1188 | // that we've got a pile of objects, so ... | ||
1189 | // We don't want to send out hundreds of terse updates over and over again | ||
1190 | // so lets throttle them and send them again after it's somewhat sorted out. | ||
1191 | this needs checking so out for now | ||
1192 | if (b1 != IntPtr.Zero) | ||
1193 | p1.ThrottleUpdates = true; | ||
1194 | if (b2 != IntPtr.Zero) | ||
1195 | p2.ThrottleUpdates = true; | ||
1196 | |||
1197 | } | ||
1198 | */ | ||
1199 | } | 1065 | } |
1200 | 1066 | ||
1201 | private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) | 1067 | private void collision_accounting_events(PhysicsActor p1, PhysicsActor p2, ContactPoint contact) |
@@ -1286,10 +1152,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1286 | // chr.CollidingGround = false; not done here | 1152 | // chr.CollidingGround = false; not done here |
1287 | chr.CollidingObj = false; | 1153 | chr.CollidingObj = false; |
1288 | // do colisions with static space | 1154 | // do colisions with static space |
1289 | d.SpaceCollide2(StaticSpace, chr.topbox, IntPtr.Zero, nearCallback); | 1155 | d.SpaceCollide2(chr.collider, StaticSpace, IntPtr.Zero, nearCallback); |
1290 | d.SpaceCollide2(StaticSpace, chr.midbox, IntPtr.Zero, nearCallback); | ||
1291 | d.SpaceCollide2(StaticSpace, chr.feetbox, IntPtr.Zero, nearCallback); | ||
1292 | d.SpaceCollide2(StaticSpace, chr.bonebox, IntPtr.Zero, nearCallback); | ||
1293 | 1156 | ||
1294 | // chars with chars | 1157 | // chars with chars |
1295 | d.SpaceCollide(CharsSpace, IntPtr.Zero, nearCallback); | 1158 | d.SpaceCollide(CharsSpace, IntPtr.Zero, nearCallback); |
@@ -1346,7 +1209,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1346 | // and with chars | 1209 | // and with chars |
1347 | try | 1210 | try |
1348 | { | 1211 | { |
1349 | d.SpaceCollide2(ActiveSpace, CharsSpace,IntPtr.Zero, nearCallback); | 1212 | d.SpaceCollide2(CharsSpace,ActiveSpace, IntPtr.Zero, nearCallback); |
1350 | } | 1213 | } |
1351 | catch (AccessViolationException) | 1214 | catch (AccessViolationException) |
1352 | { | 1215 | { |
@@ -1837,7 +1700,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1837 | foreach (OdeCharacter actor in _characters) | 1700 | foreach (OdeCharacter actor in _characters) |
1838 | { | 1701 | { |
1839 | if (actor != null) | 1702 | if (actor != null) |
1840 | actor.Move(ODE_STEPSIZE, defects); | 1703 | actor.Move(defects); |
1841 | } | 1704 | } |
1842 | if (defects.Count != 0) | 1705 | if (defects.Count != 0) |
1843 | { | 1706 | { |