A stable modding interface between Techblox and mods https://mod.exmods.org/
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

280 строки
9.8KB

  1. using System;
  2. using System.Diagnostics;
  3. using System.Reflection;
  4. using System.Text;
  5. using TechbloxModdingAPI.App;
  6. using HarmonyLib;
  7. using IllusionInjector;
  8. // test
  9. using RobocraftX.FrontEnd;
  10. using Unity.Mathematics;
  11. using UnityEngine;
  12. using RobocraftX.Common.Input;
  13. using TechbloxModdingAPI.Blocks;
  14. using TechbloxModdingAPI.Commands;
  15. using TechbloxModdingAPI.Input;
  16. using TechbloxModdingAPI.Players;
  17. using TechbloxModdingAPI.Utility;
  18. namespace TechbloxModdingAPI.Tests
  19. {
  20. #if DEBUG
  21. // unused by design
  22. /// <summary>
  23. /// Modding API implemented as a standalone IPA Plugin.
  24. /// Ideally, TechbloxModdingAPI should be loaded by another mod; not itself
  25. /// </summary>
  26. public class TechbloxModdingAPIPluginTest : IllusionPlugin.IEnhancedPlugin
  27. {
  28. private static Harmony harmony { get; set; }
  29. public override string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name;
  30. public override string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString();
  31. public string HarmonyID { get; } = "org.git.exmods.modtainers.techbloxmoddingapi";
  32. public override void OnApplicationQuit()
  33. {
  34. Main.Shutdown();
  35. }
  36. public override void OnApplicationStart()
  37. {
  38. FileLog.Reset();
  39. Harmony.DEBUG = true;
  40. Main.Init();
  41. Logging.MetaDebugLog($"Version group id {(uint)ApiExclusiveGroups.versionGroup}");
  42. // disable background music
  43. Logging.MetaDebugLog("Audio Mixers: " + string.Join(",", AudioTools.GetMixers()));
  44. //AudioTools.SetVolume(0.0f, "Music"); // The game now sets this from settings again after this is called :(
  45. //Utility.VersionTracking.Enable();//(very) unstable
  46. // debug/test handlers
  47. Client.EnterMenu += (sender, args) => throw new Exception("Test handler always throws an exception!");
  48. // debug/test commands
  49. if (Dependency.Hell("ExtraCommands"))
  50. {
  51. CommandBuilder.Builder()
  52. .Name("Exit")
  53. .Description("Close Techblox immediately, without any prompts")
  54. .Action(() => { UnityEngine.Application.Quit(); })
  55. .Build();
  56. CommandBuilder.Builder()
  57. .Name("SetFOV")
  58. .Description("Set the player camera's field of view")
  59. .Action((float d) => { UnityEngine.Camera.main.fieldOfView = d; })
  60. .Build();
  61. CommandBuilder.Builder()
  62. .Name("MoveLastBlock")
  63. .Description("Move the most-recently-placed block, and any connected blocks by the given offset")
  64. .Action((float x, float y, float z) =>
  65. {
  66. if (GameState.IsBuildMode())
  67. foreach (var block in Block.GetLastPlacedBlock().GetConnectedCubes())
  68. block.Position += new Unity.Mathematics.float3(x, y, z);
  69. else
  70. Logging.CommandLogError("Blocks can only be moved in Build mode!");
  71. }).Build();
  72. CommandBuilder.Builder()
  73. .Name("PlaceAluminium")
  74. .Description("Place a block of aluminium at the given coordinates")
  75. .Action((float x, float y, float z) =>
  76. {
  77. var block = Block.PlaceNew(BlockIDs.Cube, new float3(x, y, z));
  78. Logging.CommandLog("Block placed with type: " + block.Type);
  79. })
  80. .Build();
  81. CommandBuilder.Builder()
  82. .Name("PlaceAluminiumLots")
  83. .Description("Place a lot of blocks of aluminium at the given coordinates")
  84. .Action((float x, float y, float z) =>
  85. {
  86. Logging.CommandLog("Starting...");
  87. var sw = Stopwatch.StartNew();
  88. for (int i = 0; i < 100; i++)
  89. for (int j = 0; j < 100; j++)
  90. Block.PlaceNew(BlockIDs.Cube, new float3(x + i, y, z + j));
  91. sw.Stop();
  92. Logging.CommandLog("Finished in " + sw.ElapsedMilliseconds + "ms");
  93. })
  94. .Build();
  95. Block b = null;
  96. CommandBuilder.Builder("moveBlockInSim", "Run in build mode first while looking at a block, then in sim to move it up")
  97. .Action(() =>
  98. {
  99. if (b == null)
  100. {
  101. b = new Player(PlayerType.Local).GetBlockLookedAt();
  102. Logging.CommandLog("Block saved: " + b);
  103. }
  104. else
  105. Logging.CommandLog("Block moved to: " + (b.GetSimBody().Position += new float3(0, 2, 0)));
  106. }).Build();
  107. CommandBuilder.Builder("Error", "Throw an error to make sure SimpleCustomCommandEngine's wrapper catches it.")
  108. .Action(() => { throw new Exception("Error Command always throws an error"); })
  109. .Build();
  110. CommandBuilder.Builder("ColorBlock",
  111. "Change color of the block looked at if there's any.")
  112. .Action<string>(str =>
  113. {
  114. if (!Enum.TryParse(str, out BlockColors color))
  115. {
  116. Logging.CommandLog("Color " + str + " not found! Interpreting as 4 color values.");
  117. var s = str.Split(' ');
  118. new Player(PlayerType.Local).GetBlockLookedAt().CustomColor = new float4(float.Parse(s[0]),
  119. float.Parse(s[1]), float.Parse(s[2]), float.Parse(s[3]));
  120. return;
  121. }
  122. new Player(PlayerType.Local).GetBlockLookedAt().Color = color;
  123. Logging.CommandLog("Colored block to " + color);
  124. }).Build();
  125. CommandBuilder.Builder("MoveBlockByID", "Gets a block based on its object identifier and teleports it up.")
  126. .Action<char>(ch =>
  127. {
  128. foreach (var body in SimBody.GetFromObjectID(ch))
  129. {
  130. Logging.CommandLog("SimBody: " + body);
  131. body.Position += new float3(0, 10, 0);
  132. foreach (var bodyConnectedBody in body.GetConnectedBodies())
  133. {
  134. Logging.CommandLog("Moving " + bodyConnectedBody);
  135. bodyConnectedBody.Position += new float3(0, 10, 0);
  136. }
  137. }
  138. }).Build();
  139. CommandBuilder.Builder("TestChunkHealth", "Sets the chunk looked at to the given health.")
  140. .Action((float val, float max) =>
  141. {
  142. var body = new Player(PlayerType.Local).GetSimBodyLookedAt();
  143. if (body == null) return;
  144. body.CurrentHealth = val;
  145. body.InitialHealth = max;
  146. Logging.CommandLog("Health set to: " + val);
  147. }).Build();
  148. CommandBuilder.Builder("placeBlockGroup", "Places some blocks in a group")
  149. .Action((float x, float y, float z) =>
  150. {
  151. var pos = new float3(x, y, z);
  152. var group = BlockGroup.Create(new Block(BlockIDs.Cube, pos) {Color = BlockColors.Aqua});
  153. new Block(BlockIDs.Cube, pos += new float3(1, 0, 0))
  154. {Color = BlockColors.Blue, BlockGroup = group};
  155. new Block(BlockIDs.Cube, pos += new float3(1, 0, 0))
  156. {Color = BlockColors.Green, BlockGroup = group};
  157. new Block(BlockIDs.Cube, pos + new float3(1, 0, 0))
  158. {Color = BlockColors.Lime, BlockGroup = group};
  159. }).Build();
  160. CommandBuilder.Builder("placeCustomBlock", "Places a custom block, needs a custom catalog and assets.")
  161. .Action((float x, float y, float z) =>
  162. {
  163. Logging.CommandLog("Block placed: " +
  164. Block.PlaceNew((BlockIDs) 500, new float3(0, 0, 0)));
  165. }).Build();
  166. CommandBuilder.Builder("toggleTimeMode", "Enters or exits simulation.")
  167. .Action((float x, float y, float z) =>
  168. {
  169. Game.CurrentGame().ToggleTimeMode();
  170. }).Build();
  171. GameClient.SetDebugInfo("InstalledMods", InstalledMods);
  172. Block.Placed += (sender, args) =>
  173. Logging.MetaDebugLog("Placed block " + args.Block);
  174. Block.Removed += (sender, args) =>
  175. Logging.MetaDebugLog("Removed block " + args.Block);
  176. }
  177. // dependency test
  178. if (Dependency.Hell("TechbloxScripting", new Version("0.0.1.0")))
  179. {
  180. Logging.LogWarning("You're in TechbloxScripting dependency hell");
  181. }
  182. else
  183. {
  184. Logging.Log("Compatible TechbloxScripting detected");
  185. }
  186. // Interface test
  187. /*Interface.IMGUI.Group uiGroup = new Group(new Rect(20, 20, 200, 500), "TechbloxModdingAPI_UITestGroup", true);
  188. Interface.IMGUI.Button button = new Button("TEST");
  189. button.OnClick += (b, __) => { Logging.MetaDebugLog($"Click on {((Interface.IMGUI.Button)b).Name}");};
  190. Interface.IMGUI.Button button2 = new Button("TEST2");
  191. button2.OnClick += (b, __) => { Logging.MetaDebugLog($"Click on {((Interface.IMGUI.Button)b).Name}");};
  192. Text uiText = new Text("This is text!", multiline: true);
  193. uiText.OnEdit += (t, txt) => { Logging.MetaDebugLog($"Text in {((Text)t).Name} is now '{txt}'"); };
  194. Label uiLabel = new Label("Label!");
  195. Image uiImg = new Image(name:"Behold this texture!");
  196. uiImg.Enabled = false;
  197. uiGroup.AddElement(button);
  198. uiGroup.AddElement(button2);
  199. uiGroup.AddElement(uiText);
  200. uiGroup.AddElement(uiLabel);
  201. uiGroup.AddElement(uiImg);*/
  202. /*Addressables.LoadAssetAsync<Texture2D>("Assets/Art/Textures/UI/FrontEndMap/RCX_Blue_Background_5k.jpg")
  203. .Completed +=
  204. handle =>
  205. {
  206. uiImg.Texture = handle.Result;
  207. uiImg.Enabled = true;
  208. Logging.MetaDebugLog($"Got blue bg asset {handle.Result}");
  209. };*/
  210. /*((FasterList<GuiInputMap.GuiInputMapElement>)AccessTools.Property(typeof(GuiInputMap), "GuiInputsButtonDown").GetValue(null))
  211. .Add(new GuiInputMap.GuiInputMapElement(RewiredConsts.Action.ToggleCommandLine, GuiIn))*/
  212. #if TEST
  213. TestRoot.RunTests();
  214. #endif
  215. }
  216. private string modsString;
  217. private string InstalledMods()
  218. {
  219. if (modsString != null) return modsString;
  220. StringBuilder sb = new StringBuilder("Installed mods:");
  221. foreach (var plugin in PluginManager.Plugins)
  222. sb.Append("\n" + plugin.Name + " - " + plugin.Version);
  223. return modsString = sb.ToString();
  224. }
  225. public override void OnUpdate()
  226. {
  227. if (UnityEngine.Input.GetKeyDown(KeyCode.End))
  228. {
  229. Console.WriteLine("Pressed button to toggle console");
  230. FakeInput.CustomInput(new LocalInputEntityStruct {commandLineToggleInput = true});
  231. }
  232. }
  233. [HarmonyPatch]
  234. public class MinimumSpecsPatch
  235. {
  236. public static bool Prefix()
  237. {
  238. return false;
  239. }
  240. public static MethodInfo TargetMethod()
  241. {
  242. return ((Action) MinimumSpecsCheck.CheckRequirementsMet).Method;
  243. }
  244. }
  245. }
  246. #endif
  247. }