Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
SubsystemPathfinding.cs
浏览该文件的文档.
1using Engine;
4
5namespace Game {
7 public class Request {
8 public Vector3 Start;
9
10 public Vector3 End;
11
12 public float MinDistance;
13
15
16 public bool IgnoreDoors;
17
19
21 }
22
23 public class Storage : IAStarStorage<Vector3> {
25
26 public void Clear() {
27 Dictionary.Clear();
28 }
29
30 public object Get(Vector3 p) {
31 Dictionary.TryGetValue(p, out object value);
32 return value;
33 }
34
35 public void Set(Vector3 p, object data) {
36 Dictionary[p] = data;
37 }
38 }
39
40 public class World : IAStarWorld<Vector3> {
42
44
45 public float Cost(Vector3 p1, Vector3 p2) => 0.999f - 0.1f * Vector3.Dot(Vector3.Normalize(p2 - p1), Vector3.Normalize(Request.End - p1));
46
47 public void Neighbors(Vector3 p, DynamicArray<Vector3> neighbors) {
48 neighbors.Count = 0;
49 AddNeighbor(neighbors, p, 1, 0);
50 AddNeighbor(neighbors, p, -1, 0);
51 AddNeighbor(neighbors, p, 0, -1);
52 AddNeighbor(neighbors, p, 0, 1);
53 AddNeighbor(neighbors, p, -1, -1);
54 AddNeighbor(neighbors, p, 1, -1);
55 AddNeighbor(neighbors, p, 1, 1);
56 AddNeighbor(neighbors, p, -1, 1);
57 }
58
59 public float Heuristic(Vector3 p1, Vector3 p2) {
60 float num = MathF.Abs(p1.X - p2.X);
61 float num2 = MathF.Abs(p1.Z - p2.Z);
62 if (num > num2) {
63 return 1.41f * num2 + 1f * (num - num2);
64 }
65 return 1.41f * num + 1f * (num2 - num);
66 }
67
68 public bool IsGoal(Vector3 p) => Vector3.DistanceSquared(p, Request.End) <= Request.MinDistance * Request.MinDistance;
69
70 public void AddNeighbor(DynamicArray<Vector3> neighbors, Vector3 p, int dx, int dz) {
71 float y = p.Y;
72 float num = p.Y;
73 int num2 = Terrain.ToCell(p.X) + dx;
74 int num3 = Terrain.ToCell(p.Y);
75 int num4 = Terrain.ToCell(p.Z) + dz;
76 int cellValue = SubsystemTerrain.Terrain.GetCellValue(num2, num3, num4);
77 int num5 = Terrain.ExtractContents(cellValue);
78 Block block = BlocksManager.Blocks[num5];
79 if (block.ShouldAvoid(cellValue)) {
80 return;
81 }
82 if (block.IsCollidable_(cellValue)
83 && (!Request.IgnoreDoors || (!(block is DoorBlock) && !(block is TrapdoorBlock)))) {
84 float blockWalkingHeight = GetBlockWalkingHeight(block, cellValue);
85 if (blockWalkingHeight > 0.5f
86 && (block.NoAutoJump || block.NoSmoothRise)) {
87 return;
88 }
89 y = num3 + blockWalkingHeight;
90 num = num3 + blockWalkingHeight;
91 }
92 else {
93 bool flag = false;
94 for (int num6 = -1; num6 >= -4; num6--) {
95 int cellValue2 = SubsystemTerrain.Terrain.GetCellValue(num2, num3 + num6, num4);
96 int num7 = Terrain.ExtractContents(cellValue2);
97 Block block2 = BlocksManager.Blocks[num7];
98 if (block2.ShouldAvoid(cellValue2)) {
99 return;
100 }
101 if (block2.IsCollidable_(cellValue2)) {
102 y = num3 + num6 + 1;
103 flag = true;
104 break;
105 }
106 }
107 if (!flag) {
108 return;
109 }
110 }
111 int num8 = dx == 0 || dz == 0 ? 2 : 3;
112 Vector3 vector = new(p.X, num + 0.01f, p.Z);
113 Vector3 v = new(num2 + 0.5f, num + 0.01f, num4 + 0.5f);
114 Vector3 v2 = 1f / num8 * (v - vector);
115 for (int i = 1; i <= num8; i++) {
116 Vector3 v3 = vector + i * v2;
117 BoundingBox box = new(
118 v3 - new Vector3(Request.BoxSize.X / 2f + 0.01f, 0f, Request.BoxSize.Z / 2f + 0.01f),
119 v3 + new Vector3(Request.BoxSize.X / 2f - 0.01f, Request.BoxSize.Y, Request.BoxSize.Z / 2f - 0.01f)
120 );
121 if (IsBlocked(box)) {
122 return;
123 }
124 }
125 neighbors.Add(new Vector3(num2 + 0.5f, y, num4 + 0.5f));
126 }
127
128 public float GetBlockWalkingHeight(Block block, int value) {
129 if (block is DoorBlock
130 || block is FenceGateBlock) {
131 return 0f;
132 }
133 float num = 0f;
134 BoundingBox[] customCollisionBoxes = block.GetCustomCollisionBoxes(SubsystemTerrain, value);
135 for (int i = 0; i < customCollisionBoxes.Length; i++) {
136 BoundingBox boundingBox = customCollisionBoxes[i];
137 num = MathUtils.Max(num, boundingBox.Max.Y);
138 }
139 return num;
140 }
141
142 public bool IsBlocked(BoundingBox box) {
143 int num = Terrain.ToCell(box.Min.X);
144 int num2 = MathUtils.Max(Terrain.ToCell(box.Min.Y), 0);
145 int num3 = Terrain.ToCell(box.Min.Z);
146 int num4 = Terrain.ToCell(box.Max.X);
147 int num5 = MathUtils.Min(Terrain.ToCell(box.Max.Y), 255);
148 int num6 = Terrain.ToCell(box.Max.Z);
149 for (int i = num; i <= num4; i++) {
150 for (int j = num3; j <= num6; j++) {
151 TerrainChunk chunkAtCell = SubsystemTerrain.Terrain.GetChunkAtCell(i, j);
152 if (chunkAtCell == null) {
153 continue;
154 }
155 int num7 = TerrainChunk.CalculateCellIndex(i & 0xF, num2, j & 0xF);
156 int num8 = num2;
157 while (num8 <= num5) {
158 int cellValueFast = chunkAtCell.GetCellValueFast(num7);
159 int num9 = Terrain.ExtractContents(cellValueFast);
160 if (num9 != 0) {
161 Block block = BlocksManager.Blocks[num9];
162 if (block.ShouldAvoid(cellValueFast)) {
163 return true;
164 }
165 if (block.IsCollidable_(cellValueFast)) {
166 Vector3 v = new(i, num8, j);
167 BoundingBox[] customCollisionBoxes = block.GetCustomCollisionBoxes(SubsystemTerrain, cellValueFast);
168 for (int k = 0; k < customCollisionBoxes.Length; k++) {
169 BoundingBox boundingBox = customCollisionBoxes[k];
170 if (box.Intersection(new BoundingBox(v + boundingBox.Min, v + boundingBox.Max))) {
171 return true;
172 }
173 }
174 }
175 }
176 num8++;
177 num7++;
178 }
179 }
180 }
181 return false;
182 }
183 }
184
186
187 public Queue<Request> m_requests = new();
188
189 public AStar<Vector3> m_astar = new();
190
191 public void QueuePathSearch(Vector3 start,
192 Vector3 end,
193 float minDistance,
194 Vector3 boxSize,
195 bool ignoreDoors,
196 int maxPositionsToCheck,
197 PathfindingResult result) {
198 lock (m_requests) {
199 if (m_requests.Count < 10) {
200 result.IsCompleted = false;
201 result.IsInProgress = true;
202 m_requests.Enqueue(
203 new Request {
204 Start = start,
205 End = end,
206 MinDistance = minDistance,
207 BoxSize = boxSize,
208 IgnoreDoors = ignoreDoors,
209 MaxPositionsToCheck = maxPositionsToCheck,
210 PathfindingResult = result
211 }
212 );
213 Monitor.Pulse(m_requests);
214 }
215 else {
216 result.IsCompleted = true;
217 result.IsInProgress = false;
218 result.Path.Clear();
219 result.PathCost = 0f;
220 result.PositionsChecked = 0;
221 }
222 }
223 }
224
225 public override void Load(ValuesDictionary valuesDictionary) {
226 m_subsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(true);
227 World world = new() { SubsystemTerrain = Project.FindSubsystem<SubsystemTerrain>(true) };
228 m_astar.OpenStorage = new Storage();
229 m_astar.ClosedStorage = new Storage();
230 m_astar.World = world;
231 Task.Run(ThreadFunction);
232 }
233
234 public override void Dispose() {
235 lock (m_requests) {
236 m_requests.Clear();
237 m_requests.Enqueue(null);
238 Monitor.Pulse(m_requests);
239 }
240 }
241 public void ThreadFunction() {
242 while (true) {
243 Request request;
244 lock (m_requests) {
245 while (m_requests.Count == 0) {
246#pragma warning disable CA1416
247 Monitor.Wait(m_requests);
248#pragma warning restore CA1416
249 }
250 request = m_requests.Dequeue();
251 }
252 if (request == null) {
253 break;
254 }
255 ProcessRequest(request);
256 Task.Delay(250).Wait();
257 }
258 }
259
260
261 public void ProcessRequest(Request request) {
262 ((World)m_astar.World).Request = request;
263 m_astar.Path = request.PathfindingResult.Path;
264 _ = Time.RealTime;
265 m_astar.FindPath(request.Start, request.End, request.MinDistance, request.MaxPositionsToCheck);
266 _ = Time.RealTime;
267 SmoothPath(m_astar.Path, request.BoxSize);
268 _ = Time.RealTime;
269 request.PathfindingResult.PathCost = m_astar.PathCost;
270 request.PathfindingResult.PositionsChecked = ((Storage)m_astar.ClosedStorage).Dictionary.Count;
271 request.PathfindingResult.IsInProgress = false;
272 request.PathfindingResult.IsCompleted = true;
273 }
274
275 public void SmoothPath(DynamicArray<Vector3> path, Vector3 boxSize) {
276 for (int num = path.Count - 2; num > 0; num--) {
277 if (IsPassable(path.Array[num + 1], path.Array[num - 1], boxSize)) {
278 path.RemoveAt(num);
279 }
280 }
281 }
282
283 public bool IsPassable(Vector3 p1, Vector3 p2, Vector3 boxSize) {
284 Vector3 vector = new(p1.X, p1.Y + 0.5f, p1.Z);
285 Vector3 vector2 = new(p2.X, p2.Y + 0.5f, p2.Z);
286 Vector3 v = (0.5f * boxSize.X + 0.1f) * Vector3.Normalize(Vector3.Cross(Vector3.UnitY, vector2 - vector));
287 if (m_subsystemTerrain.Raycast(vector, vector2, false, true, SmoothingRaycastFunction_Obstacle).HasValue) {
288 return false;
289 }
290 if (m_subsystemTerrain.Raycast(vector - v, vector2 - v, false, true, SmoothingRaycastFunction_Obstacle).HasValue) {
291 return false;
292 }
293 if (m_subsystemTerrain.Raycast(vector + v, vector2 + v, false, true, SmoothingRaycastFunction_Obstacle).HasValue) {
294 return false;
295 }
296 if (m_subsystemTerrain.Raycast(
297 vector + new Vector3(0f, -1f, 0f),
298 vector2 + new Vector3(0f, -1f, 0f),
299 false,
300 false,
302 )
303 .HasValue) {
304 return false;
305 }
306 if (m_subsystemTerrain.Raycast(
307 vector + new Vector3(0f, -1f, 0f) - v,
308 vector2 + new Vector3(0f, -1f, 0f) - v,
309 false,
310 false,
312 )
313 .HasValue) {
314 return false;
315 }
316 if (m_subsystemTerrain.Raycast(
317 vector + new Vector3(0f, -1f, 0f) + v,
318 vector2 + new Vector3(0f, -1f, 0f) + v,
319 false,
320 false,
322 )
323 .HasValue) {
324 return false;
325 }
326 return true;
327 }
328
329 public static bool SmoothingRaycastFunction_Obstacle(int value, float distance) {
330 int num = Terrain.ExtractContents(value);
331 Block block = BlocksManager.Blocks[num];
332 if (block.ShouldAvoid(value)) {
333 return true;
334 }
335 if (block.IsCollidable_(value)) {
336 return true;
337 }
338 return false;
339 }
340
341 public static bool SmoothingRaycastFunction_Support(int value, float distance) {
342 int num = Terrain.ExtractContents(value);
343 Block block = BlocksManager.Blocks[num];
344 if (block.ShouldAvoid(value)) {
345 return true;
346 }
347 if (!block.IsCollidable_(value)) {
348 return true;
349 }
350 return false;
351 }
352 }
353}
Engine.Vector3 Vector3
Silk.NET.Windowing.Monitor Monitor
static int Min(int x1, int x2)
static int Max(int x1, int x2)
static double RealTime
定义 Time.cs:38
virtual bool ShouldAvoid(int value)
virtual bool IsCollidable_(int value)
bool NoAutoJump
bool NoSmoothRise
virtual BoundingBox[] GetCustomCollisionBoxes(SubsystemTerrain terrain, int value)
DynamicArray< Vector3 > Path
Dictionary< Vector3, object > Dictionary
void AddNeighbor(DynamicArray< Vector3 > neighbors, Vector3 p, int dx, int dz)
void Neighbors(Vector3 p, DynamicArray< Vector3 > neighbors)
float GetBlockWalkingHeight(Block block, int value)
float Heuristic(Vector3 p1, Vector3 p2)
override void Load(ValuesDictionary valuesDictionary)
void QueuePathSearch(Vector3 start, Vector3 end, float minDistance, Vector3 boxSize, bool ignoreDoors, int maxPositionsToCheck, PathfindingResult result)
static bool SmoothingRaycastFunction_Obstacle(int value, float distance)
static bool SmoothingRaycastFunction_Support(int value, float distance)
bool IsPassable(Vector3 p1, Vector3 p2, Vector3 boxSize)
void SmoothPath(DynamicArray< Vector3 > path, Vector3 boxSize)
static int CalculateCellIndex(int x, int y, int z)
virtual int GetCellValueFast(int index)
static int ExtractContents(int value)
static int ToCell(float x)
ValuesDictionary ValuesDictionary
bool Intersection(BoundingBox box)
static float DistanceSquared(Vector3 v1, Vector3 v2)
static Vector3 Cross(Vector3 v1, Vector3 v2)
static Vector3 Normalize(Vector3 v)
static readonly Vector3 UnitY
static float Dot(Vector3 v1, Vector3 v2)