Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
TerrainUpdater.cs
浏览该文件的文档.
1using System.Runtime.CompilerServices;
2using Engine;
3
4namespace Game {
5 public class TerrainUpdater {
6 public class UpdateStatistics {
7 public static int m_counter;
8
9 public double FindBestChunkTime;
10
12
13 public double LoadingTime;
14
15 public int LoadingCount;
16
17 public double ContentsTime1;
18
19 public int ContentsCount1;
20
21 public double ContentsTime2;
22
23 public int ContentsCount2;
24
25 public double ContentsTime3;
26
27 public int ContentsCount3;
28
29 public double ContentsTime4;
30
31 public int ContentsCount4;
32
33 public double LightTime;
34
35 public int LightCount;
36
37 public double LightSourcesTime;
38
40
41 public double LightPropagateTime;
42
44
46
47 public double VerticesTime1;
48
49 public int VerticesCount1;
50
51 public double VerticesTime2;
52
53 public int VerticesCount2;
54
55 public int HashCount;
56
57 public double HashTime;
58
59 public int GeneratedSlices;
60
61 public int SkippedSlices;
62
63 public virtual void Log() {
64 Engine.Log.Information("Terrain Update #{0}", m_counter++);
65 if (FindBestChunkCount > 0) {
66 Engine.Log.Information(" FindBestChunk: {0:0.0}ms ({1}x)", FindBestChunkTime * 1000.0, FindBestChunkCount);
67 }
68 if (LoadingCount > 0) {
69 Engine.Log.Information(" Loading: {0:0.0}ms ({1}x)", LoadingTime * 1000.0, LoadingCount);
70 }
71 if (ContentsCount1 > 0) {
72 Engine.Log.Information(" Contents1: {0:0.0}ms ({1}x)", ContentsTime1 * 1000.0, ContentsCount1);
73 }
74 if (ContentsCount2 > 0) {
75 Engine.Log.Information(" Contents2: {0:0.0}ms ({1}x)", ContentsTime2 * 1000.0, ContentsCount2);
76 }
77 if (ContentsCount3 > 0) {
78 Engine.Log.Information(" Contents3: {0:0.0}ms ({1}x)", ContentsTime3 * 1000.0, ContentsCount3);
79 }
80 if (ContentsCount4 > 0) {
81 Engine.Log.Information(" Contents4: {0:0.0}ms ({1}x)", ContentsTime4 * 1000.0, ContentsCount4);
82 }
83 if (LightCount > 0) {
84 Engine.Log.Information(" Light: {0:0.0}ms ({1}x)", LightTime * 1000.0, LightCount);
85 }
86 if (LightSourcesCount > 0) {
87 Engine.Log.Information(" LightSources: {0:0.0}ms ({1}x)", LightSourcesTime * 1000.0, LightSourcesCount);
88 }
89 if (LightPropagateCount > 0) {
91 " LightPropagate: {0:0.0}ms ({1}x) {2} ls",
92 LightPropagateTime * 1000.0,
95 );
96 }
97 if (VerticesCount1 > 0) {
98 Engine.Log.Information(" Vertices1: {0:0.0}ms ({1}x)", VerticesTime1 * 1000.0, VerticesCount1);
99 }
100 if (VerticesCount2 > 0) {
101 Engine.Log.Information(" Vertices2: {0:0.0}ms ({1}x)", VerticesTime2 * 1000.0, VerticesCount2);
102 }
103 if (VerticesCount1 + VerticesCount2 > 0) {
105 " AllVertices: {0:0.0}ms ({1}x)",
106 (VerticesTime1 + VerticesTime2) * 1000.0,
108 );
109 }
110 if (HashCount > 0) {
111 Engine.Log.Information(" Hash: {0:0.0}ms ({1}x)", HashTime * 1000.0, HashCount);
112 }
113 if (GeneratedSlices > 0) {
114 Engine.Log.Information(" Generated Slices: {0}/{1}", GeneratedSlices, GeneratedSlices + SkippedSlices);
115 }
116 }
117 }
118
119 public struct UpdateLocation {
121
123
124 public float VisibilityDistance;
125
126 public float ContentDistance;
127 }
128
129 public struct UpdateParameters {
131
132 public Dictionary<int, UpdateLocation> Locations;
133 }
134
135 public struct LightSource {
136 public int X;
137
138 public int Y;
139
140 public int Z;
141
142 public int Light;
143 }
144
146 new Vector2(0f, 0f),
147 new Vector2(0.125f, 0f),
148 new Vector2(0.25f, 0f),
149 new Vector2(0.375f, -4f),
150 new Vector2(0.5f, -12f),
151 new Vector2(0.625f, -24f),
152 new Vector2(0.75f, -12f),
153 new Vector2(0.875f, -4f),
154 new Vector2(1f, 0f)
155 );
156
158 new Vector2(0f, 0f),
159 new Vector2(0.25f, 0f),
160 new Vector2(0.5f, 0f),
161 new Vector2(0.75f, 0f),
162 new Vector2(1f, 0f)
163 );
164
165 public const int m_lightAttenuationWithDistance = 1;
166
167 public const float m_updateHysteresis = 8f;
168
170
172
174
176
178
180
182
183 public DynamicArray<LightSource> m_lightSources = [];
184
186
187 public Task m_task;
188
189 public AutoResetEvent m_updateEvent = new(true);
190
191 public ManualResetEvent m_pauseEvent = new(true);
192
193 public volatile bool m_quitUpdateThread;
194
196
197 public object m_updateParametersLock = new();
198
199 public object m_unpauseLock = new();
200
202
204
206
208
209 public Dictionary<int, UpdateLocation?> m_pendingLocations = [];
210
211 public static int ChunkUpdates;
212
213 public static int SlowTerrainUpdate;
214
215 public static bool LogTerrainUpdateStats = false;
216
217 public AutoResetEvent UpdateEvent => m_updateEvent;
218
219 public event Action<TerrainChunk> ChunkInitialized;
220
221 public TerrainUpdater() {}
222
223 public TerrainUpdater(SubsystemTerrain subsystemTerrain) {
224 ChunkUpdates = 0;
225 m_subsystemTerrain = subsystemTerrain;
226 m_subsystemGameInfo = m_subsystemTerrain.Project.FindSubsystem<SubsystemGameInfo>(true);
227 m_subsystemSky = m_subsystemTerrain.Project.FindSubsystem<SubsystemSky>(true);
228 m_subsystemSeasons = m_subsystemTerrain.Project.FindSubsystem<SubsystemSeasons>(true);
231 m_terrain = subsystemTerrain.Terrain;
232 m_updateParameters.Chunks = [];
233 m_updateParameters.Locations = [];
234 m_threadUpdateParameters.Chunks = [];
235 m_threadUpdateParameters.Locations = [];
237 }
238
239 public virtual void Dispose() {
241 m_quitUpdateThread = true;
243 m_updateEvent.Set();
244 if (m_task != null) {
245 m_task.Wait();
246 m_task = null;
247 }
248 m_pauseEvent.Dispose();
249 m_updateEvent.Dispose();
250 }
251
255
256 public virtual void SetUpdateLocation(int locationIndex, Vector2 center, float visibilityDistance, float contentDistance) {
257 contentDistance = MathUtils.Max(contentDistance, visibilityDistance);
258 m_updateParameters.Locations.TryGetValue(locationIndex, out UpdateLocation value);
259 if (contentDistance != value.ContentDistance
260 || visibilityDistance != value.VisibilityDistance
261 || !value.LastChunksUpdateCenter.HasValue
262 || Vector2.DistanceSquared(center, value.LastChunksUpdateCenter.Value) > 64f) {
263 value.Center = center;
264 value.VisibilityDistance = visibilityDistance;
265 value.ContentDistance = contentDistance;
266 value.LastChunksUpdateCenter = center;
267 m_pendingLocations[locationIndex] = value;
268 }
269 }
270
271 public virtual void RemoveUpdateLocation(int locationIndex) {
272 m_pendingLocations[locationIndex] = null;
273 }
274
275 public virtual float GetUpdateProgress(int locationIndex, float visibilityDistance, float contentDistance) {
276 int num = 0;
277 int num2 = 0;
278 if (m_updateParameters.Locations.TryGetValue(locationIndex, out UpdateLocation value)) {
279 visibilityDistance = MathUtils.Max(MathUtils.Min(visibilityDistance, value.VisibilityDistance) - m_updateHysteresis - 0.1f, 0f);
280 contentDistance = MathUtils.Max(MathUtils.Min(contentDistance, value.ContentDistance) - m_updateHysteresis - 0.1f, 0f);
281 float num3 = MathUtils.Sqr(visibilityDistance);
282 float num4 = MathUtils.Sqr(contentDistance);
283 float v = MathUtils.Max(visibilityDistance, contentDistance);
284 Point2 point = Terrain.ToChunk(value.Center - new Vector2(v));
285 Point2 point2 = Terrain.ToChunk(value.Center + new Vector2(v));
286 for (int i = point.X; i <= point2.X; i++) {
287 for (int j = point.Y; j <= point2.Y; j++) {
288 TerrainChunk chunkAtCoords = m_terrain.GetChunkAtCoords(i, j);
289 float num5 = Vector2.DistanceSquared(
290 v2: new Vector2((i + 0.5f) * TerrainChunk.Size, (j + 0.5f) * TerrainChunk.Size),
291 v1: value.Center
292 );
293 if (num5 <= num3) {
294 if (chunkAtCoords == null
295 || chunkAtCoords.State < TerrainChunkState.Valid) {
296 num2++;
297 }
298 else {
299 num++;
300 }
301 }
302 else if (num5 <= num4) {
303 if (chunkAtCoords == null
304 || chunkAtCoords.State < TerrainChunkState.InvalidLight) {
305 num2++;
306 }
307 else {
308 num++;
309 }
310 }
311 }
312 }
313 return num2 <= 0 ? 1f : num / (float)(num2 + num);
314 }
315 return 0f;
316 }
317
318 public virtual void Update() {
319 if (m_subsystemSky.SkyLightValue != m_lastSkylightValue) {
320 m_lastSkylightValue = m_subsystemSky.SkyLightValue;
321 DowngradeAllChunksState(TerrainChunkState.InvalidLight, false);
322 }
323 int num = (int)MathF.Round(TemperatureCurve.Sample(m_subsystemGameInfo.WorldSettings.TimeOfYear));
324 int num2 = (int)MathF.Round(HumidityCurve.Sample(m_subsystemGameInfo.WorldSettings.TimeOfYear));
325 if (num != m_terrain.SeasonTemperature
326 || num2 != m_terrain.SeasonHumidity) {
327 m_terrain.SeasonTemperature = num;
328 m_terrain.SeasonHumidity = num2;
329 DowngradeAllChunksState(TerrainChunkState.InvalidVertices1, false);
330 }
332 if (m_task != null) {
333 m_quitUpdateThread = true;
335 m_updateEvent.Set();
336 m_task.Wait();
337 m_task = null;
338 }
339 double realTime = Time.RealTime;
341 && Time.RealTime - realTime < 0.0099999997764825821) { }
342 }
343 else if (m_task == null) {
344 m_quitUpdateThread = false;
345 m_task = Task.Run(ThreadUpdateFunction);
347 m_updateEvent.Set();
348 }
349 if (m_pendingLocations.Count > 0) {
350 m_pauseEvent.Reset();
351 if (m_updateEvent.WaitOne(0)) {
352 m_pauseEvent.Set();
353 try {
354 foreach (KeyValuePair<int, UpdateLocation?> pendingLocation in m_pendingLocations) {
355 if (pendingLocation.Value.HasValue) {
356 m_updateParameters.Locations[pendingLocation.Key] = pendingLocation.Value.Value;
357 }
358 else {
359 m_updateParameters.Locations.Remove(pendingLocation.Key);
360 }
361 }
362 if (AllocateAndFreeChunks(m_updateParameters.Locations.Values.ToArray())) {
363 m_updateParameters.Chunks = m_terrain.AllocatedChunks;
364 }
365 m_pendingLocations.Clear();
366 }
367 finally {
368 m_updateEvent.Set();
369 }
370 }
371 }
372 if (Monitor.TryEnter(m_updateParametersLock, 0)) {
373 try {
376 }
377 }
378 finally {
380 }
381 }
382 TerrainChunk[] allocatedChunks = m_terrain.AllocatedChunks;
383 foreach (TerrainChunk terrainChunk in allocatedChunks) {
384 if (terrainChunk.State >= TerrainChunkState.InvalidVertices1
385 && !terrainChunk.AreBehaviorsNotified) {
386 terrainChunk.AreBehaviorsNotified = true;
387 NotifyBlockBehaviors(terrainChunk);
388 }
389 }
390 }
391
392 public virtual void PrepareForDrawing(Camera camera) {
395 List<TerrainChunk> list = DetermineSynchronousUpdateChunks(camera.ViewPosition, camera.ViewDirection);
396 if (list.Count > 0) {
397 m_updateEvent.WaitOne();
398 try {
401 foreach (TerrainChunk item in list) {
402 while (item.ThreadState < TerrainChunkState.Valid) {
403 UpdateChunkSingleStep(item, m_subsystemSky.SkyLightValue);
404 }
405 }
408 }
409 finally {
410 m_updateEvent.Set();
411 }
412 }
413 }
414 }
415
416 public virtual void DowngradeChunkNeighborhoodState(Point2 coordinates, int radius, TerrainChunkState state, bool forceGeometryRegeneration) {
417 for (int i = -radius; i <= radius; i++) {
418 for (int j = -radius; j <= radius; j++) {
419 TerrainChunk chunkAtCoords = m_terrain.GetChunkAtCoords(coordinates.X + i, coordinates.Y + j);
420 if (chunkAtCoords == null) {
421 continue;
422 }
423 if (chunkAtCoords.State > state) {
424 chunkAtCoords.State = state;
425 if (forceGeometryRegeneration) {
426 chunkAtCoords.InvalidateSliceContentsHashes();
427 }
428 }
429 chunkAtCoords.WasDowngraded = true;
430 }
431 }
432 }
433
434 public virtual void DowngradeAllChunksState(TerrainChunkState state, bool forceGeometryRegeneration) {
435 TerrainChunk[] allocatedChunks = m_terrain.AllocatedChunks;
436 foreach (TerrainChunk terrainChunk in allocatedChunks) {
437 if (terrainChunk.State > state) {
438 terrainChunk.State = state;
439 if (forceGeometryRegeneration) {
440 terrainChunk.InvalidateSliceContentsHashes();
441 }
442 }
443 terrainChunk.WasDowngraded = true;
444 }
445 }
446
447 public static bool IsChunkInRange(Vector2 chunkCenter, ref UpdateLocation location) =>
448 Vector2.DistanceSquared(location.Center, chunkCenter) <= (double)MathUtils.Sqr(location.ContentDistance);
449
450 public static bool IsChunkInRange(Vector2 chunkCenter, UpdateLocation[] locations) {
451 for (int i = 0; i < locations.Length; i++) {
452 if (IsChunkInRange(chunkCenter, ref locations[i])) {
453 return true;
454 }
455 }
456 return false;
457 }
458
459 public virtual bool AllocateAndFreeChunks(UpdateLocation[] locations) {
460 bool result = false;
461 TerrainChunk[] allocatedChunks = m_terrain.AllocatedChunks;
462 foreach (TerrainChunk terrainChunk in allocatedChunks) {
463 if (!IsChunkInRange(terrainChunk.Center, locations)) {
464 bool noToFree = false;
466 "ToFreeChunks",
467 modLoader => {
468 modLoader.ToFreeChunks(this, terrainChunk, out bool keepWorking);
469 noToFree |= keepWorking;
470 return false;
471 }
472 );
473 if (noToFree) {
474 continue;
475 }
476 result = true;
477 foreach (SubsystemBlockBehavior blockBehavior in m_subsystemBlockBehaviors.BlockBehaviors) {
478 blockBehavior.OnChunkDiscarding(terrainChunk);
479 }
480 m_subsystemTerrain.TerrainSerializer.SaveChunk(terrainChunk);
481 m_terrain.FreeChunk(terrainChunk);
482 }
483 }
484 for (int j = 0; j < locations.Length; j++) {
485 Point2 point = Terrain.ToChunk(locations[j].Center - new Vector2(locations[j].ContentDistance));
486 Point2 point2 = Terrain.ToChunk(locations[j].Center + new Vector2(locations[j].ContentDistance));
487 for (int k = point.X; k <= point2.X; k++) {
488 for (int l = point.Y; l <= point2.Y; l++) {
489 Vector2 chunkCenter = new((k + 0.5f) * TerrainChunk.Size, (l + 0.5f) * TerrainChunk.Size);
490 TerrainChunk chunkAtCoords = m_terrain.GetChunkAtCoords(k, l);
491 if (chunkAtCoords == null) {
492 if (IsChunkInRange(chunkCenter, ref locations[j])) {
493 result = true;
494 m_terrain.AllocateChunk(k, l);
495 DowngradeChunkNeighborhoodState(new Point2(k, l), 0, TerrainChunkState.NotLoaded, false);
496 DowngradeChunkNeighborhoodState(new Point2(k, l), 1, TerrainChunkState.InvalidLight, false);
497 }
498 }
499 else if (chunkAtCoords.Coords.X != k
500 || chunkAtCoords.Coords.Y != l) {
501 Log.Error("Chunk wraparound detected at {0}", chunkAtCoords.Coords);
502 }
503 }
504 }
505 }
507 "ToAllocateChunks",
508 modLoader => {
509 bool modification = modLoader.ToAllocateChunks(this, locations);
510 result |= modification;
511 return false;
512 }
513 );
514 return result;
515 }
516
517 public virtual bool SendReceiveChunkStates() {
518 bool result = false;
519 TerrainChunk[] chunks = m_updateParameters.Chunks;
520 foreach (TerrainChunk terrainChunk in chunks) {
521 if (terrainChunk.WasDowngraded) {
522 terrainChunk.DowngradedState = terrainChunk.State;
523 terrainChunk.WasDowngraded = false;
524 result = true;
525 }
526 else if (terrainChunk.UpgradedState.HasValue) {
527 terrainChunk.State = terrainChunk.UpgradedState.Value;
528 }
529 terrainChunk.UpgradedState = null;
530 }
531 return result;
532 }
533
534 public virtual void SendReceiveChunkStatesThread() {
535 TerrainChunk[] chunks = m_threadUpdateParameters.Chunks;
536 foreach (TerrainChunk terrainChunk in chunks) {
537 if (terrainChunk.DowngradedState.HasValue) {
538 terrainChunk.ThreadState = terrainChunk.DowngradedState.Value;
539 terrainChunk.DowngradedState = null;
540 }
541 else if (terrainChunk.WasUpgraded) {
542 terrainChunk.UpgradedState = terrainChunk.ThreadState;
543 }
544 terrainChunk.WasUpgraded = false;
545 }
546 }
547
548 public virtual void ThreadUpdateFunction() {
549 while (!m_quitUpdateThread) {
550 m_pauseEvent.WaitOne();
551 m_updateEvent.WaitOne();
552 try {
554 lock (m_unpauseLock) {
556 m_pauseEvent.Reset();
557 }
558 m_unpauseUpdateThread = false;
559 }
560 }
561 }
562 catch (Exception e) {
563 Log.Error(e.ToString());
564 }
565 finally {
566 m_updateEvent.Set();
567 }
568 }
569 }
570
571 public virtual bool SynchronousUpdateFunction() {
575 }
576 TerrainChunk terrainChunk = FindBestChunkToUpdate(out TerrainChunkState desiredState);
577 if (terrainChunk != null) {
578 double realTime = Time.RealTime;
579 do {
580 UpdateChunkSingleStep(terrainChunk, m_subsystemSky.SkyLightValue);
581 }
582 while (terrainChunk.ThreadState < desiredState
583 && Time.RealTime - realTime < 0.01);
584 return false;
585 }
587 m_statistics.Log();
589 }
590 return true;
591 }
592
593 public virtual TerrainChunk FindBestChunkToUpdate(out TerrainChunkState desiredState) {
594 double realTime = Time.RealTime;
595 TerrainChunk[] chunks = m_threadUpdateParameters.Chunks;
596 UpdateLocation[] array = m_threadUpdateParameters.Locations.Values.ToArray();
597 float num = float.MaxValue;
598 TerrainChunk result = null;
599 desiredState = TerrainChunkState.NotLoaded;
600 foreach (TerrainChunk terrainChunk in chunks) {
601 if (terrainChunk.ThreadState >= TerrainChunkState.Valid) {
602 continue;
603 }
604 for (int j = 0; j < array.Length; j++) {
605 float num2 = Vector2.DistanceSquared(array[j].Center, terrainChunk.Center);
606 if (num2 < num) {
607 if (num2 <= MathUtils.Sqr(array[j].VisibilityDistance)) {
608 desiredState = TerrainChunkState.Valid;
609 num = num2;
610 result = terrainChunk;
611 }
612 else if (terrainChunk.ThreadState < TerrainChunkState.InvalidVertices1
613 && num2 <= MathUtils.Sqr(array[j].ContentDistance)) {
614 desiredState = TerrainChunkState.InvalidVertices1;
615 num = num2;
616 result = terrainChunk;
617 }
618 }
619 }
620 }
621 double realTime2 = Time.RealTime;
622 m_statistics.FindBestChunkTime += realTime2 - realTime;
623 m_statistics.FindBestChunkCount++;
624 return result;
625 }
626
627 public virtual List<TerrainChunk> DetermineSynchronousUpdateChunks(Vector3 viewPosition, Vector3 viewDirection) {
628 Vector3 vector = Vector3.Normalize(Vector3.Cross(viewDirection, Vector3.UnitY));
629 Vector3 v = Vector3.Normalize(Vector3.Cross(viewDirection, vector));
630 Vector3[] obj = [
631 viewPosition,
632 viewPosition + 6f * viewDirection,
633 viewPosition + 6f * viewDirection - 6f * vector,
634 viewPosition + 6f * viewDirection + 6f * vector,
635 viewPosition + 6f * viewDirection - 2f * v,
636 viewPosition + 6f * viewDirection + 2f * v
637 ];
638 List<TerrainChunk> list = [];
639 Vector3[] array = obj;
640 foreach (Vector3 vector2 in array) {
641 TerrainChunk chunkAtCell = m_terrain.GetChunkAtCell(Terrain.ToCell(vector2.X), Terrain.ToCell(vector2.Z));
642 if (chunkAtCell != null
643 && chunkAtCell.State < TerrainChunkState.Valid
644 && !list.Contains(chunkAtCell)) {
645 list.Add(chunkAtCell);
646 }
647 }
648 return list;
649 }
650
651 public virtual void UpdateChunkSingleStep(TerrainChunk chunk, int skylightValue) {
652 switch (chunk.ThreadState) {
653 case TerrainChunkState.NotLoaded: {
654 double realTime19 = Time.RealTime;
655 if (m_subsystemTerrain.TerrainSerializer.LoadChunk(chunk)) {
656 chunk.ThreadState = TerrainChunkState.InvalidLight;
657 chunk.WasUpgraded = true;
658 double realTime20 = Time.RealTime;
659 chunk.IsLoaded = true;
660 m_statistics.LoadingCount++;
661 m_statistics.LoadingTime += realTime20 - realTime19;
662 }
663 else {
664 chunk.ThreadState = TerrainChunkState.InvalidContents1;
665 chunk.WasUpgraded = true;
666 }
667 break;
668 }
669 case TerrainChunkState.InvalidContents1: {
670 double realTime17 = Time.RealTime;
671 m_subsystemTerrain.TerrainContentsGenerator.GenerateChunkContentsPass1(chunk);
672 chunk.ThreadState = TerrainChunkState.InvalidContents2;
673 chunk.WasUpgraded = true;
674 double realTime18 = Time.RealTime;
675 m_statistics.ContentsCount1++;
676 m_statistics.ContentsTime1 += realTime18 - realTime17;
677 break;
678 }
679 case TerrainChunkState.InvalidContents2: {
680 double realTime15 = Time.RealTime;
681 m_subsystemTerrain.TerrainContentsGenerator.GenerateChunkContentsPass2(chunk);
682 chunk.ThreadState = TerrainChunkState.InvalidContents3;
683 chunk.WasUpgraded = true;
684 double realTime16 = Time.RealTime;
685 m_statistics.ContentsCount2++;
686 m_statistics.ContentsTime2 += realTime16 - realTime15;
687 break;
688 }
689 case TerrainChunkState.InvalidContents3: {
690 double realTime13 = Time.RealTime;
691 m_subsystemTerrain.TerrainContentsGenerator.GenerateChunkContentsPass3(chunk);
692 chunk.ThreadState = TerrainChunkState.InvalidContents4;
693 chunk.WasUpgraded = true;
694 double realTime14 = Time.RealTime;
695 m_statistics.ContentsCount3++;
696 m_statistics.ContentsTime3 += realTime14 - realTime13;
697 break;
698 }
699 case TerrainChunkState.InvalidContents4: {
700 double realTime7 = Time.RealTime;
701 m_subsystemTerrain.TerrainContentsGenerator.GenerateChunkContentsPass4(chunk);
703 "OnTerrainContentsGenerated",
704 modLoader => {
705 modLoader.OnTerrainContentsGenerated(chunk);
706 return false;
707 }
708 );
709 chunk.ThreadState = TerrainChunkState.InvalidLight;
710 chunk.WasUpgraded = true;
711 double realTime8 = Time.RealTime;
712 m_statistics.ContentsCount4++;
713 m_statistics.ContentsTime4 += realTime8 - realTime7;
714 break;
715 }
716 case TerrainChunkState.InvalidLight: {
717 double realTime3 = Time.RealTime;
718 GenerateChunkSunLightAndHeight(chunk, skylightValue);
719 chunk.ThreadState = TerrainChunkState.InvalidPropagatedLight;
720 chunk.WasUpgraded = true;
721 double realTime4 = Time.RealTime;
722 m_statistics.LightCount++;
723 m_statistics.LightTime += realTime4 - realTime3;
724 break;
725 }
726 case TerrainChunkState.InvalidPropagatedLight: {
727 for (int i = -1; i <= 1; i++) {
728 for (int j = -1; j <= 1; j++) {
729 TerrainChunk chunkAtCoords = m_terrain.GetChunkAtCoords(chunk.Coords.X + i, chunk.Coords.Y + j);
730 if (chunkAtCoords != null
731 && chunkAtCoords.ThreadState < TerrainChunkState.InvalidPropagatedLight) {
732 UpdateChunkSingleStep(chunkAtCoords, skylightValue);
733 return;
734 }
735 }
736 }
737 double realTime9 = Time.RealTime;
738 m_lightSources.Count = 0;
744 double realTime10 = Time.RealTime;
745 m_statistics.LightSourcesCount++;
746 m_statistics.LightSourcesTime += realTime10 - realTime9;
747 double realTime11 = Time.RealTime;
749 chunk.ThreadState = TerrainChunkState.InvalidVertices1;
750 chunk.WasUpgraded = true;
751 double realTime12 = Time.RealTime;
752 m_statistics.LightPropagateCount++;
753 m_statistics.LightSourceInstancesCount += m_lightSources.Count;
754 m_statistics.LightPropagateTime += realTime12 - realTime11;
755 break;
756 }
757 case TerrainChunkState.InvalidVertices1: {
758 for (int k = -1; k <= 1; k++) {
759 for (int l = -1; l <= 1; l++) {
760 TerrainChunk chunkAtCoords2 = m_terrain.GetChunkAtCoords(chunk.Coords.X + k, chunk.Coords.Y + l);
761 if (chunkAtCoords2 != null
762 && chunkAtCoords2.ThreadState < TerrainChunkState.InvalidVertices1) {
763 UpdateChunkSingleStep(chunkAtCoords2, skylightValue);
764 return;
765 }
766 }
767 }
769 double realTime5 = Time.RealTime;
770 lock (chunk.Geometry) {
771 chunk.NewGeometryData = false;
772 GenerateChunkVertices(chunk, 0);
774 "GenerateChunkVertices",
775 modLoader => {
776 modLoader.GenerateChunkVertices(chunk, true);
777 return true;
778 }
779 );
780 }
781 chunk.ThreadState = TerrainChunkState.InvalidVertices2;
782 chunk.WasUpgraded = true;
783 double realTime6 = Time.RealTime;
784 m_statistics.VerticesCount1++;
785 m_statistics.VerticesTime1 += realTime6 - realTime5;
786 break;
787 }
788 case TerrainChunkState.InvalidVertices2: {
789 double realTime = Time.RealTime;
790 lock (chunk.Geometry) {
791 GenerateChunkVertices(chunk, 1);
793 "GenerateChunkVertices",
794 modLoader => {
795 modLoader.GenerateChunkVertices(chunk, true);
796 return false;
797 }
798 );
799 chunk.NewGeometryData = true;
800 }
801 chunk.ThreadState = TerrainChunkState.Valid;
802 chunk.WasUpgraded = true;
803 double realTime2 = Time.RealTime;
804 ChunkUpdates++;
805 m_statistics.VerticesCount2++;
806 m_statistics.VerticesTime2 += realTime2 - realTime;
807 break;
808 }
809 }
810 }
811
812 public virtual void GenerateChunkSunLightAndHeight(TerrainChunk chunk, int skylightValue) {
813 for (int i = 0; i < TerrainChunk.Size; i++) {
814 for (int j = 0; j < TerrainChunk.Size; j++) {
815 int num = 0;
816 int num2 = TerrainChunk.HeightMinusOne;
817 int num4 = TerrainChunk.HeightMinusOne;
819 while (num4 >= 0) {
820 int cellValueFast = chunk.GetCellValueFast(num5);
821 if (Terrain.ExtractContents(cellValueFast) != 0) {
822 num = num4;
823 break;
824 }
825 cellValueFast = Terrain.ReplaceLight(cellValueFast, skylightValue);
826 chunk.SetCellValueFast(num5, cellValueFast);
827 num4--;
828 num5--;
829 }
830 num4 = 0;
831 num5 = TerrainChunk.CalculateCellIndex(i, 0, j);
832 while (num4 <= num + 1) {
833 int cellValueFast2 = chunk.GetCellValueFast(num5);
834 int num6 = Terrain.ExtractContents(cellValueFast2);
835 if (BlocksManager.Blocks[num6].IsTransparent_(cellValueFast2)) {
836 num2 = num4;
837 break;
838 }
839 cellValueFast2 = Terrain.ReplaceLight(cellValueFast2, 0);
840 chunk.SetCellValueFast(num5, cellValueFast2);
841 num4++;
842 num5++;
843 }
844 int num7 = skylightValue;
845 num4 = num;
846 num5 = TerrainChunk.CalculateCellIndex(i, num, j);
847 if (num7 > 0) {
848 while (num4 >= num2) {
849 int cellValueFast3 = chunk.GetCellValueFast(num5);
850 int num8 = Terrain.ExtractContents(cellValueFast3);
851 if (num8 != 0) {
852 Block block = BlocksManager.Blocks[num8];
853 if (!block.IsTransparent_(cellValueFast3)
854 || block.LightAttenuation >= num7) {
855 break;
856 }
857 num7 -= block.LightAttenuation;
858 }
859 cellValueFast3 = Terrain.ReplaceLight(cellValueFast3, num7);
860 chunk.SetCellValueFast(num5, cellValueFast3);
861 num4--;
862 num5--;
863 }
864 }
865 int num3 = num4 + 1;
866 while (num4 >= num2) {
867 int cellValueFast4 = chunk.GetCellValueFast(num5);
868 cellValueFast4 = Terrain.ReplaceLight(cellValueFast4, 0);
869 chunk.SetCellValueFast(num5, cellValueFast4);
870 num4--;
871 num5--;
872 }
873 chunk.SetTopHeightFast(i, j, num);
874 chunk.SetBottomHeightFast(i, j, num2);
875 chunk.SetSunlightHeightFast(i, j, num3);
876 }
877 }
878 }
879
880 public virtual void GenerateChunkLightSources(TerrainChunk chunk) {
882 "GenerateChunkLightSources",
883 loader => {
884 loader.GenerateChunkLightSources(m_lightSources, chunk);
885 return false;
886 }
887 );
888 Block[] blocks = BlocksManager.Blocks;
889 for (int i = 0; i < TerrainChunk.Size; i++) {
890 for (int j = 0; j < TerrainChunk.Size; j++) {
891 int topHeightFast = chunk.GetTopHeightFast(i, j);
892 int bottomHeightFast = chunk.GetBottomHeightFast(i, j);
893 int num = i + chunk.Origin.X;
894 int num2 = j + chunk.Origin.Y;
895 int k = bottomHeightFast;
896 int num3 = TerrainChunk.CalculateCellIndex(i, bottomHeightFast, j);
897 while (k <= topHeightFast) {
898 int cellValueFast = chunk.GetCellValueFast(num3);
899 Block block = blocks[Terrain.ExtractContents(cellValueFast)];
900 if (block.DefaultEmittedLightAmount > 0) {
901 int emittedLightAmount = block.GetEmittedLightAmount(cellValueFast);
902 if (emittedLightAmount > Terrain.ExtractLight(cellValueFast)) {
903 chunk.SetCellValueFast(num3, Terrain.ReplaceLight(cellValueFast, emittedLightAmount));
904 if (emittedLightAmount > 1) {
905 m_lightSources.Add(new LightSource { X = num, Y = k, Z = num2, Light = emittedLightAmount });
906 }
907 }
908 }
909 k++;
910 num3++;
911 }
912 TerrainChunk chunkAtCell = m_terrain.GetChunkAtCell(num - 1, num2);
913 TerrainChunk chunkAtCell2 = m_terrain.GetChunkAtCell(num + 1, num2);
914 TerrainChunk chunkAtCell3 = m_terrain.GetChunkAtCell(num, num2 - 1);
915 TerrainChunk chunkAtCell4 = m_terrain.GetChunkAtCell(num, num2 + 1);
916 if (chunkAtCell != null
917 && chunkAtCell2 != null
918 && chunkAtCell3 != null
919 && chunkAtCell4 != null) {
920 int num4 = num - 1 - chunkAtCell.Origin.X;
921 int num5 = num2 - chunkAtCell.Origin.Y;
922 int num6 = num + 1 - chunkAtCell2.Origin.X;
923 int num7 = num2 - chunkAtCell2.Origin.Y;
924 int num8 = num - chunkAtCell3.Origin.X;
925 int num9 = num2 - 1 - chunkAtCell3.Origin.Y;
926 int num10 = num - chunkAtCell4.Origin.X;
927 int num11 = num2 + 1 - chunkAtCell4.Origin.Y;
928 int num12 = Terrain.ExtractSunlightHeight(chunkAtCell.GetShaftValueFast(num4, num5));
929 int num13 = Terrain.ExtractSunlightHeight(chunkAtCell2.GetShaftValueFast(num6, num7));
930 int num14 = Terrain.ExtractSunlightHeight(chunkAtCell3.GetShaftValueFast(num8, num9));
931 int num15 = Terrain.ExtractSunlightHeight(chunkAtCell4.GetShaftValueFast(num10, num11));
932 int num16 = MathUtils.Min(num12, num13, num14, num15);
933 int l = num16;
934 int num17 = TerrainChunk.CalculateCellIndex(i, num16, j);
935 while (l <= topHeightFast) {
936 int cellValueFast2 = chunk.GetCellValueFast(num17);
937 Block block2 = blocks[Terrain.ExtractContents(cellValueFast2)];
938 if (block2.IsTransparent_(cellValueFast2)) {
939 int cellLightFast = chunkAtCell.GetCellLightFast(num4, l, num5);
940 int cellLightFast2 = chunkAtCell2.GetCellLightFast(num6, l, num7);
941 int cellLightFast3 = chunkAtCell3.GetCellLightFast(num8, l, num9);
942 int cellLightFast4 = chunkAtCell4.GetCellLightFast(num10, l, num11);
943 int num18 = MathUtils.Max(cellLightFast, cellLightFast2, cellLightFast3, cellLightFast4)
945 - block2.LightAttenuation;
946 if (num18 > Terrain.ExtractLight(cellValueFast2)) {
947 chunk.SetCellValueFast(num17, Terrain.ReplaceLight(cellValueFast2, num18));
948 if (num18 > 1) {
949 m_lightSources.Add(new LightSource { X = num, Y = l, Z = num2, Light = num18 });
950 }
951 }
952 }
953 l++;
954 num17++;
955 }
956 }
957 }
958 }
959 }
960
961 public virtual void GenerateChunkEdgeLightSources(TerrainChunk chunk, int face) {
962 Block[] blocks = BlocksManager.Blocks;
963 int num = 0;
964 int num2 = 0;
965 int num3 = 0;
966 int num4 = 0;
967 TerrainChunk terrainChunk;
968 switch (face) {
969 case 0:
970 terrainChunk = chunk.Terrain.GetChunkAtCoords(chunk.Coords.X, chunk.Coords.Y + 1);
972 num4 = 0;
973 break;
974 case 1:
975 terrainChunk = chunk.Terrain.GetChunkAtCoords(chunk.Coords.X + 1, chunk.Coords.Y);
977 num3 = 0;
978 break;
979 case 2:
980 terrainChunk = chunk.Terrain.GetChunkAtCoords(chunk.Coords.X, chunk.Coords.Y - 1);
981 num2 = 0;
983 break;
984 default:
985 terrainChunk = chunk.Terrain.GetChunkAtCoords(chunk.Coords.X - 1, chunk.Coords.Y);
986 num = 0;
988 break;
989 }
990 if (terrainChunk == null
991 || terrainChunk.ThreadState < TerrainChunkState.InvalidPropagatedLight) {
992 return;
993 }
994 for (int i = 0; i < TerrainChunk.Size; i++) {
995 switch (face) {
996 case 0:
997 num = i;
998 num3 = i;
999 break;
1000 case 1:
1001 num2 = i;
1002 num4 = i;
1003 break;
1004 case 2:
1005 num = i;
1006 num3 = i;
1007 break;
1008 default:
1009 num2 = i;
1010 num4 = i;
1011 break;
1012 }
1013 int num5 = num + chunk.Origin.X;
1014 int num6 = num2 + chunk.Origin.Y;
1015 int bottomHeightFast = chunk.GetBottomHeightFast(num, num2);
1016 int num7 = TerrainChunk.CalculateCellIndex(num, 0, num2);
1017 int num8 = TerrainChunk.CalculateCellIndex(num3, 0, num4);
1018 for (int j = bottomHeightFast; j < TerrainChunk.Height; j++) {
1019 int cellValueFast = chunk.GetCellValueFast(num7 + j);
1020 int num9 = Terrain.ExtractContents(cellValueFast);
1021 if (blocks[num9].IsTransparent_(cellValueFast)) {
1022 int num10 = Terrain.ExtractLight(cellValueFast);
1023 int num11 = Terrain.ExtractLight(terrainChunk.GetCellValueFast(num8 + j)) - 1;
1024 if (num11 > num10) {
1025 chunk.SetCellValueFast(num7 + j, Terrain.ReplaceLight(cellValueFast, num11));
1026 if (num11 > 1) {
1027 m_lightSources.Add(new LightSource { X = num5, Y = j, Z = num6, Light = num11 });
1028 }
1029 }
1030 }
1031 }
1032 }
1033 }
1034
1035 public virtual void PropagateLightSource(int x, int y, int z, int light) {
1036 TerrainChunk chunkAtCell = m_terrain.GetChunkAtCell(x, z);
1037 if (chunkAtCell == null) {
1038 return;
1039 }
1040 int index = TerrainChunk.CalculateCellIndex(x & 0xF, y, z & 0xF);
1041 int cellValueFast = chunkAtCell.GetCellValueFast(index);
1042 int num = Terrain.ExtractContents(cellValueFast);
1043 Block block = BlocksManager.Blocks[num];
1044 if (block.IsTransparent_(cellValueFast)) {
1045 int num2 = light - block.LightAttenuation - m_lightAttenuationWithDistance;
1046 if (num2 > Terrain.ExtractLight(cellValueFast)) {
1047 m_lightSources.Add(new LightSource { X = x, Y = y, Z = z, Light = num2 });
1048 chunkAtCell.SetCellValueFast(index, Terrain.ReplaceLight(cellValueFast, num2));
1049 }
1050 }
1051 }
1052
1053 public virtual void PropagateLightSources() {
1054 for (int i = 0; i < m_lightSources.Count && i < 120000; i++) {
1055 LightSource lightSource = m_lightSources.Array[i];
1056 int light = lightSource.Light;
1057 if (light > 1) {
1058 PropagateLightSource(lightSource.X - 1, lightSource.Y, lightSource.Z, light);
1059 PropagateLightSource(lightSource.X + 1, lightSource.Y, lightSource.Z, light);
1060 if (lightSource.Y > 0) {
1061 PropagateLightSource(lightSource.X, lightSource.Y - 1, lightSource.Z, light);
1062 }
1063 if (lightSource.Y < TerrainChunk.HeightMinusOne) {
1064 PropagateLightSource(lightSource.X, lightSource.Y + 1, lightSource.Z, light);
1065 }
1066 PropagateLightSource(lightSource.X, lightSource.Y, lightSource.Z - 1, light);
1067 PropagateLightSource(lightSource.X, lightSource.Y, lightSource.Z + 1, light);
1068 }
1069 }
1070 for (int i = 0; i < m_lightSources.Count && i < 120000; i++) {
1071 LightSource lightSource = m_lightSources.Array[i];
1072 int light = lightSource.Light;
1073 int x = lightSource.X;
1074 int y = lightSource.Y;
1075 int z = lightSource.Z;
1076 int num2 = x & TerrainChunk.SizeMinusOne;
1077 int num3 = z & TerrainChunk.SizeMinusOne;
1078 TerrainChunk chunkAtCell = m_terrain.GetChunkAtCell(x, z);
1079 if (num2 == 0) {
1080 PropagateLightSource(m_terrain.GetChunkAtCell(x - 1, z), x - 1, y, z, light);
1081 }
1082 else {
1083 PropagateLightSource(chunkAtCell, x - 1, y, z, light);
1084 }
1085 if (num2 == TerrainChunk.SizeMinusOne) {
1086 PropagateLightSource(m_terrain.GetChunkAtCell(x + 1, z), x + 1, y, z, light);
1087 }
1088 else {
1089 PropagateLightSource(chunkAtCell, x + 1, y, z, light);
1090 }
1091 if (num3 == 0) {
1092 PropagateLightSource(m_terrain.GetChunkAtCell(x, z - 1), x, y, z - 1, light);
1093 }
1094 else {
1095 PropagateLightSource(chunkAtCell, x, y, z - 1, light);
1096 }
1097 if (num3 == TerrainChunk.SizeMinusOne) {
1098 PropagateLightSource(m_terrain.GetChunkAtCell(x, z + 1), x, y, z + 1, light);
1099 }
1100 else {
1101 PropagateLightSource(chunkAtCell, x, y, z + 1, light);
1102 }
1103 if (y > 0) {
1104 PropagateLightSource(chunkAtCell, x, y - 1, z, light);
1105 }
1106 if (y < TerrainChunk.HeightMinusOne) {
1107 PropagateLightSource(chunkAtCell, x, y + 1, z, light);
1108 }
1109 }
1110 }
1111
1112 [MethodImpl(256)]
1113 public virtual void PropagateLightSource(TerrainChunk chunk, int x, int y, int z, int light) {
1114 if (chunk != null) {
1116 int cellValueFast = chunk.GetCellValueFast(num);
1117 int num2 = Terrain.ExtractContents(cellValueFast);
1118 Block block = BlocksManager.Blocks[num2];
1119 if (block.IsTransparent_(cellValueFast)) {
1120 int num3 = light - block.LightAttenuation - m_lightAttenuationWithDistance;
1121 if (num3 > Terrain.ExtractLight(cellValueFast)) {
1122 if (num3 > 1) {
1123 m_lightSources.Add(new LightSource { X = x, Y = y, Z = z, Light = num3 });
1124 }
1125 chunk.SetCellValueFast(num, Terrain.ReplaceLight(cellValueFast, num3));
1126 }
1127 }
1128 }
1129 }
1130
1131 public virtual void GenerateChunkVertices(TerrainChunk chunk, int stage) {
1132 m_subsystemTerrain.BlockGeometryGenerator.ResetCache();
1133 TerrainChunk chunkAtCoords1 = m_terrain.GetChunkAtCoords(chunk.Coords.X - 1, chunk.Coords.Y - 1);
1134 TerrainChunk chunkAtCoords2 = m_terrain.GetChunkAtCoords(chunk.Coords.X, chunk.Coords.Y - 1);
1135 TerrainChunk chunkAtCoords3 = m_terrain.GetChunkAtCoords(chunk.Coords.X + 1, chunk.Coords.Y - 1);
1136 TerrainChunk chunkAtCoords4 = m_terrain.GetChunkAtCoords(chunk.Coords.X - 1, chunk.Coords.Y);
1137 TerrainChunk chunkAtCoords5 = m_terrain.GetChunkAtCoords(chunk.Coords.X + 1, chunk.Coords.Y);
1138 TerrainChunk chunkAtCoords6 = m_terrain.GetChunkAtCoords(chunk.Coords.X - 1, chunk.Coords.Y + 1);
1139 TerrainChunk chunkAtCoords7 = m_terrain.GetChunkAtCoords(chunk.Coords.X, chunk.Coords.Y + 1);
1140 TerrainChunk chunkAtCoords8 = m_terrain.GetChunkAtCoords(chunk.Coords.X + 1, chunk.Coords.Y + 1);
1141 int num1 = 0;
1142 int num2 = 0;
1143 int num3 = TerrainChunk.Size;
1144 int num4 = TerrainChunk.Size;
1145 if (chunkAtCoords4 == null) {
1146 ++num1;
1147 }
1148 if (chunkAtCoords2 == null) {
1149 ++num2;
1150 }
1151 if (chunkAtCoords5 == null) {
1152 --num3;
1153 }
1154 if (chunkAtCoords7 == null) {
1155 --num4;
1156 }
1157 for (int index = 0; index < TerrainChunk.SlicesCount; ++index) {
1158 if (index % 2 == stage) {
1159 int generateHash = chunk.GeneratedSliceContentsHashes[index];
1160 if (generateHash != 0
1161 && generateHash == chunk.SliceContentsHashes[index]) {
1162 m_statistics.SkippedSlices++;
1163 continue;
1164 }
1165 chunk.GeneratedSliceContentsHashes[index] = 0;
1166 ++m_statistics.GeneratedSlices;
1167 TerrainGeometry geometry = chunk.ChunkSliceGeometries[index];
1168 if (geometry == null) {
1169 geometry = new TerrainGeometry(m_subsystemAnimatedTextures.AnimatedBlocksTexture);
1170 chunk.ChunkSliceGeometries[index] = geometry;
1171 }
1172 geometry.ClearGeometry();
1173 for (int x1 = num1; x1 < num3; ++x1) {
1174 for (int z1 = num2; z1 < num4; ++z1) {
1175 switch (x1) {
1176 case 0:
1177 if ((z1 == 0 && chunkAtCoords1 == null)
1178 || (z1 == TerrainChunk.SizeMinusOne && chunkAtCoords6 == null)) {
1179 break;
1180 }
1181 goto default;
1183 if ((z1 == 0 && chunkAtCoords3 == null)
1184 || (z1 == TerrainChunk.SizeMinusOne && chunkAtCoords8 == null)) {
1185 break;
1186 }
1187 goto default;
1188 default:
1189 int x2 = x1 + chunk.Origin.X;
1190 int z2 = z1 + chunk.Origin.Y;
1191 int x2_1 = MathUtils.Min(
1192 chunk.GetBottomHeightFast(x1, z1) - 1,
1193 MathUtils.Min(
1194 m_terrain.GetBottomHeight(x2 - 1, z2),
1195 m_terrain.GetBottomHeight(x2 + 1, z2),
1196 m_terrain.GetBottomHeight(x2, z2 - 1),
1197 m_terrain.GetBottomHeight(x2, z2 + 1)
1198 )
1199 );
1200 int x2_2 = chunk.GetTopHeightFast(x1, z1) + 1;
1201 int num5 = MathUtils.Max(TerrainChunk.SliceHeight * index, x2_1, 1);
1202 int num6 = MathUtils.Min(TerrainChunk.SliceHeight * (index + 1), x2_2, byte.MaxValue);
1203 int cellIndex = TerrainChunk.CalculateCellIndex(x1, 0, z1);
1204 for (int y = num5; y < num6; ++y) {
1205 int cellValueFast = chunk.GetCellValueFast(cellIndex + y);
1206 int contents = Terrain.ExtractContents(cellValueFast);
1207 if (contents != 0) {
1208 BlocksManager.Blocks[contents]
1210 m_subsystemTerrain.BlockGeometryGenerator,
1211 geometry,
1212 cellValueFast,
1213 x2,
1214 y,
1215 z2
1216 );
1217 }
1218 }
1219 break;
1220 }
1221 }
1222 }
1223 chunk.GeneratedSliceContentsHashes[index] = chunk.SliceContentsHashes[index];
1224 }
1225 }
1226 }
1227
1229 double realTime = Time.RealTime;
1230 int hash1 = 1;
1231 hash1 += m_terrain.SeasonTemperature;
1232 hash1 *= 31;
1233 hash1 += m_terrain.SeasonHumidity;
1234 hash1 *= 31;
1235 for (int i = 0; i < TerrainChunk.SlicesCount; i++) {
1236 chunk.SliceContentsHashes[i] = hash1;
1237 }
1238 int startOriginX = chunk.Origin.X - 1;
1239 int endOriginX = chunk.Origin.X + TerrainChunk.Size + 1;
1240 int startOriginY = chunk.Origin.Y - 1;
1241 int endOriginY = chunk.Origin.Y + TerrainChunk.Size + 1;
1242 for (int originX = startOriginX; originX < endOriginX; originX++) {
1243 for (int originY = startOriginY; originY < endOriginY; originY++) {
1244 TerrainChunk chunkAtCell = m_terrain.GetChunkAtCell(originX, originY);
1245 if (chunkAtCell != null) {
1246 int x = originX & TerrainChunk.SizeMinusOne;
1247 int z = originY & TerrainChunk.SizeMinusOne;
1248 int shaftValueFast = chunkAtCell.GetShaftValueFast(x, z);
1249 int topHeight = Terrain.ExtractTopHeight(shaftValueFast);
1250 int bottomHeight = Terrain.ExtractBottomHeight(shaftValueFast);
1251 int neighborBottomHeight1 = x > 0
1252 ? chunkAtCell.GetBottomHeightFast(x - 1, z)
1253 : m_terrain.GetBottomHeight(originX - 1, originY);
1254 int neighborBottomHeight2 = z > 0
1255 ? chunkAtCell.GetBottomHeightFast(x, z - 1)
1256 : m_terrain.GetBottomHeight(originX, originY - 1);
1257 int neighborBottomHeight3 = x < TerrainChunk.SizeMinusOne
1258 ? chunkAtCell.GetBottomHeightFast(x + 1, z)
1259 : m_terrain.GetBottomHeight(originX + 1, originY);
1260 int neighborBottomHeight4 = z < TerrainChunk.SizeMinusOne
1261 ? chunkAtCell.GetBottomHeightFast(x, z + 1)
1262 : m_terrain.GetBottomHeight(originX, originY + 1);
1263 int minBottomHeight = MathUtils.Min(
1264 MathUtils.Min(neighborBottomHeight1, neighborBottomHeight2, neighborBottomHeight3, neighborBottomHeight4),
1265 bottomHeight - 1
1266 );
1267 int topHeight2 = topHeight + 2;
1268 minBottomHeight = MathUtils.Max(minBottomHeight, 0);
1269 topHeight2 = MathUtils.Min(topHeight2, TerrainChunk.Height);
1270 int startSlice = MathUtils.Max((minBottomHeight - 1) / TerrainChunk.SliceHeight, 0);
1271 int endSlice = MathUtils.Min((topHeight2 + 1) / TerrainChunk.SliceHeight, TerrainChunk.SliceHeight - 1);
1272 int hash2 = 1;
1273 hash2 += Terrain.ExtractTemperature(shaftValueFast);
1274 hash2 *= 31;
1275 hash2 += Terrain.ExtractHumidity(shaftValueFast);
1276 hash2 *= 31;
1277 for (int slice = startSlice; slice <= endSlice; slice++) {
1278 int hash3 = hash2;
1279 int startY = MathUtils.Max(slice * TerrainChunk.SliceHeight - 1, minBottomHeight);
1280 int endY = MathUtils.Min(slice * TerrainChunk.SliceHeight + TerrainChunk.SliceHeight + 1, topHeight2);
1281 int cellIndex = TerrainChunk.CalculateCellIndex(x, startY, z);
1282 int endCellIndex = cellIndex + endY - startY;
1283 while (cellIndex < endCellIndex) {
1284 hash3 += chunkAtCell.GetCellValueFast(cellIndex++);
1285 hash3 *= 31;
1286 }
1287 hash3 += startY;
1288 hash3 *= 31;
1289 chunk.SliceContentsHashes[slice] += hash3;
1290 }
1291 }
1292 }
1293 }
1294 double realTime2 = Time.RealTime;
1295 m_statistics.HashCount++;
1296 m_statistics.HashTime += realTime2 - realTime;
1297 }
1298
1299 public virtual void NotifyBlockBehaviors(TerrainChunk chunk) {
1300 ChunkInitialized?.Invoke(chunk);
1301 foreach (SubsystemBlockBehavior blockBehavior in m_subsystemBlockBehaviors.BlockBehaviors) {
1302 blockBehavior.OnChunkInitialized(chunk);
1303 }
1304 bool isLoaded = chunk.IsLoaded;
1305 for (int i = 0; i < TerrainChunk.Size; i++) {
1306 for (int j = 0; j < TerrainChunk.Size; j++) {
1307 int x = i + chunk.Origin.X;
1308 int z = j + chunk.Origin.Y;
1309 int num = TerrainChunk.CalculateCellIndex(i, 0, j);
1310 int num2 = 0;
1311 while (num2 < TerrainChunk.HeightMinusOne) {
1312 int cellValueFast = chunk.GetCellValueFast(num);
1313 int contents = Terrain.ExtractContents(cellValueFast);
1314 if (contents != 0) {
1315 SubsystemBlockBehavior[] blockBehaviors = m_subsystemBlockBehaviors.GetBlockBehaviors(contents);
1316 for (int k = 0; k < blockBehaviors.Length; k++) {
1317 blockBehaviors[k].OnBlockGenerated(cellValueFast, x, num2, z, isLoaded);
1318 }
1319 }
1320 num2++;
1321 num++;
1322 }
1323 }
1324 }
1325 }
1326
1327 public virtual void UnpauseUpdateThread() {
1328 lock (m_unpauseLock) {
1329 m_unpauseUpdateThread = true;
1330 m_pauseEvent.Set();
1331 }
1332 }
1333
1334 public virtual void SettingsManager_SettingChanged(string name) {
1335 if (name == "Brightness") {
1336 DowngradeAllChunksState(TerrainChunkState.InvalidVertices1, true);
1337 }
1338 }
1339 }
1340}
Silk.NET.Windowing.Monitor Monitor
static void Error(object message)
定义 Log.cs:80
static void Information(object message)
定义 Log.cs:56
static int Min(int x1, int x2)
static int Max(int x1, int x2)
static int Sqr(int x)
static int FrameIndex
定义 Time.cs:26
static double RealTime
定义 Time.cs:38
virtual bool IsTransparent_(int value)
int LightAttenuation
int DefaultEmittedLightAmount
void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
生成地形顶点(用于绘制放置的方块)
virtual int GetEmittedLightAmount(int value)
Vector3 ViewPosition
GameWidget GameWidget
Vector3 ViewDirection
static Action< string > SettingChanged
virtual void OnChunkInitialized(TerrainChunk chunk)
virtual void OnBlockGenerated(int value, int x, int y, int z, bool isLoaded)
virtual void OnChunkDiscarding(TerrainChunk chunk)
virtual void SetSunlightHeightFast(int x, int z, int sunlightHeight)
static int CalculateCellIndex(int x, int y, int z)
TerrainChunkState? DowngradedState
TerrainChunkState State
virtual int GetCellValueFast(int index)
virtual void SetCellValueFast(int x, int y, int z, int value)
TerrainChunkState ThreadState
virtual int GetBottomHeightFast(int x, int z)
virtual int GetTopHeightFast(int x, int z)
TerrainGeometry[] ChunkSliceGeometries
TerrainChunkState? UpgradedState
virtual void SetTopHeightFast(int x, int z, int topHeight)
virtual int GetCellLightFast(int x, int y, int z)
virtual int GetShaftValueFast(int x, int z)
virtual void InvalidateSliceContentsHashes()
TerrainChunkGeometry Geometry
virtual void SetBottomHeightFast(int x, int z, int bottomHeight)
static Point2 ToChunk(Vector2 p)
static int ExtractTemperature(int value)
static int ExtractContents(int value)
static int ToCell(float x)
static int ExtractBottomHeight(int value)
static int ExtractLight(int value)
static int ExtractHumidity(int value)
static int ExtractTopHeight(int value)
virtual TerrainChunk GetChunkAtCoords(int chunkX, int chunkZ)
static int ReplaceLight(int value, int light)
static int ExtractSunlightHeight(int value)
virtual float GetUpdateProgress(int locationIndex, float visibilityDistance, float contentDistance)
TerrainUpdater(SubsystemTerrain subsystemTerrain)
ManualResetEvent m_pauseEvent
SubsystemGameInfo m_subsystemGameInfo
UpdateParameters m_updateParameters
virtual TerrainChunk FindBestChunkToUpdate(out TerrainChunkState desiredState)
virtual void PrepareForDrawing(Camera camera)
virtual void GenerateChunkVertices(TerrainChunk chunk, int stage)
virtual bool SendReceiveChunkStates()
SubsystemBlockBehaviors m_subsystemBlockBehaviors
virtual void PropagateLightSources()
virtual List< TerrainChunk > DetermineSynchronousUpdateChunks(Vector3 viewPosition, Vector3 viewDirection)
virtual bool SynchronousUpdateFunction()
Action< TerrainChunk > ChunkInitialized
SubsystemTerrain m_subsystemTerrain
virtual void NotifyBlockBehaviors(TerrainChunk chunk)
SubsystemAnimatedTextures m_subsystemAnimatedTextures
virtual void DowngradeChunkNeighborhoodState(Point2 coordinates, int radius, TerrainChunkState state, bool forceGeometryRegeneration)
virtual void PropagateLightSource(int x, int y, int z, int light)
virtual void UpdateChunkSingleStep(TerrainChunk chunk, int skylightValue)
virtual void SetUpdateLocation(int locationIndex, Vector2 center, float visibilityDistance, float contentDistance)
virtual void ThreadUpdateFunction()
SubsystemSeasons m_subsystemSeasons
static bool IsChunkInRange(Vector2 chunkCenter, UpdateLocation[] locations)
virtual void GenerateChunkLightSources(TerrainChunk chunk)
virtual void GenerateChunkSunLightAndHeight(TerrainChunk chunk, int skylightValue)
virtual void PropagateLightSource(TerrainChunk chunk, int x, int y, int z, int light)
virtual void SendReceiveChunkStatesThread()
virtual void SettingsManager_SettingChanged(string name)
virtual void CalculateChunkSliceContentsHashes(TerrainChunk chunk)
virtual void RemoveUpdateLocation(int locationIndex)
UpdateParameters m_threadUpdateParameters
UpdateStatistics m_statistics
virtual void RequestSynchronousUpdate()
static bool IsChunkInRange(Vector2 chunkCenter, ref UpdateLocation location)
Dictionary< int, UpdateLocation?> m_pendingLocations
virtual void GenerateChunkEdgeLightSources(TerrainChunk chunk, int face)
virtual void UnpauseUpdateThread()
DynamicArray< LightSource > m_lightSources
virtual bool AllocateAndFreeChunks(UpdateLocation[] locations)
virtual void DowngradeAllChunksState(TerrainChunkState state, bool forceGeometryRegeneration)
PlayerData PlayerData
static void HookAction(string HookName, Func< ModLoader, bool > action)
执行Hook
static float DistanceSquared(Vector2 v1, Vector2 v2)
static Vector3 Cross(Vector3 v1, Vector3 v2)
static Vector3 Normalize(Vector3 v)
static readonly Vector3 UnitY
Dictionary< int, UpdateLocation > Locations