Tools for building games mainly focused on changing block properties. And noclip.
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.

BlockMod.cs 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Gamecraft.Wires;
  5. using Gamecraft.Wires.ChannelsCommon;
  6. using GamecraftModdingAPI;
  7. using GamecraftModdingAPI.Blocks;
  8. using GamecraftModdingAPI.Commands;
  9. using GamecraftModdingAPI.Players;
  10. using GamecraftModdingAPI.Utility;
  11. using IllusionPlugin;
  12. using RobocraftX.CommandLine.Custom;
  13. using Unity.Mathematics;
  14. using uREPL;
  15. using Main = GamecraftModdingAPI.Main;
  16. namespace BlockMod
  17. {
  18. public class BlockMod : IPlugin
  19. {
  20. private Block[] blocks = new Block[0];
  21. private Block refBlock;
  22. public void OnApplicationStart()
  23. {
  24. Main.Init();
  25. GameClient.SetDebugInfo("BlockModInfo", GetBlockInfo);
  26. RegisterBlockCommand("scaleBlocks",
  27. "Scales the blocks you're looking at, relative to current size (current scale * new scale)." +
  28. " The block you're looking at stays where it is, everything else is moved next to it.",
  29. (scaleX, scaleY, scaleZ, blocks, refBlock) =>
  30. {
  31. if (!GameState.IsBuildMode()) return; //Scaling & positioning is weird in simulation
  32. if (CheckNoBlocks(blocks)) return;
  33. // ReSharper disable once PossibleNullReferenceException
  34. float3 reference = refBlock.Position;
  35. float3 scale = new float3(scaleX, scaleY, scaleZ);
  36. foreach (var block in blocks)
  37. {
  38. block.Scale *= scale;
  39. block.Position = reference + (block.Position - reference) * scale;
  40. }
  41. Logging.CommandLog("Blocks scaled.");
  42. });
  43. RegisterBlockCommand("scaleIndividually", "Scales the blocks you're looking at, but doesn't move them." +
  44. "The scale is relative, 1 means no change. Look at a block previously scaled to scale all of the blocks that were connected to it.",
  45. (scaleX, scaleY, scaleZ, blocks, refBlock) =>
  46. {
  47. if (!GameState.IsBuildMode()) return; //Scaling & positioning is weird in simulation
  48. float3 scale = new float3(scaleX, scaleY, scaleZ);
  49. foreach (var block in blocks)
  50. block.Scale *= scale;
  51. });
  52. RegisterBlockCommand("moveBlocks", "Moves the blocks around.", (x, y, z, blocks, refBlock) =>
  53. {
  54. if (GameState.IsBuildMode())
  55. foreach (var block in blocks)
  56. block.Position += new float3(x, y, z);
  57. else if (GameState.IsSimulationMode())
  58. foreach (var body in GetSimBodies(blocks))
  59. body.Position += new float3(x, y, z);
  60. });
  61. RegisterBlockCommand("colorBlocks", "Colors the blocks you're looking at",
  62. (color, darkness, blocks, refBlock) =>
  63. {
  64. if (!Enum.TryParse(color, true, out BlockColors clr))
  65. {
  66. Logging.CommandLogWarning("Color " + color + " not found");
  67. }
  68. foreach (var block in blocks)
  69. block.Color = new BlockColor {Color = clr, Darkness = darkness};
  70. });
  71. CommandBuilder.Builder("selectBlocksLookedAt",
  72. "Selects blocks (1 or more) to change. Only works in build mode, however the blocks can be changed afterwards." +
  73. " Paramter: whether one (true) or all connected (false) blocks should be selected.")
  74. .Action<bool>(single =>
  75. {
  76. refBlock = new Player(PlayerType.Local).GetBlockLookedAt();
  77. blocks = single ? new[] {refBlock} : refBlock?.GetConnectedCubes() ?? new Block[0];
  78. Logging.CommandLog(blocks == null ? "Selection cleared." : blocks.Length + " blocks selected.");
  79. }).Build();
  80. CommandBuilder.Builder("selectBlocksWithID", "Selects blocks with a specific object ID.")
  81. .Action<char>(id =>
  82. blocks = (refBlock = ObjectIdentifier.GetByID(id).FirstOrDefault())?.GetConnectedCubes() ??
  83. new Block[0]).Build();
  84. CommandBuilder.Builder("selectSelectedBlocks", "Selects blocks that are box selected by the player.")
  85. .Action(() =>
  86. {
  87. blocks = new Player(PlayerType.Local).GetSelectedBlocks();
  88. refBlock = blocks.Length > 0 ? blocks[0] : null;
  89. }).Build();
  90. ConsoleCommands.RegisterWithChannel("selectSendSignal", ch => { }, ChannelType.Object,
  91. "Sends a signal for selecting a given object ID for a command block.");
  92. RegisterBlockCommand("pushBlocks", "Adds velocity to the selected blocks. Only works in simulation.",
  93. (x, y, z, blocks, refBlock) =>
  94. {
  95. foreach (var block in GetSimBodies(blocks))
  96. block.Velocity += new float3(x, y, z);
  97. });
  98. RegisterBlockCommand("pushRotateBlocks",
  99. "Adds angular velocity to the selected blocks. Only works in simulation.",
  100. (x, y, z, blocks, refBlock) =>
  101. {
  102. foreach (var block in GetSimBodies(blocks))
  103. block.AngularVelocity += new float3(x, y, z);
  104. });
  105. CommandBuilder.Builder("pushPlayer", "Adds velocity to the player.")
  106. .Action<float, float, float>((x, y, z) =>
  107. {
  108. new Player(PlayerType.Local).Velocity += new float3(x, y, z);
  109. }).Build();
  110. CommandBuilder.Builder("pushRotatePlayer", "Adds angular velocity to the player.")
  111. .Action<float, float, float>((x, y, z) =>
  112. {
  113. new Player(PlayerType.Local).AngularVelocity += new float3(x, y, z);
  114. }).Build();
  115. }
  116. private string GetBlockInfo()
  117. {
  118. if (GameState.IsBuildMode())
  119. return GetBlockInfoInBuildMode();
  120. if (GameState.IsSimulationMode())
  121. return GetBodyInfoInSimMode();
  122. return "Switching modes...";
  123. }
  124. private static string GetBlockInfoInBuildMode()
  125. {
  126. var block = new Player(PlayerType.Local).GetBlockLookedAt();
  127. if (block == null) return "";
  128. float3 pos = block.Position;
  129. float3 rot = block.Rotation;
  130. float3 scale = block.Scale;
  131. return $"Block: {block.Type} at {pos.x:F} {pos.y:F} {pos.z:F}\n" +
  132. $"- Rotation: {rot.x:F}° {rot.y:F}° {rot.z:F}°\n" +
  133. $"- Color: {block.Color.Color} darkness: {block.Color.Darkness}\n" +
  134. $"- Scale: {scale.x:F} {scale.y:F} {scale.z:F}\n" +
  135. $"- Label: {block.Label}\n" +
  136. $"- ID: {block.Id}";
  137. }
  138. private static string GetBodyInfoInSimMode()
  139. {
  140. var body = new Player(PlayerType.Local).GetSimBodyLookedAt();
  141. if (body == null) return GetBlockInfoInBuildMode();
  142. float3 pos = body.Position;
  143. float3 rot = body.Rotation;
  144. float3 vel = body.Velocity;
  145. float3 ave = body.AngularVelocity;
  146. float3 com = body.CenterOfMass;
  147. return $"Body at {pos.x:F} {pos.y:F} {pos.z:F}\n" +
  148. $"- Rotation: {rot.x:F}° {rot.y:F}° {rot.z:F}°\n" +
  149. $"- Velocity: {vel.x:F} {vel.y:F} {vel.z:F}\n" +
  150. $"- Angular velocity: {ave.x:F} {ave.y:F} {ave.z:F}\n" +
  151. $"- {(body.Static ? "Static body" : $"Mass: {body.Mass:F} center: {com.x:F} {com.y:F} {com.z:F}")}";
  152. }
  153. private bool CheckNoBlocks(Block[] blocks)
  154. {
  155. if (blocks.Length == 0)
  156. {
  157. Logging.CommandLogWarning("No blocks selected. Use selectBlocks first.");
  158. return true;
  159. }
  160. return false;
  161. }
  162. private IEnumerable<SimBody> GetSimBodies(Block[] blocks)
  163. => blocks.Select(block => block.GetSimBody()).Distinct();
  164. private Block[] SelectBlocks(byte id)
  165. {
  166. var blocks = ObjectIdentifier.GetBySimID(id).SelectMany(block => block.GetConnectedCubes()).ToArray();
  167. return blocks;
  168. }
  169. private Block[] SelectBlocks(char id)
  170. {
  171. var blocks = ObjectIdentifier.GetByID(id).SelectMany(oid => oid.GetConnectedCubes())
  172. .ToArray();
  173. return blocks;
  174. }
  175. private void RegisterBlockCommandInternal(string name, string desc, Action<string, Block[], Block> action)
  176. {
  177. RuntimeCommands.Register<string>(name, a1 =>
  178. {
  179. action(a1, blocks, refBlock);
  180. }, desc);
  181. ConsoleCommands.RegisterWithChannel<string>(name, (a1, ch) =>
  182. {
  183. Console.WriteLine($"Command {name} with args {a1} and channel {ch} executing");
  184. var blks = SelectBlocks(ch);
  185. action(a1, blks, blks[0]);
  186. }, ChannelType.Object, desc);
  187. }
  188. private void RegisterBlockCommand(string name, string desc, Action<float, float, float, Block[], Block> action)
  189. {
  190. RegisterBlockCommandInternal(name, desc, (args, bs, b) =>
  191. {
  192. var argsa = args.Split(' ');
  193. if (argsa.Length < 3)
  194. {
  195. Log.Error("Too few arguments. Needed arguments are: <x> <y> <z> and [id] is optional.");
  196. return;
  197. }
  198. if (!float.TryParse(argsa[0], out float x) || !float.TryParse(argsa[1], out float y) ||
  199. !float.TryParse(argsa[2], out float z))
  200. {
  201. Log.Error("Could not parse arguments as floats.");
  202. return;
  203. }
  204. if (argsa.Length > 3)
  205. {
  206. if (argsa[3].Length == 0)
  207. {
  208. Log.Error("Missing channel.");
  209. return;
  210. }
  211. var blocks = SelectBlocks(argsa[3][0]);
  212. if (CheckNoBlocks(blocks)) return;
  213. action(x, y, z, blocks, blocks[0]);
  214. }
  215. else if (!CheckNoBlocks(bs))
  216. action(x, y, z, bs, b);
  217. });
  218. }
  219. private void RegisterBlockCommand(string name, string desc, Action<string, byte, Block[], Block> action)
  220. {
  221. RegisterBlockCommandInternal(name, desc, (args, bs, b) =>
  222. {
  223. var argsa = args.Split(' ');
  224. if (argsa.Length < 2)
  225. {
  226. Log.Error("Too few arguments. Needed arguments are: <color> <darkness> and [id] is optional.");
  227. return;
  228. }
  229. if (!byte.TryParse(argsa[1], out byte darkness))
  230. {
  231. Log.Error("Could not parse color darkness.");
  232. return;
  233. }
  234. if (argsa.Length > 2)
  235. {
  236. if (argsa[2].Length == 0)
  237. {
  238. Log.Error("Missing channel.");
  239. return;
  240. }
  241. var blocks = SelectBlocks(argsa[2][0]);
  242. if (CheckNoBlocks(blocks)) return;
  243. action(argsa[0], darkness, blocks, blocks[0]);
  244. }
  245. else if(!CheckNoBlocks(bs))
  246. action(argsa[0], darkness, bs, b);
  247. });
  248. }
  249. public void OnApplicationQuit()
  250. {
  251. }
  252. public void OnLevelWasLoaded(int level)
  253. {
  254. }
  255. public void OnLevelWasInitialized(int level)
  256. {
  257. }
  258. public void OnUpdate()
  259. {
  260. }
  261. public void OnFixedUpdate()
  262. {
  263. }
  264. public string Name { get; } = "BlockMod";
  265. public string Version { get; } = "v1.0.0";
  266. }
  267. }