using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using RobocraftX.Common; using Newtonsoft.Json; using Unity.Mathematics; using GamecraftModdingAPI.Blocks; using GamecraftModdingAPI.Utility; namespace Pixi.Robots { public static class CubeUtility { private static Dictionary<uint, string> map = null; public static RobotStruct? ParseRobotInfo(string robotInfo) { try { return JsonConvert.DeserializeObject<RobotStruct>(robotInfo); } catch (Exception e) { Logging.MetaLog(e); return null; } } public static CubeInfo[] ParseCubes(RobotStruct robot) { return ParseCubes(robot.cubeData, robot.colourData); } public static CubeInfo[] ParseCubes(string cubeData, string colourData) { BinaryBufferReader cubes = new BinaryBufferReader(Convert.FromBase64String(cubeData), 0); BinaryBufferReader colours = new BinaryBufferReader(Convert.FromBase64String(colourData), 0); uint cubeCount = cubes.ReadUint(); uint colourCount = colours.ReadUint(); if (cubeCount != colourCount) { Logging.MetaLog("Something is fucking broken"); return null; } Logging.MetaLog($"Detected {cubeCount} cubes"); CubeInfo[] result = new CubeInfo[cubeCount]; for (int cube = 0; cube < cubeCount; cube++) { result[cube] = TranslateSpacialEnumerations( cubes.ReadUint(), cubes.ReadByte(), cubes.ReadByte(), cubes.ReadByte(), cubes.ReadByte(), colours.ReadByte(), colours.ReadByte(), colours.ReadByte(), colours.ReadByte() ); } return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static CubeInfo TranslateSpacialEnumerations(uint cubeId, byte x, byte y, byte z, byte rotation, byte colour, byte colour_x, byte colour_y, byte colour_z) { if (x != colour_x || z != colour_z || y != colour_y) return default; CubeInfo result = new CubeInfo { visible = true }; TranslateBlockColour(colour, ref result); TranslateBlockPosition(x, y, z, ref result); TranslateBlockRotation(rotation, ref result); TranslateBlockId(cubeId, ref result); #if DEBUG Logging.MetaLog($"Cube {cubeId} ({x}, {y}, {z}) rot:{rotation} decoded as {result.block} {result.position} rot: {result.rotation} color: {result.color} {result.darkness}"); #endif return result; } //[MethodImpl(MethodImplOptions.AggressiveInlining)] private static void TranslateBlockRotation(byte rotation, ref CubeInfo result) { // face refers to the face of the block connected to the bottom of the current one // nvm, they're all incorrect switch (rotation) { case 0: result.rotation = new float3(0, 0, 0); // top face, forwards break; case 1: result.rotation = new float3(0, 0, 90); // left face, forwards break; case 2: result.rotation = new float3(0, 0, 180); // bottom face, forwards break; case 3: result.rotation = new float3(0, 0, -90); // front face, down break; case 4: result.rotation = new float3(0, 90, 0); // top face, right break; case 5: result.rotation = new float3(0, 90, 90); // front face, right break; case 6: result.rotation = new float3(-90, -90, 0); // right face, backwards break; case 7: result.rotation = new float3(0, 90, -90); // back face, right break; case 8: result.rotation = new float3(0, -90, 90); // back face, left break; case 9: result.rotation = new float3(0, -90, -90); // front face, left break; case 10: result.rotation = new float3(90, -90, 0); // left face, down break; case 11: result.rotation = new float3(90, 90, 0); // right face, forwards break; case 12: result.rotation = new float3(-90, 90, 0); // left face, up break; case 13: result.rotation = new float3(0, 90, 180); // bottom face, right break; case 14: result.rotation = new float3(0, 180, 0); // top face, backwards break; case 15: result.rotation = new float3(0, 180, 90); // right face, up break; case 16: result.rotation = new float3(0, 180, 180); // bottom face, backwards break; case 17: result.rotation = new float3(0, 180, -90); // left face, backwards break; case 18: result.rotation = new float3(0, -90, 0); // top face, left break; case 19: result.rotation = new float3(0, -90, 180); // bottom face, left break; case 20: result.rotation = new float3(90, 0, 0); // front face, down break; case 21: result.rotation = new float3(90, 180, 0); // back face, down break; case 22: result.rotation = new float3(-90, 0, 0); // back face, up break; case 23: result.rotation = new float3(-90, 180, 0); // front face, up break; default: #if DEBUG Logging.MetaLog($"Unknown rotation {rotation.ToString("X2")}"); #endif result.rotation = float3.zero; break; } // my brain hurts after figuring out all of those rotations // I wouldn't recommend trying to redo this } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void TranslateBlockPosition(byte x, byte y, byte z, ref CubeInfo result) { // for some reason, z is forwards in garage bays result.position = new float3(x, y, z); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void TranslateBlockColour(byte colour, ref CubeInfo result) { // I hope these colours are accurate, I just guessed // TODO colour accuracy (lol that won't ever happen) switch (colour) { case 0: result.color = BlockColors.White; result.darkness = 0; break; case 1: result.color = BlockColors.White; result.darkness = 5; break; case 2: result.color = BlockColors.Orange; result.darkness = 0; break; case 3: result.color = BlockColors.Blue; result.darkness = 2; break; case 4: result.color = BlockColors.White; result.darkness = 8; break; case 5: result.color = BlockColors.Red; result.darkness = 0; break; case 6: result.color = BlockColors.Yellow; result.darkness = 0; break; case 7: result.color = BlockColors.Green; result.darkness = 0; break; case 8: result.color = BlockColors.Purple; result.darkness = 0; break; case 9: result.color = BlockColors.Blue; result.darkness = 7; break; case 10: result.color = BlockColors.Purple; result.darkness = 5; break; case 11: result.color = BlockColors.Orange; result.darkness = 7; break; case 12: result.color = BlockColors.Green; result.darkness = 3; break; case 13: result.color = BlockColors.Green; result.darkness = 2; break; case 14: result.color = BlockColors.Pink; result.darkness = 3; break; case 15: result.color = BlockColors.Pink; result.darkness = 2; break; case 16: result.color = BlockColors.Red; result.darkness = 2; break; case 17: result.color = BlockColors.Orange; result.darkness = 8; break; case 18: result.color = BlockColors.Red; result.darkness = 7; break; case 19: result.color = BlockColors.Pink; result.darkness = 0; break; case 20: result.color = BlockColors.Yellow; result.darkness = 2; break; case 21: result.color = BlockColors.Green; result.darkness = 7; break; case 22: result.color = BlockColors.Green; result.darkness = 8; break; case 23: result.color = BlockColors.Blue; result.darkness = 8; break; case 24: result.color = BlockColors.Aqua; result.darkness = 7; break; case 25: result.color = BlockColors.Blue; result.darkness = 6; break; case 26: result.color = BlockColors.Aqua; result.darkness = 5; break; case 27: result.color = BlockColors.Blue; result.darkness = 4; break; case 28: result.color = BlockColors.Aqua; result.darkness = 3; break; case 29: result.color = BlockColors.Blue; result.darkness = 5; break; case 30: result.color = BlockColors.Purple; result.darkness = 3; break; case 31: result.color = BlockColors.Purple; result.darkness = 1; break; default: result.color = BlockColors.Aqua; result.darkness = 0; break; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void TranslateBlockId(uint cubeId, ref CubeInfo result) { if (map == null) { StreamReader cubemap = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Pixi.cubes-id.json")); map = JsonConvert.DeserializeObject<Dictionary<uint, string>>(cubemap.ReadToEnd()); } if (!map.ContainsKey(cubeId)) { result.block = BlockIDs.TextBlock; result.placeholder = "Unknown cube #" + cubeId.ToString(); //result.rotation = float3.zero; #if DEBUG Logging.MetaLog($"Unknown cubeId {cubeId}"); #endif } string cubeName = map[cubeId]; if (cubeName.Contains("cube")) { result.block = BlockIDs.AluminiumCube; result.rotation = float3.zero; } else if (cubeName.Contains("prism") || cubeName.Contains("edge")) { if (cubeName.Contains("round")) { if (cubeName.Contains("glass") || cubeName.Contains("windshield")) { result.block = BlockIDs.GlassRoundedSlope; } else result.block = BlockIDs.AluminiumRoundedSlope; } else { if (cubeName.Contains("glass") || cubeName.Contains("windshield")) { result.block = BlockIDs.GlassSlope; } else result.block = BlockIDs.AluminiumSlope; } } else if (cubeName.Contains("inner")) { if (cubeName.Contains("round")) { if (cubeName.Contains("glass") || cubeName.Contains("windshield")) { result.block = BlockIDs.GlassRoundedSlicedCube; } else result.block = BlockIDs.AluminiumRoundedSlicedCube; } else { if (cubeName.Contains("glass") || cubeName.Contains("windshield")) { result.block = BlockIDs.GlassSlicedCube; } else result.block = BlockIDs.AluminiumSlicedCube; } } else if (cubeName.Contains("tetra") || cubeName.Contains("corner")) { if (cubeName.Contains("round")) { if (cubeName.Contains("glass") || cubeName.Contains("windshield")) { result.block = BlockIDs.GlassRoundedCorner; } else result.block = BlockIDs.AluminiumRoundedCorner; } else { if (cubeName.Contains("glass") || cubeName.Contains("windshield")) { result.block = BlockIDs.GlassCorner; } else result.block = BlockIDs.AluminiumCorner; } } else if (cubeName.Contains("pyramid")) { result.block = BlockIDs.AluminiumPyramidSegment; } else if (cubeName.Contains("cone")) { result.block = BlockIDs.AluminiumConeSegment; } else { result.block = BlockIDs.TextBlock; result.placeholder = cubeName; } } } }