public static void ChangeBlocksForPos(Vector3Int pos, string blockType, IConnectedBlockCalculationType calculationType)
 {
     if (World.TryGetTypeAt(pos, out ItemTypes.ItemType itemTypeAtPos) &&
         BlockLookup.TryGetValue(itemTypeAtPos.Name, out var existingBlock) &&
         existingBlock.ConnectedBlock.BlockType == blockType)
     {
         if (calculationType != null && TryGetChangedBlockTypeAtPosition(pos, blockType, calculationType, out var newBlock) && newBlock.ConnectedBlock.AutoChange)
         {
             ServerManager.TryChangeBlock(pos, (ushort)ItemId.GetItemId(newBlock.name));
         }
     }
 }
        public static List <BlockSide> GetConnectedBlocks(Vector3Int centerBlock, string blockType, IConnectedBlockCalculationType calculationType)
        {
            List <BlockSide> connectedBlocks = new List <BlockSide>();

            foreach (var block in calculationType.AvailableBlockSides)
            {
                if (World.TryGetTypeAt(centerBlock.GetBlockOffset(block), out ItemTypes.ItemType blockAtLocation) &&
                    ItemCache.CSItems.TryGetValue(blockAtLocation.Name, out var existingBlockType) &&
                    string.Equals(existingBlockType?.ConnectedBlock?.BlockType, blockType, StringComparison.InvariantCultureIgnoreCase))
                {
                    connectedBlocks.Add(block);
                }
            }

            connectedBlocks.Sort();

            return(connectedBlocks);
        }
        public static bool TryGetChangedBlockTypeAtPosition(Vector3Int centerBlock, string blockType, IConnectedBlockCalculationType calculationType, out ICSType newBlock)
        {
            List <BlockSide> connectedBlocks = GetConnectedBlocks(centerBlock, blockType, calculationType);

            return(TryGetConnectingBlock(blockType, connectedBlocks, out newBlock));
        }
        private static void PermutateItems(ICSType baseBlock, Dictionary <List <BlockSide>, ICSType> cSTypes, string itemJson, List <BlockSide> connections, IConnectedBlockCalculationType connectedBlockCalculationType)
        {
            foreach (RotationAxis axis in connectedBlockCalculationType.AxisRotations)
            {
                foreach (BlockRotationDegrees rotationDegrees in _blockRotationDegrees)
                {
                    var rotationEuler   = new SerializableVector3();
                    var rotatedList     = new List <BlockSide>();
                    var currentRotation = rotationDegrees;

                    if (baseBlock.meshRotationEuler != null)
                    {
                        rotationEuler.x = baseBlock.meshRotationEuler.x;
                        rotationEuler.y = baseBlock.meshRotationEuler.y;
                        rotationEuler.z = baseBlock.meshRotationEuler.z;
                    }

                    switch (axis)
                    {
                    case RotationAxis.X:
                        rotationEuler.x += (int)rotationDegrees;

                        if (rotationEuler.x > (int)BlockRotationDegrees.TwoSeventy)
                        {
                            rotationEuler.x -= 360;
                        }

                        currentRotation = (BlockRotationDegrees)rotationEuler.x;
                        break;

                    case RotationAxis.Y:
                        rotationEuler.y += (int)rotationDegrees;

                        if (rotationEuler.y > (int)BlockRotationDegrees.TwoSeventy)
                        {
                            rotationEuler.y -= 360;
                        }

                        currentRotation = (BlockRotationDegrees)rotationEuler.x;
                        break;

                    case RotationAxis.Z:
                        rotationEuler.z += (int)rotationDegrees;

                        if (rotationEuler.z > (int)BlockRotationDegrees.TwoSeventy)
                        {
                            rotationEuler.z -= 360;
                        }

                        currentRotation = (BlockRotationDegrees)rotationEuler.x;
                        break;
                    }

                    if (connections.Count() == connections.Distinct().Count())
                    {
                        foreach (var side in connections)
                        {
                            Vector3 connectionPoint = side.GetVector();
                            Vector3 eulerRotation   = new Vector3(rotationEuler.x, rotationEuler.y, rotationEuler.z);

                            Vector3 rotatedConnectionPoint = Quaternion.Euler(eulerRotation) * connectionPoint;

                            if (rotatedConnectionPoint == Vector3.zero)
                            {
                                rotatedConnectionPoint = connectionPoint;
                            }

                            rotatedList.Add(rotatedConnectionPoint.GetBlocksideFromVector());
                        }
                    }

                    rotatedList.Sort();

                    if (rotatedList.Count != 0 &&
                        !rotatedList.Contains(BlockSide.Invalid) &&
                        rotatedList.Count == rotatedList.Distinct().Count() &&
                        !cSTypes.ContainsKey(rotatedList) &&
                        !rotatedList.All(r => r == rotatedList.First()))
                    {
                        bool hasCalculationTypes = rotatedList.Count <= connectedBlockCalculationType.MaxConnections;

                        foreach (var side in rotatedList)
                        {
                            if (!connectedBlockCalculationType.AvailableBlockSides.Contains(side))
                            {
                                hasCalculationTypes = false;
                            }
                        }

                        var newItem = JsonConvert.DeserializeObject <CSType>(itemJson);
                        newItem.meshRotationEuler = rotationEuler;
                        newItem.ConnectedBlock    = new ConnectedBlock()
                        {
                            BlockType            = baseBlock.ConnectedBlock.BlockType,
                            CalculationType      = baseBlock.ConnectedBlock.CalculationType,
                            Connections          = rotatedList,
                            BlockRotationDegrees = currentRotation,
                            RotationAxis         = axis
                        };

                        newItem.categories = null;
                        newItem.name       = string.Concat(newItem.name, ".", GetItemName(newItem.ConnectedBlock.Connections));

                        if (hasCalculationTypes)
                        {
                            cSTypes[newItem.ConnectedBlock.Connections] = newItem;
                        }

                        PermutateItems(newItem, cSTypes, itemJson, connections, connectedBlockCalculationType);
                    }
                }
            }
        }
        public static void ChangeBlocksForPos(Vector3Int pos, string blockType = null, IConnectedBlockCalculationType calculationType = null)
        {
            if (World.TryGetTypeAt(pos, out ItemTypes.ItemType itemTypeAtPos) && BlockLookup.ContainsKey(itemTypeAtPos.Name))
            {
                if (blockType == null &&
                    BlockLookup.TryGetValue(itemTypeAtPos.Name, out var connectedBlockAtPos))
                {
                    blockType = connectedBlockAtPos.ConnectedBlock.BlockType;

                    if (ConnectedBlockCalculator.CalculationTypes.TryGetValue(connectedBlockAtPos.ConnectedBlock.CalculationType, out var connectedBlockCalculationType))
                    {
                        calculationType = connectedBlockCalculationType;
                    }
                    else
                    {
                        return;
                    }
                }

                if (calculationType != null && TryGetChangedBlockTypeAtPosition(pos, blockType, calculationType, out var newBlock) && newBlock.ConnectedBlock.AutoChange)
                {
                    ServerManager.TryChangeBlock(pos, ItemId.GetItemId(newBlock.name));
                }
            }
        }