Magically import images and more into Gamecraft as blocks
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.

149 lines
5.0KB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Security.Cryptography;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. using Svelto.DataStructures;
  8. using Unity.Mathematics;
  9. using UnityEngine;
  10. using GamecraftModdingAPI;
  11. using GamecraftModdingAPI.Blocks;
  12. using GamecraftModdingAPI.Players;
  13. using GamecraftModdingAPI.Utility;
  14. using Pixi.Common;
  15. namespace Pixi.Robots
  16. {
  17. public class RobotInternetImporter : Importer
  18. {
  19. public int Priority { get; } = -100;
  20. public bool Optimisable { get; } = false;
  21. public string Name { get; } = "RobocraftRobot~Spell";
  22. public BlueprintProvider BlueprintProvider { get; }
  23. public static int CubeSize = 3;
  24. public RobotInternetImporter()
  25. {
  26. BlueprintProvider = new RobotBlueprintProvider(this);
  27. }
  28. public bool Qualifies(string name)
  29. {
  30. string[] extensions = name.Split('.');
  31. return extensions.Length == 1
  32. || !extensions[extensions.Length - 1].Contains(" ");
  33. }
  34. public BlockJsonInfo[] Import(string name)
  35. {
  36. // download robot data
  37. RobotStruct robot;
  38. try
  39. {
  40. RobotBriefStruct[] botList = RoboAPIUtility.ListRobots(name);
  41. if (botList.Length == 0)
  42. throw new Exception("Failed to find robot");
  43. robot = RoboAPIUtility.QueryRobotInfo(botList[0].itemId);
  44. }
  45. catch (Exception e)
  46. {
  47. Logging.CommandLogError($"Failed to download robot data. Reason: {e.Message}");
  48. Logging.MetaLog(e);
  49. return new BlockJsonInfo[0];
  50. }
  51. CubeInfo[] cubes = CubeUtility.ParseCubes(robot);
  52. // move bot closer to origin (since bots are rarely built at the garage bay origin of the bottom south-west corner)
  53. if (cubes.Length == 0)
  54. {
  55. Logging.CommandLogError($"Robot data contains no cubes");
  56. return new BlockJsonInfo[0];
  57. }
  58. float3 minPosition = cubes[0].position;
  59. for (int c = 0; c < cubes.Length; c++)
  60. {
  61. float3 cubePos = cubes[c].position;
  62. if (cubePos.x < minPosition.x)
  63. {
  64. minPosition.x = cubePos.x;
  65. }
  66. if (cubePos.y < minPosition.y)
  67. {
  68. minPosition.y = cubePos.y;
  69. }
  70. if (cubePos.z < minPosition.z)
  71. {
  72. minPosition.z = cubePos.z;
  73. }
  74. }
  75. BlockJsonInfo[] blocks = new BlockJsonInfo[cubes.Length];
  76. for (int c = 0; c < cubes.Length; c++)
  77. {
  78. ref CubeInfo cube = ref cubes[c];
  79. float3 realPosition = ((cube.position - minPosition) * CommandRoot.BLOCK_SIZE * CubeSize);
  80. if (cube.block == BlockIDs.TextBlock && !string.IsNullOrEmpty(cube.name))
  81. {
  82. // TextBlock block ID means it's a placeholder
  83. blocks[c] = new BlockJsonInfo
  84. {
  85. color = ColorSpaceUtility.UnquantizeToArray(cube.color, cube.darkness),
  86. name = cube.cubeId.ToString(),
  87. position = ConversionUtility.Float3ToFloatArray(realPosition),
  88. rotation = ConversionUtility.Float3ToFloatArray(cube.rotation),
  89. scale = ConversionUtility.Float3ToFloatArray(cube.scale)
  90. };
  91. }
  92. else
  93. {
  94. blocks[c] = new BlockJsonInfo
  95. {
  96. color = ColorSpaceUtility.UnquantizeToArray(cube.color, cube.darkness),
  97. name = cube.block.ToString(),
  98. position = ConversionUtility.Float3ToFloatArray(realPosition),
  99. rotation = ConversionUtility.Float3ToFloatArray(cube.rotation),
  100. scale = ConversionUtility.Float3ToFloatArray(cube.scale * CubeSize)
  101. };
  102. }
  103. }
  104. return blocks;
  105. }
  106. public void PreProcess(string name, ref ProcessedVoxelObjectNotation[] blocks)
  107. {
  108. Player p = new Player(PlayerType.Local);
  109. float3 pos = p.Position;
  110. for (int i = 0; i < blocks.Length; i++)
  111. {
  112. blocks[i].position += pos;
  113. }
  114. // set textblock colors (replace <color="white"> with <color=#HEX> in textblocks)
  115. Regex pattern = new Regex("<color=((?:\"white\")|(?:white))>", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
  116. for (int i = 0; i < blocks.Length; i++)
  117. {
  118. if (blocks[i].block == BlockIDs.TextBlock)
  119. {
  120. // TODO this blindly replaces color tags anywhere in metadata, not just ones that will go in the TextBlock's text field
  121. #if DEBUG
  122. Logging.MetaLog($"Replacing text field in block with colour {blocks[i].color} with #{ColorUtility.ToHtmlStringRGBA(ColorSpaceUtility.UnquantizeToColor(blocks[i].color))}");
  123. #endif
  124. blocks[i].metadata = pattern.Replace(
  125. blocks[i].metadata,
  126. $"<color=#{ColorUtility.ToHtmlStringRGBA(ColorSpaceUtility.UnquantizeToColor(blocks[i].color))}>");
  127. // NOTE: Regex.Replace replaces the whole match string only when there's a capture group (it's dumb, idk why).
  128. // The non-capturing groups may be messing with .NET or something
  129. }
  130. }
  131. }
  132. public void PostProcess(string name, ref Block[] blocks)
  133. {
  134. }
  135. }
  136. }