Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
ComponentPilot.cs
浏览该文件的文档.
1using Engine;
4
5namespace Game {
8
10
12
14
15 public Random m_random = new();
16
18
20
22
24
25 public float m_jumpOrder;
26
27 public double m_nextUpdateTime;
28
29 public double m_lastStuckCheckTime;
30
31 public int m_stuckCount;
32
33 public double? m_aboveBelowTime;
34
36
37 public DynamicArray<ComponentBody> m_nearbyBodies = [];
38
40
41 public static bool DrawPilotDestination;
42
43 public int m_maxFallHeight = 5;
44
45 public int m_maxFallHeightRisk = 7;
46
47 public Vector3? Destination { get; set; }
48
49 public float Speed { get; set; }
50
51 public float Range { get; set; }
52
53 public bool IgnoreHeightDifference { get; set; }
54
55 public bool RaycastDestination { get; set; }
56
57 public bool TakeRisks { get; set; }
58
59 public ComponentBody DoNotAvoidBody { get; set; }
60
61 public bool IsStuck { get; set; }
62
64
65 public virtual void SetDestination(Vector3? destination,
66 float speed,
67 float range,
68 bool ignoreHeightDifference,
69 bool raycastDestination,
70 bool takeRisks,
71 ComponentBody doNotAvoidBody) {
72 bool flag = true;
73 if (Destination.HasValue
74 && destination.HasValue) {
75 Vector3 v = Vector3.Normalize(Destination.Value - m_componentCreature.ComponentBody.Position);
76 if (Vector3.Dot(Vector3.Normalize(destination.Value - m_componentCreature.ComponentBody.Position), v) > 0.5f) {
77 flag = false;
78 }
79 }
80 if (flag) {
81 IsStuck = false;
83 m_aboveBelowTime = null;
84 }
85 Destination = destination;
86 Speed = speed;
87 Range = range;
88 IgnoreHeightDifference = ignoreHeightDifference;
89 RaycastDestination = raycastDestination;
90 TakeRisks = takeRisks;
91 DoNotAvoidBody = doNotAvoidBody;
92 }
93
94 public virtual void Stop() {
96 null,
97 0f,
98 0f,
99 false,
100 false,
101 false,
102 null
103 );
104 }
105
106 public virtual void Update(float dt) {
107 if (m_subsystemTime.GameTime >= m_nextUpdateTime) {
108 m_nextUpdateTime = m_subsystemTime.GameTime + m_random.Float(0.09f, 0.11f);
109 m_walkOrder = null;
110 m_flyOrder = null;
111 m_swimOrder = null;
113 m_jumpOrder = 0f;
114 if (Destination.HasValue) {
115 Vector3 position = m_componentCreature.ComponentBody.Position;
116 Vector3 forward = m_componentCreature.ComponentBody.Matrix.Forward;
117 Vector3 v = AvoidNearestBody(position, Destination.Value);
118 Vector3 vector = v - position;
119 float num = vector.LengthSquared();
120 Vector2 vector2 = new Vector2(v.X, v.Z) - new Vector2(position.X, position.Z);
121 float num2 = vector2.LengthSquared();
122 float x = Vector2.Angle(forward.XZ, vector.XZ);
123 float num3 = (m_componentCreature.ComponentBody.CollisionVelocityChange * new Vector3(1f, 0f, 1f)).LengthSquared() > 0f
124 && m_componentCreature.ComponentBody.StandingOnValue.HasValue
125 ? 0.15f
126 : 0.4f;
127 if (m_subsystemTime.GameTime >= m_lastStuckCheckTime + num3
128 || !m_lastStuckCheckPosition.HasValue) {
130 if (MathF.Abs(x) > MathUtils.DegToRad(20f)
131 || !m_lastStuckCheckPosition.HasValue
132 || Vector3.Dot(position - m_lastStuckCheckPosition.Value, Vector3.Normalize(vector)) > 0.2f) {
133 m_lastStuckCheckPosition = position;
134 m_stuckCount = 0;
135 }
136 else {
137 m_stuckCount++;
138 }
139 IsStuck = m_stuckCount >= 4;
140 }
141 if (m_componentCreature.ComponentLocomotion.FlySpeed > 0f
142 && (num > 9f
143 || vector.Y > 0.5f
144 || vector.Y < -1.5f
145 || (!m_componentCreature.ComponentBody.StandingOnValue.HasValue
146 && m_componentCreature.ComponentBody.ImmersionFactor == 0f))
147 && m_componentCreature.ComponentBody.ImmersionFactor < 1f) {
148 float y = MathUtils.Min(0.08f * vector2.LengthSquared(), 12f);
149 Vector3 v2 = v + new Vector3(0f, y, 0f);
150 Vector3 value2 = Speed * Vector3.Normalize(v2 - position);
151 value2.Y = MathUtils.Max(value2.Y, -0.5f);
152 m_flyOrder = value2;
153 m_turnOrder = new Vector2(Math.Clamp(x, -1f, 1f), 0f);
154 }
155 else if (m_componentCreature.ComponentLocomotion.SwimSpeed > 0f
156 && m_componentCreature.ComponentBody.ImmersionFactor > 0.5f) {
157 Vector3 value3 = Speed * Vector3.Normalize(v - position);
158 value3.Y = Math.Clamp(value3.Y, -0.5f, 0.5f);
159 m_swimOrder = value3;
160 m_turnOrder = new Vector2(Math.Clamp(x, -1f, 1f), 0f);
161 }
162 else if (m_componentCreature.ComponentLocomotion.WalkSpeed > 0f) {
163 if (IsTerrainSafeToGo(position, vector)) {
164 m_turnOrder = new Vector2(Math.Clamp(x, -1f, 1f), 0f);
165 if (num2 > 1f) {
166 m_walkOrder = new Vector2(0f, MathUtils.Lerp(Speed, 0f, MathUtils.Saturate((MathF.Abs(x) - 0.33f) / 0.66f)));
167 if (Speed >= 1f
168 && m_componentCreature.ComponentLocomotion.InAirWalkFactor >= 1f
169 && num > 1f
170 && m_random.Float(0f, 1f) < 0.05f) {
171 m_jumpOrder = 1f;
172 }
173 }
174 else {
175 float x2 = Speed * MathUtils.Min(1f * MathF.Sqrt(num2), 1f);
176 m_walkOrder = new Vector2(0f, MathUtils.Lerp(x2, 0f, MathUtils.Saturate(2f * MathF.Abs(x))));
177 }
178 }
179 else {
180 IsStuck = true;
181 }
182 m_componentCreature.ComponentBody.IsSmoothRiseEnabled = num2 >= 1f || vector.Y >= -0.1f;
183 if (num2 < 1f
184 && (vector.Y < -0.5f || vector.Y > 1f)) {
185 if (vector.Y > 0f
186 && m_random.Float(0f, 1f) < 0.05f) {
187 m_jumpOrder = 1f;
188 }
189 if (!m_aboveBelowTime.HasValue) {
191 }
192 else if (m_subsystemTime.GameTime - m_aboveBelowTime.Value > 2.0
193 && m_componentCreature.ComponentBody.StandingOnValue.HasValue) {
194 IsStuck = true;
195 }
196 }
197 else {
198 m_aboveBelowTime = null;
199 }
200 }
201 if (!IgnoreHeightDifference ? num <= Range * Range : num2 <= Range * Range) {
202 if (RaycastDestination) {
203 if (!m_subsystemTerrain.Raycast(
204 position + new Vector3(0f, 0.5f, 0f),
205 v + new Vector3(0f, 0.5f, 0f),
206 false,
207 true,
208 (value, _) => BlocksManager.Blocks[Terrain.ExtractContents(value)].IsCollidable_(value)
209 )
210 .HasValue) {
211 Destination = null;
212 }
213 }
214 else {
215 Destination = null;
216 }
217 }
218 }
219 if (!Destination.HasValue
220 && m_componentCreature.ComponentLocomotion.FlySpeed > 0f
221 && !m_componentCreature.ComponentBody.StandingOnValue.HasValue
222 && m_componentCreature.ComponentBody.ImmersionFactor == 0f) {
224 m_walkOrder = null;
225 m_swimOrder = null;
226 m_flyOrder = new Vector3(0f, -0.5f, 0f);
227 }
228 }
229 m_componentCreature.ComponentLocomotion.WalkOrder = CombineNullables(m_componentCreature.ComponentLocomotion.WalkOrder, m_walkOrder);
230 m_componentCreature.ComponentLocomotion.SwimOrder = CombineNullables(m_componentCreature.ComponentLocomotion.SwimOrder, m_swimOrder);
231 m_componentCreature.ComponentLocomotion.TurnOrder += m_turnOrder;
232 m_componentCreature.ComponentLocomotion.FlyOrder = CombineNullables(m_componentCreature.ComponentLocomotion.FlyOrder, m_flyOrder);
233 m_componentCreature.ComponentLocomotion.JumpOrder = MathUtils.Max(m_jumpOrder, m_componentCreature.ComponentLocomotion.JumpOrder);
234 m_jumpOrder = 0f;
235 }
236
237 public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap) {
238 m_subsystemTime = Project.FindSubsystem<SubsystemTime>(true);
239 m_subsystemBodies = Project.FindSubsystem<SubsystemBodies>(true);
240 m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(true);
241 m_componentCreature = Entity.FindComponent<ComponentCreature>(true);
242 }
243
244 public virtual bool ShouldAvoidBlock(Block block, int cellValue) => block.ShouldAvoid(cellValue, this);
245
249 public virtual bool IsTerrainSafeToGo(Vector3 position, Vector3 direction) {
250 bool isTerrainSafeToGo = false;
251 bool skipVanilla = false;
253 "IsTerrainSafeToGo",
254 modLoader => {
255 modLoader.IsTerrainSafeToGo(this, position, direction, out isTerrainSafeToGo, out skipVanilla);
256 return false;
257 }
258 );
259 if (skipVanilla) {
260 return isTerrainSafeToGo;
261 }
262 //vector是自己判断移动后的位置
263 Vector3 vector = position
264 + new Vector3(0f, 0.1f, 0f)
265 + (direction.LengthSquared() < 1.2f
266 ? new Vector3(direction.X, 0f, direction.Z)
267 : 1.2f * Vector3.Normalize(new Vector3(direction.X, 0f, direction.Z)));
268 Vector3 vector2 = position
269 + new Vector3(0f, 0.1f, 0f)
270 + (direction.LengthSquared() < 1f
271 ? new Vector3(direction.X, 0f, direction.Z)
272 : 1f * Vector3.Normalize(new Vector3(direction.X, 0f, direction.Z)));
273 for (int i = -1; i <= 1; i++) {
274 for (int j = -1; j <= 1; j++) {
275 //只有向前的向量才被计入
276 if (!(Vector3.Dot(direction, new Vector3(i, 0f, j)) > 0f)) {
277 continue;
278 }
279 //检查器位置的方块、下面一格的方块、下面两格的方块。
280 //碰到危险方块则返回不是安全方向;碰到非危险的可碰撞方块则是安全方向
281 for (int num = 0; num >= -2; num--) {
282 int cellValue = m_subsystemTerrain.Terrain.GetCellValue(
283 Terrain.ToCell(vector.X) + i,
284 Terrain.ToCell(vector.Y) + num,
285 Terrain.ToCell(vector.Z) + j
286 );
288 if (ShouldAvoidBlock(block, cellValue)) {
289 return false;
290 }
291 if (block.IsCollidable_(cellValue)) {
292 break;
293 }
294 }
295 }
296 }
297 bool isBlockBeneathDangerous = true;
298 //num2是计算的摔落高度
300 for (int num3 = 0; num3 >= -num2 && vector2.Y + num3 >= 0; num3--) {
301 int cellValue2 = m_subsystemTerrain.Terrain.GetCellValue(
302 Terrain.ToCell(vector2.X),
303 Terrain.ToCell(vector2.Y) + num3,
304 Terrain.ToCell(vector2.Z)
305 );
306 Block block2 = BlocksManager.Blocks[Terrain.ExtractContents(cellValue2)];
307 if ((block2.IsCollidable_(cellValue2) || block2 is FluidBlock)
308 && !ShouldAvoidBlock(block2, cellValue2)) {
309 isBlockBeneathDangerous = false;
310 break;
311 }
312 }
313 if (isBlockBeneathDangerous) {
314 return false;
315 }
316 return true;
317 }
318
319 public virtual ComponentBody FindNearestBodyInFront(Vector3 position, Vector2 direction) {
320 if (m_subsystemTime.GameTime >= m_nextBodiesUpdateTime) {
321 m_nextBodiesUpdateTime = m_subsystemTime.GameTime + 0.5;
322 m_nearbyBodies.Clear();
323 m_subsystemBodies.FindBodiesAroundPoint(m_componentCreature.ComponentBody.Position.XZ, 4f, m_nearbyBodies);
324 }
325 ComponentBody result = null;
326 float num = float.MaxValue;
327 foreach (ComponentBody nearbyBody in m_nearbyBodies) {
328 if (nearbyBody != m_componentCreature.ComponentBody
329 && !(MathF.Abs(nearbyBody.Position.Y - m_componentCreature.ComponentBody.Position.Y) > 1.1f)
330 && Vector2.Dot(nearbyBody.Position.XZ - position.XZ, direction) > 0f) {
331 float num2 = Vector2.DistanceSquared(nearbyBody.Position.XZ, position.XZ);
332 if (num2 < num) {
333 num = num2;
334 result = nearbyBody;
335 }
336 }
337 }
338 return result;
339 }
340
341 public virtual Vector3 AvoidNearestBody(Vector3 position, Vector3 destination) {
342 Vector2 v = destination.XZ - position.XZ;
343 ComponentBody componentBody = FindNearestBodyInFront(position, Vector2.Normalize(v));
344 if (componentBody != null
345 && componentBody != DoNotAvoidBody) {
346 float num = 0.72f * (componentBody.BoxSize.X + m_componentCreature.ComponentBody.BoxSize.X) + 0.5f;
347 Vector2 xZ = componentBody.Position.XZ;
348 Vector2 v2 = Segment2.NearestPoint(new Segment2(position.XZ, destination.XZ), xZ) - xZ;
349 if (v2.LengthSquared() < num * num) {
350 float num2 = v.Length();
351 Vector2 v3 = Vector2.Normalize(xZ + Vector2.Normalize(v2) * num - position.XZ);
352 if (Vector2.Dot(v / num2, v3) > 0.5f) {
353 return new Vector3(position.X + v3.X * num2, destination.Y, position.Z + v3.Y * num2);
354 }
355 }
356 }
357 return destination;
358 }
359
360 public static Vector2? CombineNullables(Vector2? v1, Vector2? v2) {
361 if (!v1.HasValue) {
362 return v2;
363 }
364 if (!v2.HasValue) {
365 return v1;
366 }
367 return v1.Value + v2.Value;
368 }
369
370 public static Vector3? CombineNullables(Vector3? v1, Vector3? v2) {
371 if (!v1.HasValue) {
372 return v2;
373 }
374 if (!v2.HasValue) {
375 return v1;
376 }
377 return v1.Value + v2.Value;
378 }
379 }
380}
Engine.Vector3 Vector3
static int Min(int x1, int x2)
static float Saturate(float x)
static int Max(int x1, int x2)
static float DegToRad(float degrees)
static float Lerp(float x1, float x2, float f)
virtual bool ShouldAvoid(int value)
virtual bool IsCollidable_(int value)
virtual bool ShouldAvoidBlock(Block block, int cellValue)
SubsystemTime m_subsystemTime
DynamicArray< ComponentBody > m_nearbyBodies
virtual Vector3 AvoidNearestBody(Vector3 position, Vector3 destination)
static ? Vector3 CombineNullables(Vector3? v1, Vector3? v2)
SubsystemBodies m_subsystemBodies
static ? Vector2 CombineNullables(Vector2? v1, Vector2? v2)
virtual bool IsTerrainSafeToGo(Vector3 position, Vector3 direction)
地形是否安全可通行
virtual void Update(float dt)
virtual ComponentBody FindNearestBodyInFront(Vector3 position, Vector2 direction)
override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
virtual void SetDestination(Vector3? destination, float speed, float range, bool ignoreHeightDifference, bool raycastDestination, bool takeRisks, ComponentBody doNotAvoidBody)
SubsystemTerrain m_subsystemTerrain
ComponentCreature m_componentCreature
static int ExtractContents(int value)
static int ToCell(float x)
ValuesDictionary ValuesDictionary
static void HookAction(string HookName, Func< ModLoader, bool > action)
执行Hook
static float Dot(Vector2 v1, Vector2 v2)
static readonly Vector2 Zero
static float DistanceSquared(Vector2 v1, Vector2 v2)
static Vector2 Normalize(Vector2 v)
static float Angle(Vector2 v1, Vector2 v2)
float LengthSquared()
static Vector3 Clamp(Vector3 v, float min, float max)
static Vector3 Normalize(Vector3 v)
float LengthSquared()
static float Dot(Vector3 v1, Vector3 v2)
static Vector2 NearestPoint(Segment2 s, Vector2 p)