Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
SubsystemTerrain.cs
浏览该文件的文档.
1using Engine;
4
5namespace Game {
7 public static bool TerrainRenderingEnabled = true;
8 public static bool TerrainUpdaterEnabled = true;
9
10 public Dictionary<Point3, bool> m_modifiedCells = [];
11
12 public DynamicArray<Point3> m_modifiedList = [];
13
14 public static Point3[] m_neighborOffsets = [
15 new(0, 0, 0),
16 new(-1, 0, 0),
17 new(1, 0, 0),
18 new(0, -1, 0),
19 new(0, 1, 0),
20 new(0, 0, -1),
21 new(0, 0, 1)
22 ];
23
25
27
29
31
33
35
37
38 public List<BlockDropValue> m_dropValues = [];
39
40 public static int[] m_drawOrders = [0, 100];
41
42 public virtual SubsystemGameInfo SubsystemGameInfo { get; set; }
43
45
47
48 public virtual SubsystemPalette SubsystemPalette { get; set; }
49
50 public virtual Terrain Terrain { get; set; }
51
52 public virtual TerrainUpdater TerrainUpdater { get; set; }
53
54 public virtual TerrainRenderer TerrainRenderer { get; set; }
55
56 public virtual TerrainSerializer23 TerrainSerializer { get; set; }
57
59
61
62 public int[] DrawOrders => m_drawOrders;
63
65
66 public virtual void ProcessModifiedCells() {
67 m_modifiedList.Clear();
68 foreach (Point3 key in m_modifiedCells.Keys) {
69 m_modifiedList.Add(key);
70 }
71 m_modifiedCells.Clear();
72 for (int i = 0; i < m_modifiedList.Count; i++) {
73 Point3 point = m_modifiedList.Array[i];
74 for (int j = 0; j < m_neighborOffsets.Length; j++) {
75 Point3 point2 = m_neighborOffsets[j];
76 int cellValue = Terrain.GetCellValue(point.X + point2.X, point.Y + point2.Y, point.Z + point2.Z);
77 SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(cellValue));
78 for (int k = 0; k < blockBehaviors.Length; k++) {
79 blockBehaviors[k]
80 .OnNeighborBlockChanged(point.X + point2.X, point.Y + point2.Y, point.Z + point2.Z, point.X, point.Y, point.Z);
81 }
82 }
83 }
84 }
85
86 public virtual TerrainRaycastResult? Raycast(Vector3 start,
87 Vector3 end,
88 bool useInteractionBoxes,
89 bool skipAirBlocks,
90 Func<int, float, bool> action) {
91 float num = Vector3.Distance(start, end);
92 if (num > 1000f) {
93 end = start + 1000f * Vector3.Normalize(end - start);
94 }
95 Ray3 ray = new(start, Vector3.Normalize(end - start));
96 float x = start.X;
97 float y = start.Y;
98 float z = start.Z;
99 float x2 = end.X;
100 float y2 = end.Y;
101 float z2 = end.Z;
102 int num2 = Terrain.ToCell(x);
103 int num3 = Terrain.ToCell(y);
104 int num4 = Terrain.ToCell(z);
105 int num5 = Terrain.ToCell(x2);
106 int num6 = Terrain.ToCell(y2);
107 int num7 = Terrain.ToCell(z2);
108 int num8 = x < x2 ? 1 :
109 x > x2 ? -1 : 0;
110 int num9 = y < y2 ? 1 :
111 y > y2 ? -1 : 0;
112 int num10 = z < z2 ? 1 :
113 z > z2 ? -1 : 0;
114 float num11 = MathF.Floor(x);
115 float num12 = num11 + 1f;
116 float num13 = (x > x2 ? x - num11 : num12 - x) / Math.Abs(x2 - x);
117 float num14 = MathF.Floor(y);
118 float num15 = num14 + 1f;
119 float num16 = (y > y2 ? y - num14 : num15 - y) / Math.Abs(y2 - y);
120 float num17 = MathF.Floor(z);
121 float num18 = num17 + 1f;
122 float num19 = (z > z2 ? z - num17 : num18 - z) / Math.Abs(z2 - z);
123 float num20 = 1f / Math.Abs(x2 - x);
124 float num21 = 1f / Math.Abs(y2 - y);
125 float num22 = 1f / Math.Abs(z2 - z);
126 while (true) {
127 BoundingBox boundingBox = default;
128 int collisionBoxIndex = 0;
129 float? num23 = null;
130 int cellValue = Terrain.GetCellValue(num2, num3, num4);
131 int num24 = Terrain.ExtractContents(cellValue);
132 if (num24 != 0
133 || !skipAirBlocks) {
134 Ray3 ray2 = new(ray.Position - new Vector3(num2, num3, num4), ray.Direction);
135 float? num25 = BlocksManager.Blocks[num24]
136 .Raycast(ray2, this, cellValue, useInteractionBoxes, out int nearestBoxIndex, out BoundingBox nearestBox);
137 if (num25.HasValue /* && (!num23.HasValue || num25.Value < num23.Value)*/) {
138 num23 = num25;
139 collisionBoxIndex = nearestBoxIndex;
140 boundingBox = nearestBox;
141 }
142 }
143 if (num23.HasValue
144 && num23.Value <= num
145 && (action == null || action(cellValue, num23.Value))) {
146 int face = 0;
147 Vector3 vector = start - new Vector3(num2, num3, num4) + num23.Value * ray.Direction;
148 float num26 = float.MaxValue;
149 float num27 = MathF.Abs(vector.X - boundingBox.Min.X);
150 if (num27 < num26) {
151 num26 = num27;
152 face = 3;
153 }
154 num27 = MathF.Abs(vector.X - boundingBox.Max.X);
155 if (num27 < num26) {
156 num26 = num27;
157 face = 1;
158 }
159 num27 = MathF.Abs(vector.Y - boundingBox.Min.Y);
160 if (num27 < num26) {
161 num26 = num27;
162 face = 5;
163 }
164 num27 = MathF.Abs(vector.Y - boundingBox.Max.Y);
165 if (num27 < num26) {
166 num26 = num27;
167 face = 4;
168 }
169 num27 = MathF.Abs(vector.Z - boundingBox.Min.Z);
170 if (num27 < num26) {
171 num26 = num27;
172 face = 2;
173 }
174 num27 = MathF.Abs(vector.Z - boundingBox.Max.Z);
175 if (num27 < num26) {
176 //num26 = num27;
177 face = 0;
178 }
179 TerrainRaycastResult value = default;
180 value.Ray = ray;
181 value.Value = cellValue;
182 value.CellFace = new CellFace { X = num2, Y = num3, Z = num4, Face = face };
183 value.CollisionBoxIndex = collisionBoxIndex;
184 value.Distance = num23.Value;
185 return value;
186 }
187 if (num13 <= num16
188 && num13 <= num19) {
189 if (num2 == num5) {
190 break;
191 }
192 num13 += num20;
193 num2 += num8;
194 }
195 else if (num16 <= num13
196 && num16 <= num19) {
197 if (num3 == num6) {
198 break;
199 }
200 num16 += num21;
201 num3 += num9;
202 }
203 else {
204 if (num4 == num7) {
205 break;
206 }
207 num19 += num22;
208 num4 += num10;
209 }
210 }
211 return null;
212 }
213
226 public static TerrainRaycastResult? Raycast(Terrain terrain,
227 Vector3 start,
228 Vector3 end,
229 bool useInteractionBoxes,
230 bool skipAirBlocks,
231 Func<int, float, bool> action) {
232 float num = Vector3.Distance(start, end);
233 if (num > 1000f) {
234 end = start + 1000f * Vector3.Normalize(end - start);
235 }
236 Ray3 ray = new(start, Vector3.Normalize(end - start));
237 float x = start.X;
238 float y = start.Y;
239 float z = start.Z;
240 float x2 = end.X;
241 float y2 = end.Y;
242 float z2 = end.Z;
243 int num2 = Terrain.ToCell(x);
244 int num3 = Terrain.ToCell(y);
245 int num4 = Terrain.ToCell(z);
246 int num5 = Terrain.ToCell(x2);
247 int num6 = Terrain.ToCell(y2);
248 int num7 = Terrain.ToCell(z2);
249 int num8 = x < x2 ? 1 :
250 x > x2 ? -1 : 0;
251 int num9 = y < y2 ? 1 :
252 y > y2 ? -1 : 0;
253 int num10 = z < z2 ? 1 :
254 z > z2 ? -1 : 0;
255 float num11 = MathF.Floor(x);
256 float num12 = num11 + 1f;
257 float num13 = (x > x2 ? x - num11 : num12 - x) / Math.Abs(x2 - x);
258 float num14 = MathF.Floor(y);
259 float num15 = num14 + 1f;
260 float num16 = (y > y2 ? y - num14 : num15 - y) / Math.Abs(y2 - y);
261 float num17 = MathF.Floor(z);
262 float num18 = num17 + 1f;
263 float num19 = (z > z2 ? z - num17 : num18 - z) / Math.Abs(z2 - z);
264 float num20 = 1f / Math.Abs(x2 - x);
265 float num21 = 1f / Math.Abs(y2 - y);
266 float num22 = 1f / Math.Abs(z2 - z);
267 while (true) {
268 BoundingBox boundingBox = default;
269 int collisionBoxIndex = 0;
270 float? num23 = null;
271 int cellValue = terrain.GetCellValue(num2, num3, num4);
272 int num24 = Terrain.ExtractContents(cellValue);
273 if (num24 != 0
274 || !skipAirBlocks) {
275 Ray3 ray2 = new(ray.Position - new Vector3(num2, num3, num4), ray.Direction);
276 float? num25 = BlocksManager.Blocks[num24]
277 .Raycast(ray2, null, cellValue, useInteractionBoxes, out int nearestBoxIndex, out BoundingBox nearestBox);
278 if (num25.HasValue /* && (!num23.HasValue || num25.Value < num23.Value)*/) {
279 num23 = num25;
280 collisionBoxIndex = nearestBoxIndex;
281 boundingBox = nearestBox;
282 }
283 }
284 if (num23.HasValue
285 && num23.Value <= num
286 && (action == null || action(cellValue, num23.Value))) {
287 int face = 0;
288 Vector3 vector = start - new Vector3(num2, num3, num4) + num23.Value * ray.Direction;
289 float num26 = float.MaxValue;
290 float num27 = MathF.Abs(vector.X - boundingBox.Min.X);
291 if (num27 < num26) {
292 num26 = num27;
293 face = 3;
294 }
295 num27 = MathF.Abs(vector.X - boundingBox.Max.X);
296 if (num27 < num26) {
297 num26 = num27;
298 face = 1;
299 }
300 num27 = MathF.Abs(vector.Y - boundingBox.Min.Y);
301 if (num27 < num26) {
302 num26 = num27;
303 face = 5;
304 }
305 num27 = MathF.Abs(vector.Y - boundingBox.Max.Y);
306 if (num27 < num26) {
307 num26 = num27;
308 face = 4;
309 }
310 num27 = MathF.Abs(vector.Z - boundingBox.Min.Z);
311 if (num27 < num26) {
312 num26 = num27;
313 face = 2;
314 }
315 num27 = MathF.Abs(vector.Z - boundingBox.Max.Z);
316 if (num27 < num26) {
317 //num26 = num27;
318 face = 0;
319 }
320 TerrainRaycastResult value = default;
321 value.Ray = ray;
322 value.Value = cellValue;
323 value.CellFace = new CellFace { X = num2, Y = num3, Z = num4, Face = face };
324 value.CollisionBoxIndex = collisionBoxIndex;
325 value.Distance = num23.Value;
326 return value;
327 }
328 if (num13 <= num16
329 && num13 <= num19) {
330 if (num2 == num5) {
331 break;
332 }
333 num13 += num20;
334 num2 += num8;
335 }
336 else if (num16 <= num13
337 && num16 <= num19) {
338 if (num3 == num6) {
339 break;
340 }
341 num16 += num21;
342 num3 += num9;
343 }
344 else {
345 if (num4 == num7) {
346 break;
347 }
348 num19 += num22;
349 num4 += num10;
350 }
351 }
352 return null;
353 }
354
355 public virtual void ChangeCell(int x, int y, int z, int value, bool updateModificationCounter = true, MovingBlock movingBlock = null) {
356 bool pass = false;
358 "TerrainChangeCell",
359 loader => {
360 // ReSharper disable AccessToModifiedClosure
361 loader.TerrainChangeCell(this, x, y, z, value, out bool Skip);
362 // ReSharper restore AccessToModifiedClosure
363 pass |= Skip;
364 return false;
365 }
366 );
367 if (pass) {
368 return;
369 }
370 if (!Terrain.IsCellValid(x, y, z)) {
371 return;
372 }
373 int cellValueFast = Terrain.GetCellValueFast(x, y, z);
374 value = Terrain.ReplaceLight(value, 0);
375 cellValueFast = Terrain.ReplaceLight(cellValueFast, 0);
376 if (value == cellValueFast) {
377 return;
378 }
379 Terrain.SetCellValueFast(x, y, z, value);
380 TerrainChunk chunkAtCell = Terrain.GetChunkAtCell(x, z);
381 if (chunkAtCell != null) {
382 if (updateModificationCounter) {
383 chunkAtCell.ModificationCounter++;
384 }
385 TerrainUpdater.DowngradeChunkNeighborhoodState(chunkAtCell.Coords, 1, TerrainChunkState.InvalidLight, false);
386 }
387 m_modifiedCells[new Point3(x, y, z)] = true;
388 try {
389 ChangeCellToBehavior(x, y, z, cellValueFast, value, movingBlock);
390 }
391 catch (Exception e) {
392 Log.Error($"Block behavior on terrain change execute error: {e}");
393 }
394 }
395
396 public virtual void ChangeCellToBehavior(int x, int y, int z, int oldValue, int newValue, MovingBlock movingBlock) {
397 int num = Terrain.ExtractContents(oldValue);
398 int num2 = Terrain.ExtractContents(newValue);
399 SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(oldValue));
400 SubsystemBlockBehavior[] blockBehaviors2 = m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(newValue));
401 if (movingBlock?.MovingBlockSet != null) {
402 if (movingBlock.MovingBlockSet.Stopped) {
403 for (int j = 0; j < blockBehaviors2.Length; j++) {
404 blockBehaviors2[j].OnBlockStopMoving(newValue, oldValue, x, y, z, movingBlock);
405 }
406 }
407 else {
408 for (int j = 0; j < blockBehaviors.Length; j++) {
409 blockBehaviors[j].OnBlockStartMoving(oldValue, newValue, x, y, z, movingBlock);
410 }
411 }
412 return;
413 }
414 if (num2 != num) {
415 for (int i = 0; i < blockBehaviors.Length; i++) {
416 blockBehaviors[i].OnBlockRemoved(oldValue, newValue, x, y, z);
417 }
418 for (int j = 0; j < blockBehaviors2.Length; j++) {
419 blockBehaviors2[j].OnBlockAdded(newValue, oldValue, x, y, z);
420 }
421 }
422 else {
423 for (int k = 0; k < blockBehaviors2.Length; k++) {
424 blockBehaviors2[k].OnBlockModified(newValue, oldValue, x, y, z);
425 }
426 }
427 }
428
429 public virtual void DestroyCell(int toolLevel,
430 int x,
431 int y,
432 int z,
433 int newValue,
434 bool noDrop,
435 bool noParticleSystem,
436 MovingBlock movingBlock = null) {
437 int cellValue = Terrain.GetCellValue(x, y, z);
438 int num = Terrain.ExtractContents(cellValue);
439 Block block = BlocksManager.Blocks[num];
440 if (num != 0) {
441 bool showDebris = true;
442 if (!noDrop) {
443 m_dropValues.Clear();
444 block.GetDropValues(this, cellValue, newValue, toolLevel, m_dropValues, out showDebris);
445 for (int i = 0; i < m_dropValues.Count; i++) {
446 BlockDropValue dropValue = m_dropValues[i];
447 if (dropValue.Count > 0) {
448 SubsystemBlockBehavior[] blockBehaviors =
449 m_subsystemBlockBehaviors.GetBlockBehaviors(Terrain.ExtractContents(dropValue.Value));
450 for (int j = 0; j < blockBehaviors.Length; j++) {
451 blockBehaviors[j].OnItemHarvested(x, y, z, cellValue, ref dropValue, ref newValue);
452 }
453 if (dropValue.Count > 0
454 && Terrain.ExtractContents(dropValue.Value) != 0) {
455 Vector3 position = new Vector3(x, y, z) + new Vector3(0.5f);
456 m_subsystemPickables.AddPickable(dropValue.Value, dropValue.Count, position, null, null);
457 }
458 }
459 }
460 }
461 if (showDebris
462 && !noParticleSystem
463 && m_subsystemViews.CalculateDistanceFromNearestView(new Vector3(x, y, z)) < 16f) {
464 m_subsystemParticles.AddParticleSystem(
465 block.CreateDebrisParticleSystem(this, new Vector3(x + 0.5f, y + 0.5f, z + 0.5f), cellValue, 1f)
466 );
467 }
468 }
469 ChangeCell(x, y, z, newValue, true, movingBlock);
470 }
471
472 public virtual void Draw(Camera camera, int drawOrder) {
474 if (drawOrder == DrawOrders[0]) {
475 TerrainUpdater.PrepareForDrawing(camera);
476 TerrainRenderer.PrepareForDrawing(camera);
477 TerrainRenderer.DrawOpaque(camera);
478 TerrainRenderer.DrawAlphaTested(camera);
479 }
480 else if (drawOrder == m_drawOrders[1]) {
481 TerrainRenderer.DrawTransparent(camera);
482 }
483 }
484 }
485
486 public virtual void Update(float dt) {
488 TerrainUpdater.Update();
490 }
491 }
492
493 public override void Load(ValuesDictionary valuesDictionary) {
494 m_subsystemViews = Project.FindSubsystem<SubsystemGameWidgets>(true);
495 SubsystemGameInfo = Project.FindSubsystem<SubsystemGameInfo>(true);
496 m_subsystemParticles = Project.FindSubsystem<SubsystemParticles>(true);
497 m_subsystemPickables = Project.FindSubsystem<SubsystemPickables>(true);
501 m_subsystemsky = Project.FindSubsystem<SubsystemSky>();
502 m_subsystemTime = Project.FindSubsystem<SubsystemTime>();
504 SubsystemPalette = Project.FindSubsystem<SubsystemPalette>(true);
505 Terrain = new Terrain();
507 TerrainUpdater = new TerrainUpdater(this);
510 Terrain,
511 this,
512 Project.FindSubsystem<SubsystemElectricity>(true),
514 Project.FindSubsystem<SubsystemMetersBlockBehavior>(true),
516 );
517 TerrainGenerationMode terrainGenerationMode = SubsystemGameInfo.WorldSettings.TerrainGenerationMode;
518 if (string.CompareOrdinal(SubsystemGameInfo.WorldSettings.OriginalSerializationVersion, "2.1") <= 0) {
519 if (terrainGenerationMode == TerrainGenerationMode.FlatContinent
520 || terrainGenerationMode == TerrainGenerationMode.FlatIsland) {
522 }
523 else {
525 }
526 }
527 else if (string.CompareOrdinal(SubsystemGameInfo.WorldSettings.OriginalSerializationVersion, "2.2") == 0) {
528 if (terrainGenerationMode == TerrainGenerationMode.FlatContinent
529 || terrainGenerationMode == TerrainGenerationMode.FlatIsland) {
531 }
532 else {
534 }
535 }
536 else if (string.CompareOrdinal(SubsystemGameInfo.WorldSettings.OriginalSerializationVersion, "2.3") == 0) {
537 if (terrainGenerationMode == TerrainGenerationMode.FlatContinent
538 || terrainGenerationMode == TerrainGenerationMode.FlatIsland) {
540 }
541 else {
543 }
544 }
545 else if (terrainGenerationMode == TerrainGenerationMode.FlatContinent
546 || terrainGenerationMode == TerrainGenerationMode.FlatIsland) {
548 }
549 else {
551 }
552 }
553
554 public override void Save(ValuesDictionary valuesDictionary) {
555 TerrainUpdater.UpdateEvent.WaitOne();
556 try {
557 TerrainChunk[] allocatedChunks = Terrain.AllocatedChunks;
558 foreach (TerrainChunk chunk in allocatedChunks) {
559 TerrainSerializer.SaveChunk(chunk);
560 }
561 }
562 finally {
563 TerrainUpdater.UpdateEvent.Set();
564 }
565 }
566
567 public override void Dispose() {
568 TerrainRenderer.Dispose();
569 TerrainUpdater.Dispose();
570 TerrainSerializer.Dispose();
571 Terrain.Dispose();
572 }
573 }
574}
Engine.Vector3 Vector3
static void Error(object message)
定义 Log.cs:80
virtual void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List< BlockDropValue > dropValues, out bool showDebris)
virtual BlockDebrisParticleSystem CreateDebrisParticleSystem(SubsystemTerrain subsystemTerrain, Vector3 position, int value, float strength)
virtual ? float Raycast(Ray3 ray, SubsystemTerrain subsystemTerrain, int value, bool useInteractionBoxes, out int nearestBoxIndex, out BoundingBox nearestBox)
IMovingBlockSet MovingBlockSet
virtual void OnItemHarvested(int x, int y, int z, int blockValue, ref BlockDropValue dropValue, ref int newBlockValue)
virtual void OnBlockStopMoving(int value, int oldValue, int x, int y, int z, MovingBlock movingBlock)
virtual void OnNeighborBlockChanged(int x, int y, int z, int neighborX, int neighborY, int neighborZ)
virtual void OnBlockAdded(int value, int oldValue, int x, int y, int z)
virtual void OnBlockModified(int value, int oldValue, int x, int y, int z)
virtual void OnBlockRemoved(int value, int newValue, int x, int y, int z)
virtual void OnBlockStartMoving(int value, int newValue, int x, int y, int z, MovingBlock movingBlock)
override void Load(ValuesDictionary valuesDictionary)
SubsystemGameWidgets m_subsystemViews
virtual TerrainSerializer23 TerrainSerializer
virtual SubsystemFurnitureBlockBehavior SubsystemFurnitureBlockBehavior
virtual void ChangeCell(int x, int y, int z, int value, bool updateModificationCounter=true, MovingBlock movingBlock=null)
virtual void Draw(Camera camera, int drawOrder)
virtual SubsystemGameInfo SubsystemGameInfo
virtual void Update(float dt)
Dictionary< Point3, bool > m_modifiedCells
SubsystemBlockBehaviors m_subsystemBlockBehaviors
SubsystemTimeOfDay m_subsystemTimeOfDay
virtual void DestroyCell(int toolLevel, int x, int y, int z, int newValue, bool noDrop, bool noParticleSystem, MovingBlock movingBlock=null)
virtual SubsystemAnimatedTextures SubsystemAnimatedTextures
virtual BlockGeometryGenerator BlockGeometryGenerator
virtual ITerrainContentsGenerator TerrainContentsGenerator
List< BlockDropValue > m_dropValues
virtual void ChangeCellToBehavior(int x, int y, int z, int oldValue, int newValue, MovingBlock movingBlock)
static ? TerrainRaycastResult Raycast(Terrain terrain, Vector3 start, Vector3 end, bool useInteractionBoxes, bool skipAirBlocks, Func< int, float, bool > action)
一个不依赖于SubsystemTerrain的射线检测方法 注意!由于此方法不依赖于SubsystemTerrain,故射线检测某些方块(如家具等)会异常或报错 请谨慎使用
SubsystemPickables m_subsystemPickables
virtual ? TerrainRaycastResult Raycast(Vector3 start, Vector3 end, bool useInteractionBoxes, bool skipAirBlocks, Func< int, float, bool > action)
virtual TerrainRenderer TerrainRenderer
override void Save(ValuesDictionary valuesDictionary)
virtual SubsystemPalette SubsystemPalette
SubsystemParticles m_subsystemParticles
DynamicArray< Point3 > m_modifiedList
virtual TerrainUpdater TerrainUpdater
virtual int GetCellValue(int x, int y, int z)
ValuesDictionary ValuesDictionary
static void HookAction(string HookName, Func< ModLoader, bool > action)
执行Hook
Vector3 Direction
定义 Ray3.cs:5
static Vector3 Normalize(Vector3 v)
static float Distance(Vector3 v1, Vector3 v2)