Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
BlocksManager.cs
浏览该文件的文档.
1using System.Globalization;
2using System.Reflection;
3using Engine;
4using Engine.Media;
8
9namespace Game {
10 public static class BlocksManager {
11 public struct ImageExtrusionKey {
12 public Image Image;
13
14 public int Slot;
15
16 public override int GetHashCode() => Image.GetHashCode() ^ Slot.GetHashCode();
17
18 public override bool Equals(object obj) {
19 if (obj != null) {
20 ImageExtrusionKey imageExtrusionKey = (ImageExtrusionKey)obj;
21 if (imageExtrusionKey.Image == Image) {
22 return imageExtrusionKey.Slot == Slot;
23 }
24 }
25 return false;
26 }
27 }
28
29 public static Block[] m_blocks = new Block[1024];
30
31 public static FluidBlock[] m_fluidBlocks = new FluidBlock[1024];
32
33 public static List<string> m_categories = [];
34
36
37 public static Vector4[] m_slotTexCoords = new Vector4[256];
38
39 public static Dictionary<ImageExtrusionKey, BlockMesh> m_imageExtrusionsCache = [];
40
41 public static Block[] Blocks => m_blocks;
42
43 public static List<BlockAllocateData> BlocksAllocateData = new();
45
46 //将ModBlock和BlockIndex联系起来的表格。
47 public static Dictionary<string, int> BlockNameToIndex = new();
48 public static Dictionary<Type, int> BlockTypeToIndex = new();
49
50 public static ReadOnlyList<string> Categories => new(m_categories);
51
52 [Obsolete("Use BlockTypeToOriginalIndex.")]
53 public static int[] m_originalBlockIndex = new int[1024];
54
55 public static Dictionary<Type, int> BlockTypeToOriginalIndex = new();
56
57 public const int SurvivalCraftBlockCount = 299;
58
59 public static bool DrawImageExtrusionEnabled = true;
60
61 public static bool LoadBlocksStaticly = false;
62
63 public class BlockAllocateDataComparer : IComparer<BlockAllocateData> {
64 public static BlockAllocateDataComparer Instance = new();
65
67 ArgumentNullException.ThrowIfNull(u1);
68 ArgumentNullException.ThrowIfNull(u2);
69 //首先比对是否已分配,未分配的排前面
70 int blockAllocate = (u1.Allocated ? 1 : 0) - (u2.Allocated ? 1 : 0);
71 if (blockAllocate != 0) {
72 return blockAllocate;
73 }
74 //然后比对mod信息
75 int modEntitySub = u1.ModEntity.GetHashCode() - u2.ModEntity.GetHashCode();
76 if (modEntitySub != 0) {
77 return modEntitySub;
78 }
79 //mod相同,则比对BlockIndex
80 int blockIndexSub = u1.Block.BlockIndex - u2.Block.BlockIndex;
81 return blockIndexSub != 0
82 ? blockIndexSub
83 :
84 //方块的Index相同(均未分配),则按方块名顺序分配
85 string.Compare(u1.Block.GetType().Name, u2.Block.GetType().Name, CultureInfo.InvariantCulture, CompareOptions.None);
86 }
87 }
88
89 public static void AllocateBlock(BlockAllocateData allocateData, int Index) {
90 Block block = allocateData.Block;
91 m_blocks[Index] = block;
92 BlockNameToIndex[block.GetType().Name] = Index;
93 BlockTypeToIndex[block.GetType()] = Index;
94 if (!BlockTypeToOriginalIndex.ContainsKey(block.GetType())) {
95 BlockTypeToOriginalIndex.Add(block.GetType(), allocateData.Block.BlockIndex);
96 }
97
98 //修复了加载旧API存档时,会导致方块索引错乱的问题
99 allocateData.Block.BlockIndex = Index;
100 allocateData.Allocated = true;
101 allocateData.Index = Index;
102 //修改方块的Index静态字段值
103#pragma warning disable IL2072
104 FieldInfo fieldInfo = block.GetType().GetRuntimeFields().FirstOrDefault(p => p.Name == "Index" && p.IsPublic && p.IsStatic);
105#pragma warning restore IL2072
106 if (fieldInfo != null
107 && fieldInfo.FieldType == typeof(int)
108 && !fieldInfo.IsLiteral) {
109 try {
110 fieldInfo.SetValue(null, block.BlockIndex); // 对于静态字段,第一个参数为null
111 }
112 catch (Exception ex) {
113 Log.Error($"Failed to edit Index of <{block.GetType().AssemblyQualifiedName}>! {ex}");
114 }
115 }
116 }
117
118 public static void Initialize() {
122 InitializeBlocks(null);
124 }
125
126 public static void ResetBlocks() {
127 for (int i = 0; i < m_blocks.Length; i++) {
128#pragma warning disable IL2072
129 m_blocks[i] = Activator.CreateInstance(m_blocks[i].GetType()) as Block;
130#pragma warning restore IL2072
131 if (!(m_blocks[i] is AirBlock)) {
132 m_blocks[i].BlockIndex = i;
133 }
134 if (m_blocks[i] is FluidBlock fluidBlock) {
135 m_fluidBlocks[i] = fluidBlock;
136 }
137 }
138 }
139
140 public static void InitializeCategories() {
141 m_categories.Clear();
142 m_categories.Add("Terrain");
143 m_categories.Add("Minerals");
144 m_categories.Add("Plants");
145 m_categories.Add("Construction");
146 m_categories.Add("Items");
147 m_categories.Add("Tools");
148 m_categories.Add("Weapons");
149 m_categories.Add("Clothes");
150 m_categories.Add("Electrics");
151 m_categories.Add("Food");
152 m_categories.Add("Spawner Eggs");
153 m_categories.Add("Painted");
154 m_categories.Add("Dyed");
155 m_categories.Add("Fireworks");
156 }
157
165 public static int GetBlockIndex(string BlockName, bool throwIfNotFound = false) {
166 bool valueGotten = BlockNameToIndex.TryGetValue(BlockName, out int index);
167 if (valueGotten) {
168 return index;
169 }
170 if (throwIfNotFound) {
171 throw new KeyNotFoundException($"Block with name <{BlockName}> is not found.");
172 }
173 return -1;
174 }
175
184 public static int GetBlockIndex<T>(bool throwIfNotFound = false, bool mustBeInSameType = false) where T : Block =>
185 GetBlockIndex(typeof(T), throwIfNotFound, mustBeInSameType);
186
195 public static int GetBlockIndex(Type blockType, bool throwIfNotFound = false, bool mustBeInSameType = false) {
196 int blockIndexByType = BlockTypeToIndex.GetValueOrDefault(blockType, -1);
197 if (blockIndexByType >= 0
198 && blockIndexByType < 1024) {
199 return blockIndexByType;
200 }
201 if (mustBeInSameType) {
202 if (throwIfNotFound) {
203 throw new KeyNotFoundException($"Block with type <{blockType.AssemblyQualifiedName}> is not found.");
204 }
205 return -1;
206 }
207 return GetBlockIndex(blockType.Name, throwIfNotFound);
208 }
209
216 public static Block GetBlockGeneral<T>(bool throwIfNotFound = false) where T : Block {
217 int blockIndex = GetBlockIndex<T>(throwIfNotFound);
218 if (blockIndex >= 0
219 && blockIndex < 1024) {
220 return Blocks[blockIndex];
221 }
222 return null;
223 }
224
225 public static Block GetBlock(string BlockName, bool throwIfNotFound = false) {
226 int blockIndex = GetBlockIndex(BlockName, throwIfNotFound);
227 if (blockIndex >= 0
228 && blockIndex < 1024) {
229 return m_blocks[blockIndex];
230 }
231 return null;
232 }
233
242 public static T GetBlock<T>(bool throwIfNotFound = false, bool mustBeInSameType = false) where T : Block {
243 int blockIndex = GetBlockIndex<T>(throwIfNotFound, mustBeInSameType);
244 if (blockIndex < 0) {
245 return null;
246 }
247 T blockT = Blocks[blockIndex] as T;
248 if (blockT == null && throwIfNotFound) {
249 throw new InvalidCastException(
250 $"Block <{typeof(T).AssemblyQualifiedName}> is modified into <{Blocks[blockIndex].GetType().AssemblyQualifiedName}> thus not capable for type."
251 );
252 }
253 return blockT; //方块列表中有名为"T"的方块,但无法转化为T也返回null
254 }
255
262 public static Block GetBlock(Type blockType, bool throwIfNotFound = false, bool mustBeInSameType = false) {
263 int blockIndex = GetBlockIndex(blockType, throwIfNotFound, mustBeInSameType);
264 if (blockIndex < 0) {
265 return null;
266 }
267 Block block = Blocks[blockIndex];
268 if (throwIfNotFound && block.GetType() == blockType) {
269 throw new InvalidCastException(
270 $"Block <{blockType.AssemblyQualifiedName}> is modified into <{block.GetType().AssemblyQualifiedName}> thus not capable for type."
271 );
272 }
273 return block;
274 }
275
276 public static void InitializeBlocks(SubsystemBlocksManager subsystemBlocksManager) {
277 for (int i = 0; i < m_blocks.Length; i++) {
278 m_blocks[i] = null;
279 }
280 BlocksAllocateData.Clear();
281 foreach (ModEntity entity in ModsManager.ModList) {
282 for (int i = 0; i < entity.BlockTypes.Count; i++) {
283 Type type = entity.BlockTypes[i];
284#pragma warning disable IL2072
285 Block block = (Block)Activator.CreateInstance(type);
286 if (block == null) {
287 continue;
288 }
289 FieldInfo fieldInfo = type.GetRuntimeFields().FirstOrDefault(p => p.Name == "Index" && p.IsPublic && p.IsStatic);
290#pragma warning restore IL2072
291 if (fieldInfo != null
292 && fieldInfo.FieldType == typeof(int)) {
293 int staticIndex = (int)fieldInfo.GetValue(null)!;
294 block.BlockIndex = staticIndex;
295 }
296 else {
297 block.BlockIndex = -1;
298 }
299 if (block.ShouldBeAddedToProject(subsystemBlocksManager)) {
300 bool staticBlockIndexBefore = false;
301 //对重名方块进行移除。复杂度n^2,如果严重影响性能可以考虑使用字典。
302 BlockAllocateData blockAllocateDataToRemove =
303 BlocksAllocateData.FirstOrDefault(b => b.Block.GetType().Name == block.GetType().Name);
304 if (blockAllocateDataToRemove != null) {
305 BlocksAllocateData.Remove(blockAllocateDataToRemove);
306 staticBlockIndexBefore = blockAllocateDataToRemove.StaticBlockIndex;
307 //Log.Information("Block覆盖:" + blockAllocateDataToRemove.Block.GetType().AssemblyQualifiedName + " => " + block.GetType().AssemblyQualifiedName);
308 }
311 Block = block,
312 Index = 0,
313 Allocated = false,
314 StaticBlockIndex = !block.IsIndexDynamic
315 || Equals(entity, ModsManager.SurvivalCraftModEntity)
316 || staticBlockIndexBefore,
317 ModEntity = entity
318 }
319 );
320 }
321 }
322 }
323 //分配静态ID方块
324 if (LoadBlocksStaticly) {
325 Log.Information("[BlocksManager]Blocks Loaded Statically");
326 }
327 for (int i = 0; i < BlocksAllocateData.Count; i++) {
328 try {
329 BlockAllocateData allocateData = BlocksAllocateData[i];
330 if (allocateData.Block.BlockIndex >= 0) {
331 BlockTypeToOriginalIndex.TryGetValue(allocateData.Block.GetType(), out int originalIndex);
332 if (originalIndex == 0) {
333 originalIndex = allocateData.Block.BlockIndex;
334 }
335 if (allocateData.StaticBlockIndex) {
336 AllocateBlock(allocateData, originalIndex);
337 }
338 else if (LoadBlocksStaticly && originalIndex >= 0) //负ID方块不进行分配
339 {
340 AllocateBlock(allocateData, originalIndex);
341 if (subsystemBlocksManager != null) {
342 subsystemBlocksManager.DynamicBlockNameToIndex[m_blocks[allocateData.Block.BlockIndex].GetType().Name] =
343 originalIndex;
344 }
345 }
346 }
347 }
348 catch (Exception ex) {
349 Log.Error(ex);
350 }
351 }
352 //进行排序
354 //调用SubsystemBlocksManager,加载Project对于<动态Mod方块-方块ID>的匹配信息。
355 if (subsystemBlocksManager != null) {
356 subsystemBlocksManager.CallAllocate();
357 //分配在SubsystemBlocksManager声明的动态方块
358 for (int i = 0; i < BlocksAllocateData.Count; i++) {
359 BlockAllocateData allocateData = BlocksAllocateData[i];
360 if (!allocateData.Allocated) {
361 bool containsKey = subsystemBlocksManager.DynamicBlockNameToIndex.TryGetValue(
362 allocateData.Block.GetType().Name,
363 out int blockValue
364 );
365 if (containsKey) {
366 AllocateBlock(allocateData, blockValue);
367 }
368 }
369 }
370 }
371 //分配剩余动态ID方块
372 int allocateDataIndex = 0;
373 for (int num = SurvivalCraftBlockCount + 1; allocateDataIndex < BlocksAllocateData.Count; num++) {
374 if (num == 1024) {
375 throw new Exception("Too many blocks! Please reduce the mods count.");
376 }
377 if (m_blocks[num] == null) {
378 try {
379 while (allocateDataIndex < BlocksAllocateData.Count
380 && BlocksAllocateData[allocateDataIndex].Allocated) {
381 allocateDataIndex++;
382 }
383 if (allocateDataIndex == BlocksAllocateData.Count) {
384 break;
385 }
386 AllocateBlock(BlocksAllocateData[allocateDataIndex], num);
387 if (subsystemBlocksManager != null) {
388 subsystemBlocksManager.DynamicBlockNameToIndex[m_blocks[num].GetType().Name] = num;
389 }
390 }
391 catch {
392 // ignored
393 }
394 }
395 }
396 //对未分配方块进行空置操作
397 for (int num = 0; num < m_blocks.Length; num++) {
398 m_blocks[num] ??= Blocks[0];
399 }
400 }
401
402 public static void PostProcessBlocksLoad() {
403 ResetBlocks();
404 foreach (ModEntity modEntity in ModsManager.ModList) {
405 modEntity.LoadBlocksData();
406 }
407 foreach (Block block in m_blocks) {
408 try {
409 block.Initialize();
410 }
411 catch (Exception e) {
412 LoadingScreen.Warning($"Loading Block {block.GetType().Name} error.\n{e}");
413 }
414 foreach (int value in block.GetCreativeValues()) {
415 string category = block.GetCategory(value);
416 AddCategory(category);
417 }
418 }
420 "BlocksInitalized",
421 modLoader => {
422 modLoader.BlocksInitalized();
423 return false;
424 }
425 );
426 }
427
428 public static void AddCategory(string category) {
429 if (!m_categories.Contains(category)) {
430 m_categories.Add(category);
431 }
432 }
433
434 [Obsolete("Use BlocksManager.GetBlock() instead.")]
435 public static Block FindBlockByTypeName(string typeName, bool throwIfNotFound) {
436 Block block = Blocks.FirstOrDefault(b => b.GetType().Name == typeName);
437 if (block == null && throwIfNotFound) {
438 throw new InvalidOperationException(string.Format(LanguageControl.Get("BlocksManager", 1), typeName));
439 }
440 return block;
441 }
442
443 public static Block[] FindBlocksByCraftingId(string craftingId) {
444 List<Block> blocks = [];
445 foreach (Block c in Blocks) {
446 if (c.MatchCrafingId(craftingId)) {
447 blocks.Add(c);
448 }
449 }
450 return blocks.ToArray();
451 }
452
453 public static void DrawCubeBlock(PrimitivesRenderer3D primitivesRenderer,
454 int value,
455 Vector3 size,
456 ref Matrix matrix,
457 Color color,
458 Color topColor,
459 DrawBlockEnvironmentData environmentData) {
461 primitivesRenderer,
462 value,
463 size,
464 1f,
465 ref matrix,
466 color,
467 topColor,
468 environmentData,
469 environmentData.SubsystemTerrain != null
472 );
473 }
474
475 public static void DrawCubeBlock(PrimitivesRenderer3D primitivesRenderer,
476 int value,
477 Vector3 size,
478 float height,
479 ref Matrix matrix,
480 Color color,
481 Color topColor,
482 DrawBlockEnvironmentData environmentData) {
484 primitivesRenderer,
485 value,
486 size,
487 height,
488 ref matrix,
489 color,
490 topColor,
491 environmentData,
492 environmentData.SubsystemTerrain != null
495 );
496 }
497
498 public static void DrawCubeBlock(PrimitivesRenderer3D primitivesRenderer,
499 int value,
500 Vector3 size,
501 float height,
502 ref Matrix matrix,
503 Color color,
504 Color topColor,
505 DrawBlockEnvironmentData environmentData,
506 Texture2D texture) {
507 environmentData = environmentData ?? m_defaultEnvironmentData;
508 TexturedBatch3D texturedBatch3D = primitivesRenderer.TexturedBatch(
509 texture,
510 true,
511 0,
512 null,
514 null,
516 );
517 float s = LightingManager.LightIntensityByLightValue[environmentData.Light];
518 color = Color.MultiplyColorOnlyNotSaturated(color, s);
519 topColor = Color.MultiplyColorOnlyNotSaturated(topColor, s);
520 Vector3 translation = matrix.Translation;
521 Vector3 vector = matrix.Right * size.X;
522 Vector3 v = matrix.Up * size.Y * height;
523 Vector3 v2 = matrix.Forward * size.Z;
524 Vector3 v3 = translation + 0.5f * (-vector - v - v2);
525 Vector3 v4 = translation + 0.5f * (vector - v - v2);
526 Vector3 v5 = translation + 0.5f * (-vector + v - v2);
527 Vector3 v6 = translation + 0.5f * (vector + v - v2);
528 Vector3 v7 = translation + 0.5f * (-vector - v + v2);
529 Vector3 v8 = translation + 0.5f * (vector - v + v2);
530 Vector3 v9 = translation + 0.5f * (-vector + v + v2);
531 Vector3 v10 = translation + 0.5f * (vector + v + v2);
532 if (environmentData.ViewProjectionMatrix.HasValue) {
533 Matrix m = environmentData.ViewProjectionMatrix.Value;
534 Vector3.Transform(ref v3, ref m, out v3);
535 Vector3.Transform(ref v4, ref m, out v4);
536 Vector3.Transform(ref v5, ref m, out v5);
537 Vector3.Transform(ref v6, ref m, out v6);
538 Vector3.Transform(ref v7, ref m, out v7);
539 Vector3.Transform(ref v8, ref m, out v8);
540 Vector3.Transform(ref v9, ref m, out v9);
541 Vector3.Transform(ref v10, ref m, out v10);
542 }
543 int num = Terrain.ExtractContents(value);
544 Block block = Blocks[num];
545 Vector4 vector2 = Vector4.Zero;
546 int textureSlotCount = block.GetTextureSlotCount(value);
547 int textureSlot = block.GetFaceTextureSlot(0, value);
548 vector2.X = (float)(textureSlot % textureSlotCount) / textureSlotCount;
549 vector2.Y = (float)(textureSlot / textureSlotCount) / textureSlotCount;
550 vector2.W = vector2.Y + 1f / textureSlotCount;
551 vector2.Z = vector2.X + 1f / textureSlotCount;
552 vector2.W = MathUtils.Lerp(vector2.Y, vector2.W, height);
553 texturedBatch3D.QueueQuad(
555 p1: v3,
556 p2: v5,
557 p3: v6,
558 p4: v4,
559 texCoord1: new Vector2(vector2.X, vector2.W),
560 texCoord2: new Vector2(vector2.X, vector2.Y),
561 texCoord3: new Vector2(vector2.Z, vector2.Y),
562 texCoord4: new Vector2(vector2.Z, vector2.W)
563 );
564 textureSlot = block.GetFaceTextureSlot(2, value);
565 vector2.X = (float)(textureSlot % textureSlotCount) / textureSlotCount;
566 vector2.Y = (float)(textureSlot / textureSlotCount) / textureSlotCount;
567 vector2.W = vector2.Y + 1f / textureSlotCount;
568 vector2.Z = vector2.X + 1f / textureSlotCount;
569 vector2.W = MathUtils.Lerp(vector2.Y, vector2.W, height);
570 texturedBatch3D.QueueQuad(
572 p1: v7,
573 p2: v8,
574 p3: v10,
575 p4: v9,
576 texCoord1: new Vector2(vector2.Z, vector2.W),
577 texCoord2: new Vector2(vector2.X, vector2.W),
578 texCoord3: new Vector2(vector2.X, vector2.Y),
579 texCoord4: new Vector2(vector2.Z, vector2.Y)
580 );
581 textureSlot = block.GetFaceTextureSlot(5, value);
582 vector2.X = (float)(textureSlot % textureSlotCount) / textureSlotCount;
583 vector2.Y = (float)(textureSlot / textureSlotCount) / textureSlotCount;
584 vector2.W = vector2.Y + 1f / textureSlotCount;
585 vector2.Z = vector2.X + 1f / textureSlotCount;
586 texturedBatch3D.QueueQuad(
588 p1: v3,
589 p2: v4,
590 p3: v8,
591 p4: v7,
592 texCoord1: new Vector2(vector2.X, vector2.Y),
593 texCoord2: new Vector2(vector2.Z, vector2.Y),
594 texCoord3: new Vector2(vector2.Z, vector2.W),
595 texCoord4: new Vector2(vector2.X, vector2.W)
596 );
597 textureSlot = block.GetFaceTextureSlot(4, value);
598 vector2.X = (float)(textureSlot % textureSlotCount) / textureSlotCount;
599 vector2.Y = (float)(textureSlot / textureSlotCount) / textureSlotCount;
600 vector2.W = vector2.Y + 1f / textureSlotCount;
601 vector2.Z = vector2.X + 1f / textureSlotCount;
602 texturedBatch3D.QueueQuad(
604 p1: v5,
605 p2: v9,
606 p3: v10,
607 p4: v6,
608 texCoord1: new Vector2(vector2.X, vector2.W),
609 texCoord2: new Vector2(vector2.X, vector2.Y),
610 texCoord3: new Vector2(vector2.Z, vector2.Y),
611 texCoord4: new Vector2(vector2.Z, vector2.W)
612 );
613 textureSlot = block.GetFaceTextureSlot(1, value);
614 vector2.X = (float)(textureSlot % textureSlotCount) / textureSlotCount;
615 vector2.Y = (float)(textureSlot / textureSlotCount) / textureSlotCount;
616 vector2.W = vector2.Y + 1f / textureSlotCount;
617 vector2.Z = vector2.X + 1f / textureSlotCount;
618 vector2.W = MathUtils.Lerp(vector2.Y, vector2.W, height);
619 texturedBatch3D.QueueQuad(
621 p1: v3,
622 p2: v7,
623 p3: v9,
624 p4: v5,
625 texCoord1: new Vector2(vector2.Z, vector2.W),
626 texCoord2: new Vector2(vector2.X, vector2.W),
627 texCoord3: new Vector2(vector2.X, vector2.Y),
628 texCoord4: new Vector2(vector2.Z, vector2.Y)
629 );
630 textureSlot = block.GetFaceTextureSlot(3, value);
631 vector2.X = (float)(textureSlot % textureSlotCount) / textureSlotCount;
632 vector2.Y = (float)(textureSlot / textureSlotCount) / textureSlotCount;
633 vector2.W = vector2.Y + 1f / textureSlotCount;
634 vector2.Z = vector2.X + 1f / textureSlotCount;
635 vector2.W = MathUtils.Lerp(vector2.Y, vector2.W, height);
636 texturedBatch3D.QueueQuad(
637 color: Color.MultiplyColorOnly(color, LightingManager.CalculateLighting(matrix.Right)),
638 p1: v4,
639 p2: v6,
640 p3: v10,
641 p4: v8,
642 texCoord1: new Vector2(vector2.X, vector2.W),
643 texCoord2: new Vector2(vector2.X, vector2.Y),
644 texCoord3: new Vector2(vector2.Z, vector2.Y),
645 texCoord4: new Vector2(vector2.Z, vector2.W)
646 );
647 }
648
649 public static void DrawCubeBlock(PrimitivesRenderer3D primitivesRenderer,
650 int value,
651 Vector3 size,
652 ref Matrix matrix,
653 Color color,
654 Color topColor,
655 DrawBlockEnvironmentData environmentData,
656 Texture2D texture) {
658 primitivesRenderer,
659 value,
660 size,
661 1f,
662 ref matrix,
663 color,
664 topColor,
665 environmentData,
666 texture
667 );
668 }
669
670 public static void DrawFlatOrImageExtrusionBlock(PrimitivesRenderer3D primitivesRenderer,
671 int value,
672 float size,
673 ref Matrix matrix,
674 Texture2D texture,
675 Color color,
676 bool isEmissive,
677 DrawBlockEnvironmentData environmentData) {
678 environmentData = environmentData ?? m_defaultEnvironmentData;
680 && texture == null
681 && !isEmissive
682 && (environmentData.DrawBlockMode == DrawBlockMode.FirstPerson || environmentData.DrawBlockMode == DrawBlockMode.ThirdPerson)) {
683 DrawImageExtrusionBlock(primitivesRenderer, value, size, ref matrix, color, environmentData);
684 }
685 else {
687 primitivesRenderer,
688 value,
689 size,
690 ref matrix,
691 texture,
692 color,
693 isEmissive,
694 environmentData
695 );
696 }
697 }
698
699 public static void DrawFlatBlock(PrimitivesRenderer3D primitivesRenderer,
700 int value,
701 float size,
702 ref Matrix matrix,
703 Texture2D texture,
704 Color color,
705 bool isEmissive,
706 DrawBlockEnvironmentData environmentData) {
707 environmentData = environmentData ?? m_defaultEnvironmentData;
708 int num = Terrain.ExtractContents(value);
709 Block block = Blocks[num];
710 Vector4 vector;
711 texture ??= environmentData.SubsystemTerrain != null
712 ? environmentData.SubsystemTerrain.SubsystemAnimatedTextures.AnimatedBlocksTexture
714 int textureSlotCount = block.GetTextureSlotCount(value);
715 int textureSlot = block.GetFaceTextureSlot(-1, value);
716 if (textureSlotCount == 16) {
717 vector = m_slotTexCoords[textureSlot];
718 }
719 else {
720 float tx = (float)(textureSlot % textureSlotCount) / textureSlotCount;
721 float ty = (float)(textureSlot / textureSlotCount) / textureSlotCount;
722 vector = new Vector4(tx, ty, tx + 1f / textureSlotCount, ty + 1f / textureSlotCount);
723 }
724 if (!isEmissive) {
725 float s = LightingManager.LightIntensityByLightValue[environmentData.Light];
726 color = Color.MultiplyColorOnly(color, s);
727 }
728 Vector3 translation = matrix.Translation;
729 Vector3 vector2;
730 Vector3 vector3;
731 if (environmentData.BillboardDirection.HasValue) {
732 vector2 = Vector3.Normalize(Vector3.Cross(environmentData.BillboardDirection.Value, Vector3.UnitY));
733 vector3 = -Vector3.Normalize(Vector3.Cross(environmentData.BillboardDirection.Value, vector2));
734 }
735 else {
736 vector2 = matrix.Right;
737 vector3 = matrix.Up;
738 }
739 Vector3 v = translation + 0.85f * size * (-vector2 - vector3);
740 Vector3 v2 = translation + 0.85f * size * (vector2 - vector3);
741 Vector3 v3 = translation + 0.85f * size * (-vector2 + vector3);
742 Vector3 v4 = translation + 0.85f * size * (vector2 + vector3);
743 if (environmentData.ViewProjectionMatrix.HasValue) {
744 Matrix m = environmentData.ViewProjectionMatrix.Value;
745 Vector3.Transform(ref v, ref m, out v);
746 Vector3.Transform(ref v2, ref m, out v2);
747 Vector3.Transform(ref v3, ref m, out v3);
748 Vector3.Transform(ref v4, ref m, out v4);
749 }
750 TexturedBatch3D texturedBatch3D = primitivesRenderer.TexturedBatch(
751 texture,
752 true,
753 0,
754 null,
758 );
759 texturedBatch3D.QueueQuad(
760 v,
761 v3,
762 v4,
763 v2,
764 new Vector2(vector.X, vector.W),
765 new Vector2(vector.X, vector.Y),
766 new Vector2(vector.Z, vector.Y),
767 new Vector2(vector.Z, vector.W),
768 color
769 );
770 if (!environmentData.BillboardDirection.HasValue) {
771 texturedBatch3D.QueueQuad(
772 v,
773 v2,
774 v4,
775 v3,
776 new Vector2(vector.X, vector.W),
777 new Vector2(vector.Z, vector.W),
778 new Vector2(vector.Z, vector.Y),
779 new Vector2(vector.X, vector.Y),
780 color
781 );
782 }
783 }
784
785 public static void DrawImageExtrusionBlock(PrimitivesRenderer3D primitivesRenderer,
786 int value,
787 float size,
788 ref Matrix matrix,
789 Color color,
790 DrawBlockEnvironmentData environmentData) {
791 environmentData = environmentData ?? m_defaultEnvironmentData;
792 int num = Terrain.ExtractContents(value);
793 Block block = Blocks[num];
794 try {
795 Image image = environmentData.SubsystemTerrain != null
798 BlockMesh imageExtrusionBlockMesh = GetImageExtrusionBlockMesh(image, block.GetFaceTextureSlot(-1, value));
799 DrawMeshBlock(primitivesRenderer, imageExtrusionBlockMesh, color, 1.7f * size, ref matrix, environmentData);
800 }
801 catch (Exception) {
802 // ignored
803 }
804 }
805
806 public static BlockMesh GetImageExtrusionBlockMesh(Image image, int slot) {
807 ImageExtrusionKey imageExtrusionKey = default;
808 imageExtrusionKey.Image = image;
809 imageExtrusionKey.Slot = slot;
810 if (!m_imageExtrusionsCache.TryGetValue(imageExtrusionKey, out BlockMesh value)) {
811 value = new BlockMesh();
812 int num = (int)MathF.Round(m_slotTexCoords[slot].X * image.Width);
813 int num2 = (int)MathF.Round(m_slotTexCoords[slot].Y * image.Height);
814 int num3 = (int)MathF.Round(m_slotTexCoords[slot].Z * image.Width);
815 int num4 = (int)MathF.Round(m_slotTexCoords[slot].W * image.Height);
816 int num5 = MathUtils.Max(num3 - num, num4 - num2);
817 value.AppendImageExtrusion(
818 image,
819 new Rectangle(num, num2, num3 - num, num4 - num2),
820 new Vector3(1f / num5, 1f / num5, 0.0833333358f),
821 Color.White,
822 0
823 );
824 m_imageExtrusionsCache.Add(imageExtrusionKey, value);
825 }
826 return value;
827 }
828
829 public static void DrawMeshBlock(PrimitivesRenderer3D primitivesRenderer,
830 BlockMesh blockMesh,
831 float size,
832 ref Matrix matrix,
833 DrawBlockEnvironmentData environmentData) {
834 environmentData = environmentData ?? m_defaultEnvironmentData;
835 Texture2D texture = environmentData.SubsystemTerrain != null
836 ? environmentData.SubsystemTerrain.SubsystemAnimatedTextures.AnimatedBlocksTexture
839 primitivesRenderer,
840 blockMesh,
841 texture,
842 Color.White,
843 size,
844 ref matrix,
845 environmentData
846 );
847 }
848
849 public static void DrawMeshBlock(PrimitivesRenderer3D primitivesRenderer,
850 BlockMesh blockMesh,
851 Color color,
852 float size,
853 ref Matrix matrix,
854 DrawBlockEnvironmentData environmentData) {
855 environmentData = environmentData ?? m_defaultEnvironmentData;
856 Texture2D texture = environmentData.SubsystemTerrain != null
857 ? environmentData.SubsystemTerrain.SubsystemAnimatedTextures.AnimatedBlocksTexture
860 primitivesRenderer,
861 blockMesh,
862 texture,
863 color,
864 size,
865 ref matrix,
866 environmentData
867 );
868 }
869
870 public static void DrawMeshBlock(PrimitivesRenderer3D primitivesRenderer,
871 BlockMesh blockMesh,
872 Texture2D texture,
873 Color color,
874 float size,
875 ref Matrix matrix,
876 DrawBlockEnvironmentData environmentData) {
877 environmentData = environmentData ?? m_defaultEnvironmentData;
878 float num = LightingManager.LightIntensityByLightValue[environmentData.Light];
879 Vector4 vector = new(color);
880 Vector4 vector2 = new(new Vector3(vector.X, vector.Y, vector.Z) * num, vector.W);
881 TexturedBatch3D texturedBatch3D = primitivesRenderer.TexturedBatch(
882 texture,
883 true,
884 0,
885 null,
887 null,
889 );
890 bool flag = false;
891 Matrix m = !environmentData.ViewProjectionMatrix.HasValue ? matrix : matrix * environmentData.ViewProjectionMatrix.Value;
892 if (size != 1f) {
893 m = Matrix.CreateScale(size) * m;
894 }
895 if (m.M14 != 0f
896 || m.M24 != 0f
897 || m.M34 != 0f
898 || m.M44 != 1f) {
899 flag = true;
900 }
901 int count = blockMesh.Vertices.Count;
902 BlockMeshVertex[] array = blockMesh.Vertices.Array;
903 int count2 = blockMesh.Indices.Count;
904 int[] array2 = blockMesh.Indices.Array;
905 DynamicArray<VertexPositionColorTexture> triangleVertices = texturedBatch3D.TriangleVertices;
906 int count3 = triangleVertices.Count;
907 int count4 = triangleVertices.Count;
908 triangleVertices.Count += count;
909 for (int i = 0; i < count; i++) {
910 BlockMeshVertex blockMeshVertex = array[i];
911 if (flag) {
912 Vector4 v2 = new(blockMeshVertex.Position, 1f);
913 Vector4.Transform(ref v2, ref m, out v2);
914 float num2 = 1f / v2.W;
915 blockMeshVertex.Position = new Vector3(v2.X * num2, v2.Y * num2, v2.Z * num2);
916 }
917 else {
918 Vector3.Transform(ref blockMeshVertex.Position, ref m, out blockMeshVertex.Position);
919 }
920 Color color2 = !blockMeshVertex.IsEmissive
921 ? new Color(
922 (byte)(blockMeshVertex.Color.R * vector2.X),
923 (byte)(blockMeshVertex.Color.G * vector2.Y),
924 (byte)(blockMeshVertex.Color.B * vector2.Z),
925 (byte)(blockMeshVertex.Color.A * vector2.W)
926 )
927 : new Color(
928 (byte)(blockMeshVertex.Color.R * vector.X),
929 (byte)(blockMeshVertex.Color.G * vector.Y),
930 (byte)(blockMeshVertex.Color.B * vector.Z),
931 (byte)(blockMeshVertex.Color.A * vector.W)
932 );
933 triangleVertices.Array[count4++] = new VertexPositionColorTexture(
934 blockMeshVertex.Position,
935 color2,
936 blockMeshVertex.TextureCoordinates
937 );
938 }
939 DynamicArray<int> triangleIndices = texturedBatch3D.TriangleIndices;
940 int count5 = triangleIndices.Count;
941 triangleIndices.Count += count2;
942 for (int j = 0; j < count2; j++) {
943 triangleIndices.Array[count5++] = count3 + array2[j];
944 }
945 }
946
947 public static int DamageItem(int value, int damageCount, Entity owner = null) {
948 int num = Terrain.ExtractContents(value);
949 Block block = Blocks[num];
950 int result = 0;
951 bool skipVanilla = false;
953 "DamageItem",
954 modLoader => {
955 result = modLoader.DamageItem(block, value, damageCount, owner, out skipVanilla);
956 return false;
957 }
958 );
959 if (skipVanilla) {
960 return result;
961 }
962 int durability = block.GetDurability(value);
963 if (durability >= 0) {
964 int num2 = block.GetDamage(value) + damageCount;
965 if (num2 <= durability) {
966 return block.SetDamage(value, num2);
967 }
968 return block.GetDamageDestructionValue(value);
969 }
970 return value;
971 }
972
973 public static void LoadBlocksData(string blocksDataString) {
974 blocksDataString = blocksDataString.Replace("\r", string.Empty);
975 string[] lines = blocksDataString.Split('\n', StringSplitOptions.RemoveEmptyEntries);
976 string[] firstLine = lines[0].Split(';');
977 for (int i = 1; i < lines.Length; i++) {
978 string line = lines[i];
979 if (string.IsNullOrEmpty(line)) {
980 continue;
981 }
982 string[] array = line.Split(';');
983 if (array.Length != firstLine.Length) {
984 throw new InvalidOperationException(
985 $"{string.Format(LanguageControl.Get("BlocksManager", "2"), array.Length > 0 ? array[0] : LanguageControl.Unknown)}{string.Format(LanguageControl.Get("BlocksManager", "7"), firstLine.Length, array.Length)}"
986 );
987 }
988 string typeName = array[0];
989 if (string.IsNullOrEmpty(typeName)) {
990 continue;
991 }
992 Block block = m_blocks.FirstOrDefault(v => v.GetType().Name == typeName);
993 if (block == null) {
994 Log.Warning(string.Format(LanguageControl.Get("BlocksManager", 3), typeName));
995 continue;
996 }
997 Dictionary<string, FieldInfo> fieldInfos = new();
998#pragma warning disable IL2072
999 foreach (FieldInfo runtimeField in block.GetType().GetRuntimeFields()) {
1000#pragma warning disable IL2072
1001 if (runtimeField.IsPublic
1002 && !runtimeField.IsStatic) {
1003 fieldInfos.Add(runtimeField.Name, runtimeField);
1004 }
1005 }
1006 for (int j = 1; j < array.Length; j++) {
1007 string fieldName = firstLine[j];
1008 string data = array[j];
1009 if (!string.IsNullOrEmpty(data)) {
1010 if (!fieldInfos.TryGetValue(fieldName, out FieldInfo value)) {
1011 throw new InvalidOperationException(string.Format(LanguageControl.Get("BlocksManager", "8"), fieldName, typeName));
1012 }
1013 object obj;
1014 if (data.StartsWith('#')) {
1015 string refTypeName = data.Substring(1);
1016 obj = !string.IsNullOrEmpty(refTypeName)
1017 ? (m_blocks.FirstOrDefault(v => v.GetType().Name == refTypeName)
1018 ?? throw new InvalidOperationException(string.Format(LanguageControl.Get("BlocksManager", "9"), refTypeName, typeName, fieldName)))
1019 .BlockIndex
1020 : (object)block.BlockIndex;
1021 }
1022 else {
1023 obj = HumanReadableConverter.ConvertFromString(value.FieldType, data);
1024 }
1025 value.SetValue(block, obj);
1026 }
1027 }
1028 }
1029 }
1030
1031 public static void CalculateSlotTexCoordTables() {
1032 for (int i = 0; i < 256; i++) {
1034 }
1035 }
1036
1037 public static Vector4 TextureSlotToTextureCoords(int slot) {
1038 int num = slot % 16;
1039 int num2 = slot / 16;
1040 float x = (num + 0.001f) / 16f;
1041 float y = (num2 + 0.001f) / 16f;
1042 float z = (num + 1 - 0.001f) / 16f;
1043 float w = (num2 + 1 - 0.001f) / 16f;
1044 return new Vector4(x, y, z, w);
1045 }
1046
1047 public static Vector4[] GetslotTexCoords(int textureSlotCount) {
1048 int totalCount = textureSlotCount * textureSlotCount;
1049 Vector4[] slotTexCoords = new Vector4[totalCount];
1050 for (int i = 0; i < totalCount; i++) {
1051 int num = i % textureSlotCount;
1052 int num2 = i / textureSlotCount;
1053 float x = (num + 0.001f) / textureSlotCount;
1054 float y = (num2 + 0.001f) / textureSlotCount;
1055 float z = (num + 1 - 0.001f) / textureSlotCount;
1056 float w = (num2 + 1 - 0.001f) / textureSlotCount;
1057 slotTexCoords[i] = new Vector4(x, y, z, w);
1058 }
1059 return slotTexCoords;
1060 }
1061
1062 [Obsolete("Use BlocksManager.GetBlock() instead.")]
1063 public static Block GetBlockInMod(string ModSpace, string TypeFullName) {
1064 if (ModsManager.GetModEntity(ModSpace, out ModEntity modEntity)) {
1065 Type type = modEntity.BlockTypes.Find(p => p.Name == TypeFullName);
1066 Block block = GetBlock(type, false, true);
1067 if (block != null) {
1068 return block;
1069 }
1070 }
1071 return null;
1072 }
1073 }
1074}
Engine.Color Color
Engine.Vector3 Vector3
readonly DynamicArray< int > TriangleIndices
readonly DynamicArray< VertexPositionColorTexture > TriangleVertices
static readonly BlendState AlphaBlend
TexturedBatch3D TexturedBatch(Texture2D texture, bool useAlphaTest=false, int layer=0, DepthStencilState depthStencilState=null, RasterizerState rasterizerState=null, BlendState blendState=null, SamplerState samplerState=null)
static readonly RasterizerState CullCounterClockwiseScissor
void QueueQuad(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4, Vector2 texCoord1, Vector2 texCoord2, Vector2 texCoord3, Vector2 texCoord4, Color color)
static void Error(object message)
定义 Log.cs:80
static void Information(object message)
定义 Log.cs:56
static void Warning(object message)
定义 Log.cs:68
static int Max(int x1, int x2)
static float Lerp(float x1, float x2, float f)
static object ConvertFromString(Type type, string data)
virtual string GetCategory(int value)
int BlockIndex
定义 Block.cs:6
virtual int GetTextureSlotCount(int value)
设置材质(正方形)单行格子(分割后每个材质)数,对放置后的方块无效
virtual int SetDamage(int value, int damage)
virtual void Initialize()
virtual int GetDamage(int value)
virtual int GetFaceTextureSlot(int face, int value)
virtual int GetDurability(int value)
virtual IEnumerable< int > GetCreativeValues()
virtual bool ShouldBeAddedToProject(SubsystemBlocksManager subsystemBlocksManager)
virtual bool MatchCrafingId(string CraftId)
virtual int GetDamageDestructionValue(int value)
DynamicArray< BlockMeshVertex > Vertices
DynamicArray< int > Indices
int Compare(BlockAllocateData u1, BlockAllocateData u2)
static BlockAllocateDataComparer Instance
static Block GetBlockGeneral< T >(bool throwIfNotFound=false)
获取一个方块的通用Block类,具有较好的模组兼容稳定性
static Block GetBlock(Type blockType, bool throwIfNotFound=false, bool mustBeInSameType=false)
static Dictionary< Type, int > BlockTypeToIndex
static Dictionary< string, int > BlockNameToIndex
static int GetBlockIndex< T >(bool throwIfNotFound=false, bool mustBeInSameType=false)
获取方块的Index
static Vector4[] m_slotTexCoords
static void DrawMeshBlock(PrimitivesRenderer3D primitivesRenderer, BlockMesh blockMesh, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
static void LoadBlocksData(string blocksDataString)
static Dictionary< ImageExtrusionKey, BlockMesh > m_imageExtrusionsCache
static int DamageItem(int value, int damageCount, Entity owner=null)
static ReadOnlyList< string > Categories
static void CalculateSlotTexCoordTables()
static void DrawCubeBlock(PrimitivesRenderer3D primitivesRenderer, int value, Vector3 size, ref Matrix matrix, Color color, Color topColor, DrawBlockEnvironmentData environmentData, Texture2D texture)
static bool DrawImageExtrusionEnabled
static void DrawMeshBlock(PrimitivesRenderer3D primitivesRenderer, BlockMesh blockMesh, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
static DrawBlockEnvironmentData m_defaultEnvironmentData
static void InitializeCategories()
static FluidBlock[] m_fluidBlocks
static Block GetBlockInMod(string ModSpace, string TypeFullName)
static void DrawMeshBlock(PrimitivesRenderer3D primitivesRenderer, BlockMesh blockMesh, Texture2D texture, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
static List< BlockAllocateData > BlocksAllocateData
static void DrawFlatBlock(PrimitivesRenderer3D primitivesRenderer, int value, float size, ref Matrix matrix, Texture2D texture, Color color, bool isEmissive, DrawBlockEnvironmentData environmentData)
static Vector4[] GetslotTexCoords(int textureSlotCount)
static void DrawCubeBlock(PrimitivesRenderer3D primitivesRenderer, int value, Vector3 size, ref Matrix matrix, Color color, Color topColor, DrawBlockEnvironmentData environmentData)
static List< string > m_categories
static int GetBlockIndex(string BlockName, bool throwIfNotFound=false)
通过方块名称来获取方块的Index
static Block GetBlock(string BlockName, bool throwIfNotFound=false)
static Block[] FindBlocksByCraftingId(string craftingId)
static BlockMesh GetImageExtrusionBlockMesh(Image image, int slot)
static void PostProcessBlocksLoad()
static void DrawImageExtrusionBlock(PrimitivesRenderer3D primitivesRenderer, int value, float size, ref Matrix matrix, Color color, DrawBlockEnvironmentData environmentData)
static void DrawCubeBlock(PrimitivesRenderer3D primitivesRenderer, int value, Vector3 size, float height, ref Matrix matrix, Color color, Color topColor, DrawBlockEnvironmentData environmentData)
static void DrawFlatOrImageExtrusionBlock(PrimitivesRenderer3D primitivesRenderer, int value, float size, ref Matrix matrix, Texture2D texture, Color color, bool isEmissive, DrawBlockEnvironmentData environmentData)
static int[] m_originalBlockIndex
static Dictionary< Type, int > BlockTypeToOriginalIndex
static T GetBlock< T >(bool throwIfNotFound=false, bool mustBeInSameType=false)
static void InitializeBlocks(SubsystemBlocksManager subsystemBlocksManager)
static void AllocateBlock(BlockAllocateData allocateData, int Index)
static Vector4 TextureSlotToTextureCoords(int slot)
static FluidBlock[] FluidBlocks
static Block FindBlockByTypeName(string typeName, bool throwIfNotFound)
static void DrawCubeBlock(PrimitivesRenderer3D primitivesRenderer, int value, Vector3 size, float height, ref Matrix matrix, Color color, Color topColor, DrawBlockEnvironmentData environmentData, Texture2D texture)
static void AddCategory(string category)
static Action< Project > ProjectDisposed
static string Get(string className, int key)
获取在当前语言类名键对应的字符串
static readonly float[] LightIntensityByLightValue
static float CalculateLighting(Vector3 normal)
static void Warning(string mesg)
List< Type > BlockTypes
virtual void LoadBlocksData()
初始化BlocksData资源
override int GetHashCode()
virtual SubsystemAnimatedTextures SubsystemAnimatedTextures
static int ExtractContents(int value)
static void HookAction(string HookName, Func< ModLoader, bool > action)
执行Hook
static bool GetModEntity(string packagename, out ModEntity modEntity)
static ModEntity SurvivalCraftModEntity
static List< ModEntity > ModList
所有已启用的模组
static Color White
static Color MultiplyColorOnlyNotSaturated(Color c, float s)
static Color MultiplyColorOnly(Color c, float s)
static Matrix CreateScale(float scale)
static Vector3 Transform(Vector3 v, Matrix m)
static Vector3 Cross(Vector3 v1, Vector3 v2)
static Vector3 Normalize(Vector3 v)
static readonly Vector3 UnitY
static Vector4 Transform(Vector4 v, Matrix m)
static readonly Vector4 Zero