public BlockJsonInfo[] Blueprint(string name, BlockJsonInfo root) { if (botprints == null) { botprints = BlueprintUtility.ParseBlueprintResource("Pixi.blueprints.json"); } if (!botprints.ContainsKey(root.name) || RobotInternetImporter.CubeSize != 3) { BlockJsonInfo copy = root; copy.name = $"TextBlock\t{root.name} ({CubeUtility.CubeIdDescription(uint.Parse(root.name))})\tPixi"; return(new BlockJsonInfo[1] { copy }); } BlockJsonInfo[] blueprint = botprints[root.name]; BlockJsonInfo[] adjustedBlueprint = new BlockJsonInfo[blueprint.Length]; Quaternion cubeQuaternion = Quaternion.Euler(ConversionUtility.FloatArrayToFloat3(root.rotation)); if (blueprint.Length == 0) { Logging.LogWarning($"Found empty blueprint for {root.name} (during '{name}'), is the blueprint correct?"); return(new BlockJsonInfo[0]); } // move blocks to correct position & rotation float3 defaultCorrectionVec = new float3((float)(0), (float)(CommandRoot.BLOCK_SIZE), (float)(0)); float3 baseRot = new float3(blueprint[0].rotation[0], blueprint[0].rotation[1], blueprint[0].rotation[2]); float3 baseScale = new float3(blueprint[0].scale[0], blueprint[0].scale[1], blueprint[0].scale[2]); //Block[] placedBlocks = new Block[blueprint.Length]; bool isBaseScaled = !(blueprint[0].scale[1] > 0f && blueprint[0].scale[1] < 2f); float3 correctionVec = isBaseScaled ? (float3)(Quaternion.Euler(baseRot) * baseScale / 2) * (float)-CommandRoot.BLOCK_SIZE : -defaultCorrectionVec; // FIXME scaled base blocks cause the blueprint to be placed in the wrong location (this also could be caused by a bug in DumpVON command) if (isBaseScaled) { Logging.LogWarning($"Found blueprint with scaled base block for {root.name} (during '{name}'), this is not currently supported"); } float3 rootPos = ConversionUtility.FloatArrayToFloat3(root.position); for (int i = 0; i < blueprint.Length; i++) { BlockColor blueprintBlockColor = ColorSpaceUtility.QuantizeToBlockColor(blueprint[i].color); float[] physicalColor = blueprintBlockColor.Color == BlockColors.White && blueprintBlockColor.Darkness == 0 ? root.color : blueprint[i].color; float3 bluePos = ConversionUtility.FloatArrayToFloat3(blueprint[i].position); float3 blueScale = ConversionUtility.FloatArrayToFloat3(blueprint[i].scale); float3 blueRot = ConversionUtility.FloatArrayToFloat3(blueprint[i].rotation); float3 physicalLocation = (float3)(cubeQuaternion * bluePos) + rootPos; // + (blueprintSizeRotated / 2); //physicalLocation.x += blueprintSize.x / 2; physicalLocation += (float3)(cubeQuaternion * (correctionVec)); //physicalLocation.y -= (float)(RobotCommands.blockSize * scale / 2); //float3 physicalScale = (float3)(cubeQuaternion * blueScale); // this actually over-rotates when combined with rotation float3 physicalScale = blueScale; float3 physicalRotation = (cubeQuaternion * Quaternion.Euler(blueRot)).eulerAngles; #if DEBUG Logging.MetaLog($"Placing blueprint block at {physicalLocation} rot{physicalRotation} scale{physicalScale}"); Logging.MetaLog($"Location math check original:{bluePos} rotated: {(float3)(cubeQuaternion * bluePos)} actualPos: {rootPos} result: {physicalLocation}"); Logging.MetaLog($"Scale math check original:{blueScale} rotation: {(float3)cubeQuaternion.eulerAngles} result: {physicalScale}"); Logging.MetaLog($"Rotation math check original:{blueRot} rotated: {(cubeQuaternion * Quaternion.Euler(blueRot))} result: {physicalRotation}"); #endif adjustedBlueprint[i] = new BlockJsonInfo { color = physicalColor, name = blueprint[i].name, position = ConversionUtility.Float3ToFloatArray(physicalLocation), rotation = ConversionUtility.Float3ToFloatArray(physicalRotation), scale = ConversionUtility.Float3ToFloatArray(physicalScale) }; } return(adjustedBlueprint); }
public BlockJsonInfo[] Import(string name) { // download robot data RobotStruct robot; try { RobotBriefStruct[] botList = RoboAPIUtility.ListRobots(name); if (botList.Length == 0) { throw new Exception("Failed to find robot"); } robot = RoboAPIUtility.QueryRobotInfo(botList[0].itemId); } catch (Exception e) { Logging.CommandLogError($"Failed to download robot data. Reason: {e.Message}"); Logging.MetaLog(e); return(new BlockJsonInfo[0]); } CubeInfo[] cubes = CubeUtility.ParseCubes(robot); // move bot closer to origin (since bots are rarely built at the garage bay origin of the bottom south-west corner) if (cubes.Length == 0) { Logging.CommandLogError($"Robot data contains no cubes"); return(new BlockJsonInfo[0]); } float3 minPosition = cubes[0].position; for (int c = 0; c < cubes.Length; c++) { float3 cubePos = cubes[c].position; if (cubePos.x < minPosition.x) { minPosition.x = cubePos.x; } if (cubePos.y < minPosition.y) { minPosition.y = cubePos.y; } if (cubePos.z < minPosition.z) { minPosition.z = cubePos.z; } } BlockJsonInfo[] blocks = new BlockJsonInfo[cubes.Length]; for (int c = 0; c < cubes.Length; c++) { ref CubeInfo cube = ref cubes[c]; float3 realPosition = ((cube.position - minPosition) * CommandRoot.BLOCK_SIZE * CubeSize); if (cube.block == BlockIDs.TextBlock && !string.IsNullOrEmpty(cube.name)) { // TextBlock block ID means it's a placeholder blocks[c] = new BlockJsonInfo { color = ColorSpaceUtility.UnquantizeToArray(cube.color, cube.darkness), name = cube.cubeId.ToString(), position = ConversionUtility.Float3ToFloatArray(realPosition), rotation = ConversionUtility.Float3ToFloatArray(cube.rotation), scale = ConversionUtility.Float3ToFloatArray(cube.scale) }; } else { blocks[c] = new BlockJsonInfo { color = ColorSpaceUtility.UnquantizeToArray(cube.color, cube.darkness), name = cube.block.ToString(), position = ConversionUtility.Float3ToFloatArray(realPosition), rotation = ConversionUtility.Float3ToFloatArray(cube.rotation), scale = ConversionUtility.Float3ToFloatArray(cube.scale * CubeSize) }; } }