A stable modding interface between Techblox and mods https://mod.exmods.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
6.4KB

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using Gamecraft.Blocks.BlockGroups;
  5. using Unity.Mathematics;
  6. using UnityEngine;
  7. using GamecraftModdingAPI.Blocks;
  8. using GamecraftModdingAPI.Utility;
  9. namespace GamecraftModdingAPI
  10. {
  11. /// <summary>
  12. /// A group of blocks that can be selected together. The placed version of blueprints.
  13. /// </summary>
  14. public class BlockGroup : ICollection<Block>
  15. {
  16. internal static BlueprintEngine _engine = new BlueprintEngine();
  17. public int Id { get; }
  18. private readonly Block sourceBlock;
  19. private readonly List<Block> blocks;
  20. private float3 position, rotation;
  21. internal bool PosAndRotCalculated;
  22. internal BlockGroup(int id, Block block)
  23. {
  24. if (id == BlockGroupUtility.GROUP_UNASSIGNED)
  25. throw new BlockException("Cannot create a block group for blocks without a group!");
  26. Id = id;
  27. sourceBlock = block;
  28. blocks = new List<Block>(GetBlocks());
  29. }
  30. /// <summary>
  31. /// The position of the block group (center). Recalculated if blocks have been added/removed since the last query.
  32. /// </summary>
  33. public float3 Position
  34. {
  35. get
  36. {
  37. if (!PosAndRotCalculated)
  38. Refresh();
  39. return position;
  40. }
  41. set
  42. {
  43. var diff = value - position;
  44. foreach (var block in blocks)
  45. block.Position += diff;
  46. if (!PosAndRotCalculated) //The condition can only be true if a block has been added/removed manually
  47. Refresh(); //So the blocks array is up to date
  48. else
  49. position += diff;
  50. }
  51. }
  52. /// <summary>
  53. /// The rotation of the block group. Recalculated if blocks have been added/removed since the last query.
  54. /// </summary>
  55. public float3 Rotation
  56. {
  57. get
  58. {
  59. if (!PosAndRotCalculated)
  60. Refresh();
  61. return rotation;
  62. }
  63. set
  64. {
  65. var diff = value - rotation;
  66. var qdiff = Quaternion.Euler(diff);
  67. foreach (var block in blocks)
  68. {
  69. block.Rotation += diff;
  70. block.Position = qdiff * block.Position;
  71. }
  72. if (!PosAndRotCalculated)
  73. Refresh();
  74. else
  75. rotation += diff;
  76. }
  77. }
  78. /*/// <summary>
  79. /// Removes all of the blocks in this group from the world.
  80. /// </summary>
  81. public void RemoveBlocks()
  82. {
  83. _engine.RemoveBlockGroup(Id); - TODO: Causes a hard crash
  84. }*/
  85. /// <summary>
  86. /// Creates a new block group consisting of a single block.
  87. /// You can add more blocks using the Add() method or by setting the BlockGroup property of the blocks.<br />
  88. /// Note that only newly placed blocks should be added to groups.
  89. /// </summary>
  90. /// <param name="block">The block to add</param>
  91. /// <returns>A new block group containing the given block</returns>
  92. public static BlockGroup Create(Block block)
  93. {
  94. return new BlockGroup(_engine.CreateBlockGroup(default, default), block);
  95. }
  96. /// <summary>
  97. /// Collects each block that is a part of this group. Also sets the position and rotation.
  98. /// </summary>
  99. /// <returns>An array of blocks</returns>
  100. private Block[] GetBlocks()
  101. {
  102. if (!sourceBlock.Exists) return new[] {sourceBlock}; //The block must exist to get the others
  103. var ret = _engine.GetBlocksFromGroup(sourceBlock.Id, out var pos, out var rot);
  104. position = pos;
  105. rotation = ((Quaternion) rot).eulerAngles;
  106. PosAndRotCalculated = true;
  107. return ret;
  108. }
  109. private void Refresh()
  110. {
  111. blocks.Clear();
  112. blocks.AddRange(GetBlocks());
  113. }
  114. internal static void Init()
  115. {
  116. GameEngineManager.AddGameEngine(_engine);
  117. }
  118. public IEnumerator<Block> GetEnumerator() => blocks.GetEnumerator();
  119. IEnumerator IEnumerable.GetEnumerator() => blocks.GetEnumerator();
  120. /// <summary>
  121. /// Adds a block to the group. You should only add newly placed blocks
  122. /// so that the game initializes the group membership properly.
  123. /// </summary>
  124. /// <param name="item"></param>
  125. /// <exception cref="NullReferenceException"></exception>
  126. public void Add(Block item)
  127. {
  128. if (item == null) throw new NullReferenceException("Cannot add null to a block group");
  129. item.BlockGroup = this; //Calls AddInternal
  130. }
  131. internal void AddInternal(Block item) => blocks.Add(item);
  132. /// <summary>
  133. /// Removes all blocks from this group.
  134. /// You should not remove blocks that have been initialized, only those that you placed recently.
  135. /// </summary>
  136. public void Clear()
  137. {
  138. while (blocks.Count > 0)
  139. Remove(blocks[blocks.Count - 1]);
  140. }
  141. public bool Contains(Block item) => blocks.Contains(item);
  142. public void CopyTo(Block[] array, int arrayIndex) => blocks.CopyTo(array, arrayIndex);
  143. /// <summary>
  144. /// Removes a block from this group.
  145. /// You should not remove blocks that have been initialized, only those that you placed recently.
  146. /// </summary>
  147. /// <param name="item"></param>
  148. /// <returns></returns>
  149. /// <exception cref="NullReferenceException"></exception>
  150. public bool Remove(Block item)
  151. {
  152. if (item == null) throw new NullReferenceException("Cannot remove null from a block group");
  153. bool ret = item.BlockGroup == this;
  154. if (ret)
  155. item.BlockGroup = null; //Calls RemoveInternal
  156. return ret;
  157. }
  158. internal void RemoveInternal(Block item) => blocks.Remove(item);
  159. public int Count => blocks.Count;
  160. public bool IsReadOnly { get; } = false;
  161. public Block this[int index] => blocks[index]; //Setting is not supported, since the order doesn't matter
  162. }
  163. }