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.

GamecraftModdingAPIPluginTest.cs 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. using System;
  2. using System.Linq;
  3. using System.Reflection;
  4. using HarmonyLib;
  5. // test
  6. using Svelto.ECS;
  7. using RobocraftX.Blocks;
  8. using RobocraftX.Common;
  9. using RobocraftX.SimulationModeState;
  10. using GamecraftModdingAPI.Commands;
  11. using GamecraftModdingAPI.Events;
  12. using GamecraftModdingAPI.Utility;
  13. using GamecraftModdingAPI.Blocks;
  14. using RobocraftX.FrontEnd;
  15. namespace GamecraftModdingAPI.Tests
  16. {
  17. // unused by design
  18. /// <summary>
  19. /// Modding API implemented as a standalone IPA Plugin.
  20. /// Ideally, GamecraftModdingAPI should be loaded by another mod; not itself
  21. /// </summary>
  22. public class GamecraftModdingAPIPluginTest
  23. #if DEBUG
  24. : IllusionPlugin.IEnhancedPlugin
  25. #endif
  26. {
  27. private static Harmony harmony { get; set; }
  28. public string[] Filter { get; } = new string[] { "Gamecraft", "GamecraftPreview" };
  29. public string Name { get; } = Assembly.GetExecutingAssembly().GetName().Name;
  30. public string Version { get; } = Assembly.GetExecutingAssembly().GetName().Version.ToString();
  31. public string HarmonyID { get; } = "org.git.exmods.modtainers.gamecraftmoddingapi";
  32. public void OnApplicationQuit()
  33. {
  34. GamecraftModdingAPI.Main.Shutdown();
  35. }
  36. public void OnApplicationStart()
  37. {
  38. FileLog.Reset();
  39. Harmony.DEBUG = true;
  40. GamecraftModdingAPI.Main.Init();
  41. Logging.MetaDebugLog($"Version group id {(uint)ApiExclusiveGroups.versionGroup}");
  42. // in case Steam is not installed/running
  43. // this will crash the game slightly later during startup
  44. //SteamInitPatch.ForcePassSteamCheck = true;
  45. // in case running in a VM
  46. //MinimumSpecsCheckPatch.ForcePassMinimumSpecCheck = true;
  47. // disable some Gamecraft analytics
  48. //AnalyticsDisablerPatch.DisableAnalytics = true;
  49. // disable background music
  50. Logging.MetaDebugLog("Audio Mixers: "+string.Join(",", AudioTools.GetMixers()));
  51. //AudioTools.SetVolume(0.0f, "Music"); // The game now sets this from settings again after this is called :(
  52. Utility.VersionTracking.Enable();
  53. // debug/test handlers
  54. HandlerBuilder.Builder()
  55. .Name("appinit API debug")
  56. .Handle(EventType.ApplicationInitialized)
  57. .OnActivation(() => { Logging.Log("App Inited event!"); })
  58. .Build();
  59. HandlerBuilder.Builder("menuact API debug")
  60. .Handle(EventType.Menu)
  61. .OnActivation(() => { Logging.Log("Menu Activated event!"); })
  62. .OnDestruction(() => { Logging.Log("Menu Destroyed event!"); })
  63. .Build();
  64. HandlerBuilder.Builder("menuswitch API debug")
  65. .Handle(EventType.MenuSwitchedTo)
  66. .OnActivation(() => { Logging.Log("Menu Switched To event!"); })
  67. .Build();
  68. HandlerBuilder.Builder("gameact API debug")
  69. .Handle(EventType.Menu)
  70. .OnActivation(() => { Logging.Log("Game Activated event!"); })
  71. .OnDestruction(() => { Logging.Log("Game Destroyed event!"); })
  72. .Build();
  73. HandlerBuilder.Builder("gamerel API debug")
  74. .Handle(EventType.GameReloaded)
  75. .OnActivation(() => { Logging.Log("Game Reloaded event!"); })
  76. .Build();
  77. HandlerBuilder.Builder("gameswitch API debug")
  78. .Handle(EventType.GameSwitchedTo)
  79. .OnActivation(() => { Logging.Log("Game Switched To event!"); })
  80. .Build();
  81. HandlerBuilder.Builder("simulationswitch API debug")
  82. .Handle(EventType.SimulationSwitchedTo)
  83. .OnActivation(() => { Logging.Log("Game Mode Simulation Switched To event!"); })
  84. .Build();
  85. HandlerBuilder.Builder("buildswitch API debug")
  86. .Handle(EventType.BuildSwitchedTo)
  87. .OnActivation(() => { Logging.Log("Game Mode Build Switched To event!"); })
  88. .Build();
  89. HandlerBuilder.Builder("menu activated API error thrower test")
  90. .Handle(EventType.Menu)
  91. .OnActivation(() => { throw new Exception("Event Handler always throws an exception!"); })
  92. .Build();
  93. // debug/test commands
  94. if (Dependency.Hell("ExtraCommands"))
  95. {
  96. CommandBuilder.Builder()
  97. .Name("Exit")
  98. .Description("Close Gamecraft immediately, without any prompts")
  99. .Action(() => { UnityEngine.Application.Quit(); })
  100. .Build();
  101. CommandBuilder.Builder()
  102. .Name("SetFOV")
  103. .Description("Set the player camera's field of view")
  104. .Action((float d) => { UnityEngine.Camera.main.fieldOfView = d; })
  105. .Build();
  106. CommandBuilder.Builder()
  107. .Name("MoveLastBlock")
  108. .Description("Move the most-recently-placed block, and any connected blocks by the given offset")
  109. .Action((float x, float y, float z) =>
  110. {
  111. if (GameState.IsBuildMode())
  112. foreach (var block in Block.GetLastPlacedBlock().GetConnectedCubes())
  113. block.Position += new Unity.Mathematics.float3(x, y, z);
  114. else
  115. GamecraftModdingAPI.Utility.Logging.CommandLogError("Blocks can only be moved in Build mode!");
  116. }).Build();
  117. CommandBuilder.Builder()
  118. .Name("PlaceAluminium")
  119. .Description("Place a block of aluminium at the given coordinates")
  120. .Action((float x, float y, float z) => { Block.PlaceNew(Blocks.BlockIDs.AluminiumCube, new Unity.Mathematics.float3(x, y, z)); })
  121. .Build();
  122. System.Random random = new System.Random(); // for command below
  123. CommandBuilder.Builder()
  124. .Name("RandomizeSignalsInputs")
  125. .Description("Do the thing")
  126. .Action(() => {
  127. if (!GameState.IsSimulationMode())
  128. {
  129. Logging.CommandLogError("You must be in simulation mode for this to work!");
  130. return;
  131. }
  132. Tasks.Repeatable task = new Tasks.Repeatable(
  133. () => {
  134. uint count = 0;
  135. EGID[] eBlocks = Blocks.Signals.GetElectricBlocks();
  136. for (uint i = 0u; i < eBlocks.Length; i++)
  137. {
  138. uint[] ids = Blocks.Signals.GetSignalIDs(eBlocks[i]);
  139. for (uint j = 0u; j < ids.Length; j++)
  140. {
  141. Blocks.Signals.SetSignalByID(ids[j], (float)random.NextDouble());
  142. count++;
  143. }
  144. }
  145. Logging.MetaDebugLog($"Did the thing on {count} inputs");
  146. },
  147. () => { return GameState.IsSimulationMode(); });
  148. Tasks.Scheduler.Schedule(task);
  149. }).Build();
  150. CommandBuilder.Builder("getBlock")
  151. .Action(() => uREPL.Log.Output(new Player(Players.PlayerType.Local).GetBlockLookedAt()+"")).Build();
  152. CommandBuilder.Builder("Error", "Throw an error to make sure SimpleCustomCommandEngine's wrapper catches it.")
  153. .Action(() => { throw new Exception("Error Command always throws an error"); })
  154. .Build();
  155. GameClient.SetDebugInfo("lookedAt", LookedAt);
  156. /*
  157. CommandManager.AddCommand(new SimpleCustomCommandEngine<float>((float d) => { UnityEngine.Camera.main.fieldOfView = d; },
  158. "SetFOV", "Set the player camera's field of view"));
  159. CommandManager.AddCommand(new SimpleCustomCommandEngine<float, float, float>(
  160. (x, y, z) => {
  161. bool success = GamecraftModdingAPI.Blocks.Movement.MoveConnectedBlocks(
  162. GamecraftModdingAPI.Blocks.BlockIdentifiers.LatestBlockID,
  163. new Unity.Mathematics.float3(x, y, z));
  164. if (!success)
  165. {
  166. GamecraftModdingAPI.Utility.Logging.CommandLogError("Blocks can only be moved in Build mode!");
  167. }
  168. }, "MoveLastBlock", "Move the most-recently-placed block, and any connected blocks by the given offset"));
  169. CommandManager.AddCommand(new SimpleCustomCommandEngine<float, float, float>(
  170. (x, y, z) => { Blocks.Placement.PlaceBlock(Blocks.BlockIDs.AluminiumCube, new Unity.Mathematics.float3(x, y, z)); },
  171. "PlaceAluminium", "Place a block of aluminium at the given coordinates"));
  172. System.Random random = new System.Random(); // for command below
  173. CommandManager.AddCommand(new SimpleCustomCommandEngine(
  174. () => {
  175. if (!GameState.IsSimulationMode())
  176. {
  177. Logging.CommandLogError("You must be in simulation mode for this to work!");
  178. return;
  179. }
  180. Tasks.Repeatable task = new Tasks.Repeatable(() => {
  181. uint count = 0;
  182. EGID[] eBlocks = Blocks.Signals.GetElectricBlocks();
  183. for (uint i = 0u; i < eBlocks.Length; i++)
  184. {
  185. uint[] ids = Blocks.Signals.GetSignalIDs(eBlocks[i]);
  186. for (uint j = 0u; j < ids.Length; j++)
  187. {
  188. Blocks.Signals.SetSignalByID(ids[j], (float)random.NextDouble());
  189. count++;
  190. }
  191. }
  192. Logging.MetaDebugLog($"Did the thing on {count} inputs");
  193. },
  194. () => { return GameState.IsSimulationMode(); });
  195. Tasks.Scheduler.Schedule(task);
  196. }, "RandomizeSignalsInputs", "Do the thing"));
  197. */
  198. }
  199. // dependency test
  200. if (Dependency.Hell("GamecraftScripting", new Version("0.0.1.0")))
  201. {
  202. Logging.LogWarning("You're in GamecraftScripting dependency hell");
  203. }
  204. else
  205. {
  206. Logging.Log("Compatible GamecraftScripting detected");
  207. }
  208. }
  209. private Player player;
  210. private string LookedAt()
  211. {
  212. if (player == null)
  213. player = new Player(Players.PlayerType.Local);
  214. Block block = player.GetBlockLookedAt();
  215. if (block == null) return "Block: none";
  216. return "Block: " + block.Type + "\nColor: " + block.Color + "\n" + "At: " + block.Position;
  217. }
  218. public void OnFixedUpdate() { }
  219. public void OnLateUpdate() { }
  220. public void OnLevelWasInitialized(int level) { }
  221. public void OnLevelWasLoaded(int level) { }
  222. public void OnUpdate() { }
  223. [HarmonyPatch]
  224. public class MinimumSpecsPatch
  225. {
  226. public static bool Prefix(ref bool __result)
  227. {
  228. __result = true;
  229. return false;
  230. }
  231. public static MethodInfo TargetMethod()
  232. {
  233. return ((Func<bool>)MinimumSpecsCheck.CheckRequirementsMet).Method;
  234. }
  235. }
  236. }
  237. }