private void SendGatePortStatesInfo(TSPlayer player, GateStateMetadata gateState)
 {
     player.SendMessage("Top Port: " + this.GatePortStateToString(gateState.PortStates[0]), Color.LightGray);
     player.SendMessage("Left Port: " + this.GatePortStateToString(gateState.PortStates[2]), Color.LightGray);
     player.SendMessage("Bottom Port: " + this.GatePortStateToString(gateState.PortStates[1]), Color.LightGray);
     player.SendMessage("Right Port: " + this.GatePortStateToString(gateState.PortStates[3]), Color.LightGray);
 }
        private bool TryExecuteSubCommand(string commandNameLC, CommandArgs args)
        {
            switch (commandNameLC)
            {
            case "commands":
            case "cmds":
                args.Player.SendMessage("Available Sub-Commands:", Color.White);
                args.Player.SendMessage("/ac blocks", Color.Yellow);
                args.Player.SendMessage("/ac toggle|switch", Color.Yellow);

                if (args.Player.Group.HasPermission(AdvancedCircuitsPlugin.ReloadCfg_Permission))
                {
                    args.Player.SendMessage("/ac reloadcfg", Color.Yellow);
                }

                return(true);

            case "reloadcfg":
                if (args.Player.Group.HasPermission(AdvancedCircuitsPlugin.ReloadCfg_Permission))
                {
                    this.PluginTrace.WriteLineInfo("Reloading configuration file.");
                    try {
                        this.ReloadConfigurationCallback();
                        this.PluginTrace.WriteLineInfo("Configuration file successfully reloaded.");

                        if (args.Player != TSPlayer.Server)
                        {
                            args.Player.SendMessage("Configuration file successfully reloaded.", Color.Yellow);
                        }
                    } catch (Exception ex) {
                        this.PluginTrace.WriteLineError(
                            "Reloading the configuration file failed. Keeping old configuration. Exception details:\n{0}", ex
                            );
                    }
                }
                else
                {
                    args.Player.SendErrorMessage("You do not have the necessary permission to do that.");
                }

                return(true);

            case "blocks":
            case "ores":
            case "tiles":
                int pageNumber;
                if (!PaginationTools.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
                {
                    return(true);
                }

                PaginationTools.SendPage(
                    args.Player, pageNumber,
                    new List <string>()
                {
                    "Copper Ore - OR-Gate",
                    "Silver Ore - AND-Gate",
                    "Gold Ore - XOR-Gate / XOR-Port",
                    "Obsidian - NOT-Gate / NOT-Port",
                    "Iron Ore - Swapper",
                    "Spike - Crossover Bridge",
                    "Glass - Input Port",
                    "Active Stone - Active Stone and Block Activator",
                    "Adamantite Ore - Wireless Transmitter"
                },
                    new PaginationTools.Settings {
                    HeaderFormat    = "Advanced Circuits Special Blocks (Page {0} of {1})",
                    HeaderTextColor = Color.Lime,
                    LineTextColor   = Color.LightGray,
                    MaxLinesPerPage = 4,
                }
                    );

                return(true);

            case "toggle":
            case "switch":
                args.Player.SendInfoMessage("Place or destroy a wire on the component you want to toggle.");

                if (args.Parameters.Count > 3)
                {
                    args.Player.SendErrorMessage("Proper syntax: /ac switch [state] [+p]");
                    args.Player.SendInfoMessage("Type /ac switch help to get more help to this command.");
                    return(true);
                }

                bool persistentMode = false;
                bool?newState       = null;
                if (args.Parameters.Count > 1)
                {
                    int newStateRaw;
                    if (int.TryParse(args.Parameters[1], out newStateRaw))
                    {
                        newState = (newStateRaw == 1);
                    }

                    persistentMode = args.ContainsParameter("+p", StringComparison.InvariantCultureIgnoreCase);
                }

                CommandInteraction interaction = this.StartOrResetCommandInteraction(args.Player);
                interaction.DoesNeverComplete = persistentMode;
                interaction.TileEditCallback  = (player, editType, blockType, location, blockStyle) => {
                    if (
                        editType != TileEditType.PlaceTile ||
                        editType != TileEditType.PlaceWall ||
                        editType != TileEditType.DestroyWall ||
                        editType != TileEditType.PlaceActuator
                        )
                    {
                        CommandInteractionResult result = new CommandInteractionResult {
                            IsHandled = true, IsInteractionCompleted = true
                        };
                        ITile tile = TerrariaUtils.Tiles[location];

                        if (
                            !args.Player.HasBuildPermission(location.X, location.Y) || (
                                this.PluginCooperationHandler.IsProtectorAvailable &&
                                this.PluginCooperationHandler.Protector_CheckProtected(args.Player, location, false)
                                ))
                        {
                            player.SendErrorMessage("This object is protected.");
                            player.SendTileSquare(location, 1);
                            return(result);
                        }

                        int hitBlockType = tile.type;
                        if (tile.active() && hitBlockType == TileID.ActiveStoneBlock)
                        {
                            if (newState == null || newState == false)
                            {
                                TerrariaUtils.Tiles.SetBlock(location, TileID.InactiveStoneBlock);
                            }
                            else
                            {
                                args.Player.SendTileSquare(location);
                            }
                        }
                        else if (hitBlockType == TileID.InactiveStoneBlock)
                        {
                            if (tile.active() && newState == null || newState == true)
                            {
                                TerrariaUtils.Tiles.SetBlock(location, TileID.ActiveStoneBlock);
                            }
                            else
                            {
                                args.Player.SendTileSquare(location);
                            }
                        }
                        else if (tile.active() && TerrariaUtils.Tiles.IsMultistateObject(hitBlockType))
                        {
                            ObjectMeasureData measureData = TerrariaUtils.Tiles.MeasureObject(location);
                            bool currentState             = TerrariaUtils.Tiles.ObjectHasActiveState(measureData);
                            if (newState == null)
                            {
                                newState = !TerrariaUtils.Tiles.ObjectHasActiveState(measureData);
                            }

                            if (currentState != newState.Value)
                            {
                                TerrariaUtils.Tiles.SetObjectState(measureData, newState.Value);
                            }
                            else
                            {
                                args.Player.SendTileSquare(location);
                            }
                        }
                        else if (
                            hitBlockType == AdvancedCircuits.BlockType_ORGate ||
                            hitBlockType == AdvancedCircuits.BlockType_ANDGate ||
                            hitBlockType == AdvancedCircuits.BlockType_XORGate
                            )
                        {
                            if (
                                !args.Player.HasBuildPermission(location.X, location.Y) || (
                                    this.PluginCooperationHandler.IsProtectorAvailable &&
                                    this.PluginCooperationHandler.Protector_CheckProtected(args.Player, location, false)
                                    ))
                            {
                                player.SendErrorMessage("This gate is protected.");
                                player.SendTileSquare(location);
                                return(result);
                            }

                            PaintColor paint = (PaintColor)TerrariaUtils.Tiles[location].color();
                            if (paint == AdvancedCircuits.Paint_Gate_TemporaryState)
                            {
                                player.SendErrorMessage("The gate is painted {0}, there's no point in initializing it.", AdvancedCircuits.Paint_Gate_TemporaryState);
                                args.Player.SendTileSquare(location);
                                return(result);
                            }

                            GateStateMetadata gateState;
                            if (!this.WorldMetadata.GateStates.TryGetValue(location, out gateState))
                            {
                                gateState = new GateStateMetadata();
                                this.WorldMetadata.GateStates.Add(location, gateState);
                            }

                            List <DPoint> gatePortLocations = new List <DPoint>(AdvancedCircuits.EnumerateComponentPortLocations(location, new DPoint(1, 1)));
                            for (int i = 0; i < 4; i++)
                            {
                                ITile gatePort = TerrariaUtils.Tiles[gatePortLocations[i]];
                                if (!gatePort.active() || gatePort.type != (int)AdvancedCircuits.BlockType_InputPort)
                                {
                                    continue;
                                }

                                if (newState == null)
                                {
                                    if (gateState.PortStates[i] == null)
                                    {
                                        gateState.PortStates[i] = true;
                                    }
                                    else
                                    {
                                        gateState.PortStates[i] = !gateState.PortStates[i];
                                    }
                                }
                                else
                                {
                                    gateState.PortStates[i] = newState.Value;
                                }
                            }

                            player.SendSuccessMessage("The states of this gate's ports are now:");
                            this.SendGatePortStatesInfo(args.Player, gateState);
                            args.Player.SendTileSquare(location);
                        }
                        else if (tile.active() && tile.type == (int)AdvancedCircuits.BlockType_InputPort)
                        {
                            foreach (DPoint adjacentTileLocation in AdvancedCircuits.EnumerateComponentPortLocations(location, new DPoint(1, 1)))
                            {
                                ITile adjacentTile = TerrariaUtils.Tiles[adjacentTileLocation];
                                if (!adjacentTile.active() || !AdvancedCircuits.IsLogicalGate(adjacentTile.type))
                                {
                                    continue;
                                }

                                if (
                                    !args.Player.HasBuildPermission(adjacentTileLocation.X, adjacentTileLocation.Y) || (
                                        this.PluginCooperationHandler.IsProtectorAvailable &&
                                        this.PluginCooperationHandler.Protector_CheckProtected(args.Player, adjacentTileLocation, false)
                                        ))
                                {
                                    player.SendErrorMessage("This gate is protected.");
                                    player.SendTileSquare(location);
                                    return(result);
                                }

                                PaintColor paint = (PaintColor)TerrariaUtils.Tiles[location].color();
                                if (paint == AdvancedCircuits.Paint_Gate_TemporaryState)
                                {
                                    player.SendErrorMessage("The gate is painted {0}, there's no point in initializing it.", AdvancedCircuits.Paint_Gate_TemporaryState);
                                    args.Player.SendTileSquare(location);
                                    return(result);
                                }

                                GateStateMetadata gateState;
                                if (!this.WorldMetadata.GateStates.TryGetValue(adjacentTileLocation, out gateState))
                                {
                                    gateState = new GateStateMetadata();
                                    this.WorldMetadata.GateStates.Add(adjacentTileLocation, gateState);
                                }

                                int portIndex;
                                switch (AdvancedCircuits.DirectionFromTileLocations(adjacentTileLocation, location))
                                {
                                case Direction.Up:
                                    portIndex = 0;
                                    break;

                                case Direction.Down:
                                    portIndex = 1;
                                    break;

                                case Direction.Left:
                                    portIndex = 2;
                                    break;

                                case Direction.Right:
                                    portIndex = 3;
                                    break;

                                default:
                                    return(result);
                                }

                                if (newState == null)
                                {
                                    if (gateState.PortStates[portIndex] == null)
                                    {
                                        gateState.PortStates[portIndex] = true;
                                    }
                                    else
                                    {
                                        gateState.PortStates[portIndex] = !gateState.PortStates[portIndex];
                                    }
                                }
                                else
                                {
                                    gateState.PortStates[portIndex] = newState.Value;
                                }

                                player.SendSuccessMessage("The states of this gate's ports are now:");
                                this.SendGatePortStatesInfo(args.Player, gateState);
                                args.Player.SendTileSquare(location);
                                return(result);
                            }

                            player.SendErrorMessage($"The state of \"{TerrariaUtils.Tiles.GetBlockTypeName(hitBlockType, 0)}\" can not be changed.");
                            player.SendTileSquare(location);
                        }

                        return(result);
                    }

                    return(new CommandInteractionResult {
                        IsHandled = false, IsInteractionCompleted = false
                    });
                };
                interaction.TimeExpiredCallback = (player) => {
                    player.SendErrorMessage("Waited too long, no component will be toggled.");
                };

                args.Player.SendSuccessMessage("Hit an object to change its state.");
                return(true);
            }

            return(false);
        }
        private bool TryExecuteSubCommand(string commandNameLC, CommandArgs args)
        {
            switch (commandNameLC) {
            case "commands":
            case "cmds":
              args.Player.SendMessage("Available Sub-Commands:", Color.White);
              args.Player.SendMessage("/ac blocks", Color.Yellow);
              args.Player.SendMessage("/ac toggle|switch", Color.Yellow);

              if (args.Player.Group.HasPermission(AdvancedCircuitsPlugin.ReloadCfg_Permission))
            args.Player.SendMessage("/ac reloadcfg", Color.Yellow);

              return true;
            case "reloadcfg":
              if (args.Player.Group.HasPermission(AdvancedCircuitsPlugin.ReloadCfg_Permission)) {
            this.PluginTrace.WriteLineInfo("Reloading configuration file.");
            try {
              this.ReloadConfigurationCallback();
              this.PluginTrace.WriteLineInfo("Configuration file successfully reloaded.");

              if (args.Player != TSPlayer.Server)
                args.Player.SendMessage("Configuration file successfully reloaded.", Color.Yellow);
            } catch (Exception ex) {
              this.PluginTrace.WriteLineError(
                "Reloading the configuration file failed. Keeping old configuration. Exception details:\n{0}", ex
              );
            }
              } else {
            args.Player.SendErrorMessage("You do not have the necessary permission to do that.");
              }

              return true;
            case "blocks":
            case "ores":
            case "tiles":
              int pageNumber;
              if (!PaginationUtil.TryParsePageNumber(args.Parameters, 1, args.Player, out pageNumber))
            return true;

              PaginationUtil.SendPage(
            args.Player, pageNumber,
            new List<string>() {
              "Copper Ore - OR-Gate",
              "Silver Ore - AND-Gate",
              "Gold Ore - XOR-Gate / XOR-Port",
              "Obsidian - NOT-Gate / NOT-Port",
              "Iron Ore - Swapper",
              "Spike - Crossover Bridge",
              "Glass - Input Port",
              "Active Stone - Active Stone and Block Activator",
              "Adamantite Ore - Wireless Transmitter"
            },
            new PaginationUtil.Settings {
              HeaderFormat = "Advanced Circuits Special Blocks (Page {0} of {1})",
              HeaderTextColor = Color.Lime,
              LineTextColor = Color.LightGray,
              MaxLinesPerPage = 4,
            }
              );

              return true;
            case "toggle":
            case "switch":
              args.Player.SendInfoMessage("Place or destroy a wire on the component you want to toggle.");

              if (args.Parameters.Count > 3) {
            args.Player.SendErrorMessage("Proper syntax: /ac switch [state] [+p]");
            args.Player.SendInfoMessage("Type /ac switch help to get more help to this command.");
            return true;
              }

              bool persistentMode = false;
              bool? newState = null;
              if (args.Parameters.Count > 1) {
            int newStateRaw;
            if (int.TryParse(args.Parameters[1], out newStateRaw))
              newState = (newStateRaw == 1);

            persistentMode = args.ContainsParameter("+p", StringComparison.InvariantCultureIgnoreCase);
              }

              CommandInteraction interaction = this.StartOrResetCommandInteraction(args.Player);
              interaction.DoesNeverComplete = persistentMode;
              interaction.TileEditCallback = (player, editType, blockType, location, blockStyle) => {
            if (
              editType != TileEditType.PlaceTile ||
              editType != TileEditType.PlaceWall ||
              editType != TileEditType.DestroyWall ||
              editType != TileEditType.PlaceActuator
            ) {
              CommandInteractionResult result = new CommandInteractionResult { IsHandled = true, IsInteractionCompleted = true };
              Tile tile = TerrariaUtils.Tiles[location];

              if (
                TShock.CheckTilePermission(args.Player, location.X, location.Y) || (
                  this.PluginCooperationHandler.IsProtectorAvailable &&
                  this.PluginCooperationHandler.Protector_CheckProtected(args.Player, location, false)
                )
              ) {
                player.SendErrorMessage("This object is protected.");
                player.SendTileSquare(location, 1);
                return result;
              }

              BlockType hitBlockType = (BlockType)tile.type;
              if (tile.active() && hitBlockType == BlockType.ActiveStone) {
                if (newState == null || newState == false)
                  TerrariaUtils.Tiles.SetBlock(location, BlockType.InactiveStone);
                else
                  args.Player.SendTileSquare(location);
              } else if (hitBlockType == BlockType.InactiveStone) {
                if (tile.active() &&  newState == null || newState == true)
                  TerrariaUtils.Tiles.SetBlock(location, BlockType.ActiveStone);
                else
                  args.Player.SendTileSquare(location);
              } else if (tile.active() && TerrariaUtils.Tiles.IsMultistateObject(hitBlockType)) {
                ObjectMeasureData measureData = TerrariaUtils.Tiles.MeasureObject(location);
                bool currentState = TerrariaUtils.Tiles.ObjectHasActiveState(measureData);
                if (newState == null)
                  newState = !TerrariaUtils.Tiles.ObjectHasActiveState(measureData);

                if (currentState != newState.Value)
                  TerrariaUtils.Tiles.SetObjectState(measureData, newState.Value);
                else
                  args.Player.SendTileSquare(location);
              } else if (
                hitBlockType == AdvancedCircuits.BlockType_ORGate ||
                hitBlockType == AdvancedCircuits.BlockType_ANDGate ||
                hitBlockType == AdvancedCircuits.BlockType_XORGate
              ) {
                if (
                  TShock.CheckTilePermission(args.Player, location.X, location.Y) || (
                  this.PluginCooperationHandler.IsProtectorAvailable &&
                  this.PluginCooperationHandler.Protector_CheckProtected(args.Player, location, false)
                )) {
                  player.SendErrorMessage("This gate is protected.");
                  player.SendTileSquare(location);
                  return result;
                }

                PaintColor paint = (PaintColor)TerrariaUtils.Tiles[location].color();
                if (paint == AdvancedCircuits.Paint_Gate_TemporaryState) {
                  player.SendErrorMessage("The gate is painted {0}, there's no point in initializing it.", AdvancedCircuits.Paint_Gate_TemporaryState);
                  args.Player.SendTileSquare(location);
                  return result;
                }

                GateStateMetadata gateState;
                if (!this.WorldMetadata.GateStates.TryGetValue(location, out gateState)) {
                  gateState = new GateStateMetadata();
                  this.WorldMetadata.GateStates.Add(location, gateState);
                }

                List<DPoint> gatePortLocations = new List<DPoint>(AdvancedCircuits.EnumerateComponentPortLocations(location, new DPoint(1, 1)));
                for (int i = 0; i < 4; i++) {
                  Tile gatePort = TerrariaUtils.Tiles[gatePortLocations[i]];
                  if (!gatePort.active() || gatePort.type != (int)AdvancedCircuits.BlockType_InputPort)
                    continue;

                  if (newState == null) {
                    if (gateState.PortStates[i] == null)
                      gateState.PortStates[i] = true;
                    else
                      gateState.PortStates[i] = !gateState.PortStates[i];
                  } else {
                    gateState.PortStates[i] = newState.Value;
                  }
                }

                player.SendSuccessMessage("The states of this gate's ports are now:");
                this.SendGatePortStatesInfo(args.Player, gateState);
                args.Player.SendTileSquare(location);
              } else if (tile.active() && tile.type == (int)AdvancedCircuits.BlockType_InputPort) {
                foreach (DPoint adjacentTileLocation in AdvancedCircuits.EnumerateComponentPortLocations(location, new DPoint(1, 1))) {
                  Tile adjacentTile = TerrariaUtils.Tiles[adjacentTileLocation];
                  if (!adjacentTile.active() || !AdvancedCircuits.IsLogicalGate((BlockType)adjacentTile.type))
                    continue;

                  if (
                    TShock.CheckTilePermission(args.Player, adjacentTileLocation.X, adjacentTileLocation.Y) || (
                      this.PluginCooperationHandler.IsProtectorAvailable &&
                      this.PluginCooperationHandler.Protector_CheckProtected(args.Player, adjacentTileLocation, false)
                    )
                  ) {
                    player.SendErrorMessage("This gate is protected.");
                    player.SendTileSquare(location);
                    return result;
                  }

                  PaintColor paint = (PaintColor)TerrariaUtils.Tiles[location].color();
                  if (paint == AdvancedCircuits.Paint_Gate_TemporaryState) {
                    player.SendErrorMessage("The gate is painted {0}, there's no point in initializing it.", AdvancedCircuits.Paint_Gate_TemporaryState);
                    args.Player.SendTileSquare(location);
                    return result;
                  }

                  GateStateMetadata gateState;
                  if (!this.WorldMetadata.GateStates.TryGetValue(adjacentTileLocation, out gateState)) {
                    gateState = new GateStateMetadata();
                    this.WorldMetadata.GateStates.Add(adjacentTileLocation, gateState);
                  }

                  int portIndex;
                  switch (AdvancedCircuits.DirectionFromTileLocations(adjacentTileLocation, location)) {
                    case Direction.Up:
                      portIndex = 0;
                      break;
                    case Direction.Down:
                      portIndex = 1;
                      break;
                    case Direction.Left:
                      portIndex = 2;
                      break;
                    case Direction.Right:
                      portIndex = 3;
                      break;
                    default:
                      return result;
                  }

                  if (newState == null) {
                    if (gateState.PortStates[portIndex] == null)
                      gateState.PortStates[portIndex] = true;
                    else
                      gateState.PortStates[portIndex] = !gateState.PortStates[portIndex];
                  } else {
                    gateState.PortStates[portIndex] = newState.Value;
                  }

                  player.SendSuccessMessage("The states of this gate's ports are now:");
                  this.SendGatePortStatesInfo(args.Player, gateState);
                  args.Player.SendTileSquare(location);
                  return result;
                }

                player.SendErrorMessage(string.Format(
                  "The state of \"{0}\" can not be changed.", TerrariaUtils.Tiles.GetBlockTypeName(hitBlockType)
                ));

                player.SendTileSquare(location);
              }

              return result;
            }

            return new CommandInteractionResult { IsHandled = false, IsInteractionCompleted = false };
              };
              interaction.TimeExpiredCallback = (player) => {
            player.SendErrorMessage("Waited too long, no component will be toggled.");
              };

              args.Player.SendSuccessMessage("Hit an object to change its state.");
              return true;
              }

              return false;
        }
        private bool SignalPortDefiningComponent(RootBranchProcessData rootBranch, ObjectMeasureData measureData, DPoint portLocation, bool signal)
        {
            if (!this.IsAdvancedCircuit)
            throw new InvalidOperationException("This is no advanced circuit.");

              Tile portTile = TerrariaUtils.Tiles[portLocation];
              Tile componentTile = TerrariaUtils.Tiles[measureData.OriginTileLocation];
              if (!portTile.HasWire(rootBranch.WireColor) || componentTile.HasWire())
            return false;

              if (portTile.active() && portTile.type == (int)AdvancedCircuits.BlockType_NOTGate && measureData.BlockType != AdvancedCircuits.BlockType_NOTGate)
            signal = !signal;
              else if (portTile.active() && portTile.type == (int)AdvancedCircuits.BlockType_XORGate && measureData.BlockType != AdvancedCircuits.BlockType_XORGate)
            signal = false;

              List<DPoint> componentPorts = null;
              bool outputSignal = signal;
              DPoint componentLocation = measureData.OriginTileLocation;
              PaintColor componentPaint = (PaintColor)TerrariaUtils.Tiles[measureData.OriginTileLocation].color();

              BlockActivatorMetadata blockActivatorToRegister = null;
              DPoint blockActivatorLocationToRegister = DPoint.Empty;
              BlockActivatorMode blockActivatorModeToRegister = BlockActivatorMode.Default;

              switch (measureData.BlockType) {
            case BlockType.DoorOpened:
            case BlockType.DoorClosed: {
              for (int y = measureData.OriginTileLocation.Y; y < measureData.OriginTileLocation.Y + measureData.Size.Y; y++)
            if (TerrariaUtils.Tiles[measureData.OriginTileLocation.X, y].HasWire())
              return false;

              if (measureData.BlockType == BlockType.DoorOpened) {
            // Extra check needed if a port of the door is really hit. This is because doors define ports differently than
            // other components if they are opened.
            componentPorts = new List<DPoint>(AdvancedCircuits.EnumerateComponentPortLocations(measureData));
            if (!componentPorts.Contains(portLocation))
              return false;
              }

              this.OpenDoor(measureData, AdvancedCircuits.BoolToSignal(signal));
              break;
            }
            case BlockType.XSecondTimer: {
              if (!portTile.active() || portTile.type != (int)AdvancedCircuits.BlockType_InputPort)
            return false;

              bool currentState = (TerrariaUtils.Tiles.ObjectHasActiveState(measureData));
              if (currentState != signal)
            TerrariaUtils.Tiles.SetObjectState(measureData, signal);

              if (currentState != signal)
            this.CircuitHandler.RegisterUnregisterTimer(this.TriggeringPlayer, measureData, signal);
              else if (signal)
            this.CircuitHandler.ResetTimer(measureData);

              return true;
            }
            case BlockType.Switch:
            case BlockType.Lever: {
              if (measureData.BlockType == BlockType.Lever && TerrariaUtils.Tiles.IsObjectWired(measureData))
            return false;

              bool isInputPort = (portTile.active() && portTile.type == (int)AdvancedCircuits.BlockType_InputPort);
              bool currentState = (TerrariaUtils.Tiles.ObjectHasActiveState(measureData));
              if (isInputPort) {
            if (currentState != signal)
              TerrariaUtils.Tiles.SetObjectState(measureData, signal);

            return true;
              } else {
            switch (componentPaint) {
              default:
                if (currentState == signal)
                  return true;

                TerrariaUtils.Tiles.SetObjectState(measureData, signal);
                break;
              case AdvancedCircuits.Paint_Switch_ToggleAndForward:
                if (currentState != signal)
                  TerrariaUtils.Tiles.SetObjectState(measureData, signal);

                break;
              case AdvancedCircuits.Paint_Switch_ForwardIfEqual:
                if (currentState != signal)
                  return true;

                break;
              case AdvancedCircuits.Paint_Switch_ForwardIfEqualByChance:
                if (currentState != signal)
                  return true;

                if (CircuitProcessor.Random.Next(0, 2) == 0)
                  outputSignal = !signal;

                break;
              case AdvancedCircuits.Paint_Switch_ForwardByChance:
                if (CircuitProcessor.Random.Next(0, 2) == 0)
                  return true;

                break;
            }

            if (componentPaint != AdvancedCircuits.Paint_Switch_ToggleAndForward) {
              blockActivatorToRegister = rootBranch.BlockActivator;
              blockActivatorLocationToRegister = rootBranch.BlockActivatorLocation;
              blockActivatorModeToRegister = rootBranch.BlockActivatorMode;
            }
              }

              break;
            }
            case AdvancedCircuits.BlockType_NOTGate: {
              if (!portTile.active() || portTile.type != (int)AdvancedCircuits.BlockType_InputPort)
            return false;

              outputSignal = !signal;

              blockActivatorToRegister = rootBranch.BlockActivator;
              blockActivatorLocationToRegister = rootBranch.BlockActivatorLocation;
              blockActivatorModeToRegister = rootBranch.BlockActivatorMode;

              break;
            }
            case AdvancedCircuits.BlockType_ANDGate:
            case AdvancedCircuits.BlockType_ORGate:
            case AdvancedCircuits.BlockType_XORGate: {
              if (!portTile.active() || portTile.type != (int)AdvancedCircuits.BlockType_InputPort)
            return false;

              GateStateMetadata metadata;
              switch (componentPaint) {
            default:
              if (!this.CircuitHandler.WorldMetadata.GateStates.TryGetValue(componentLocation, out metadata)) {
                metadata = new GateStateMetadata();
                this.CircuitHandler.WorldMetadata.GateStates.Add(componentLocation, metadata);
              }
              break;
            case AdvancedCircuits.Paint_Gate_TemporaryState:
              if (!temporaryGateStates.TryGetValue(componentLocation, out metadata)) {
                metadata = new GateStateMetadata();
                temporaryGateStates.Add(componentLocation, metadata);
              }
              break;
              }

              componentPorts = new List<DPoint>(AdvancedCircuits.EnumerateComponentPortLocations(measureData));
              int inputPorts = 0;
              int signaledPorts = 0;
              bool isInvalid = false;
              for (int i = 0; i < componentPorts.Count; i++) {
            DPoint port = componentPorts[i];
            portTile = TerrariaUtils.Tiles[port];
            if (portTile.HasWire() && portTile.active() && portTile.type == (int)AdvancedCircuits.BlockType_InputPort) {
              inputPorts++;

              if (port == portLocation)
                metadata.PortStates[i] = outputSignal;

              if (metadata.PortStates[i] == null)
                isInvalid = true;
            }

            if (metadata.PortStates[i] != null && metadata.PortStates[i].Value)
              signaledPorts++;
              }

              // Gates will not operate as long as the input port states are not clear.
              if (isInvalid)
            return false;

              switch ((BlockType)componentTile.type) {
            case AdvancedCircuits.BlockType_ANDGate:
              outputSignal = (inputPorts == signaledPorts);
              break;
            case AdvancedCircuits.BlockType_ORGate:
              outputSignal = (signaledPorts > 0);
              break;
            case AdvancedCircuits.BlockType_XORGate:
              outputSignal = (signaledPorts != 0 && signaledPorts < inputPorts);
              break;
              }

              blockActivatorToRegister = rootBranch.BlockActivator;
              blockActivatorLocationToRegister = rootBranch.BlockActivatorLocation;
              blockActivatorModeToRegister = rootBranch.BlockActivatorMode;

              break;
            }
            case AdvancedCircuits.BlockType_Swapper: {
              if (!signal)
            return false;

              int swapperCounterValue;
              if (!this.CircuitHandler.WorldMetadata.Swappers.TryGetValue(componentLocation, out swapperCounterValue)) {
            this.CircuitHandler.WorldMetadata.Swappers.Add(componentLocation, 1);

            if (componentPaint == PaintColor.None)
              outputSignal = false;
            else
              return true;
              } else {
            swapperCounterValue++;

            bool sendSignal = true;
            int swapperCounterMax = AdvancedCircuits.SwapperPaintToCount(componentPaint);
            if (swapperCounterValue == swapperCounterMax) {
              outputSignal = false;
            } else if (swapperCounterValue >= swapperCounterMax * 2) {
              outputSignal = true;
              swapperCounterValue = 0;
            } else {
              sendSignal = false;
            }

            this.CircuitHandler.WorldMetadata.Swappers[componentLocation] = swapperCounterValue;
            if (!sendSignal)
              return true;
              }

              blockActivatorToRegister = rootBranch.BlockActivator;
              blockActivatorLocationToRegister = rootBranch.BlockActivatorLocation;
              blockActivatorModeToRegister = rootBranch.BlockActivatorMode;

              break;
            }
            case AdvancedCircuits.BlockType_CrossoverBridge: {
              switch (AdvancedCircuits.DirectionFromTileLocations(componentLocation, portLocation)) {
            case Direction.Left:
              componentPorts = new List<DPoint> { new DPoint(componentLocation.X + 1, componentLocation.Y) };
              break;
            case Direction.Up:
              componentPorts = new List<DPoint> { new DPoint(componentLocation.X, componentLocation.Y + 1) };
              break;
            case Direction.Right:
              componentPorts = new List<DPoint> { new DPoint(componentLocation.X - 1, componentLocation.Y) };
              break;
            case Direction.Down:
              componentPorts = new List<DPoint> { new DPoint(componentLocation.X, componentLocation.Y - 1) };
              break;
            default:
              throw new ArgumentOutOfRangeException();
              }

              blockActivatorToRegister = rootBranch.BlockActivator;
              blockActivatorLocationToRegister = rootBranch.BlockActivatorLocation;
              blockActivatorModeToRegister = rootBranch.BlockActivatorMode;

              break;
            }
            case AdvancedCircuits.BlockType_BlockActivator: {
              if (!portTile.active() || portTile.type != (int)AdvancedCircuits.BlockType_InputPort)
            return false;
              if (
            this.CircuitHandler.Config.BlockActivatorConfig.Cooldown > 0 &&
            !WorldGen.checkMech(componentLocation.X, componentLocation.Y, this.CircuitHandler.Config.BlockActivatorConfig.Cooldown
              ))
            return false;

              if (
            this.TriggeringPlayer != TSPlayer.Server &&
            !this.TriggeringPlayer.Group.HasPermission(AdvancedCircuitsPlugin.TriggerBlockActivator_Permission)
              ) {
            this.Result.WarnReason = CircuitWarnReason.InsufficientPermissionToSignalComponent;
            this.Result.WarnRelatedComponentType = AdvancedCircuits.BlockType_BlockActivator;
            return true;
              }

              BlockActivatorMetadata blockActivator;
              this.CircuitHandler.WorldMetadata.BlockActivators.TryGetValue(componentLocation, out blockActivator);

              if (signal) {
            if (blockActivator == null || blockActivator.IsActivated)
              return true;
              } else {
            if (blockActivator == null) {
              blockActivator = new BlockActivatorMetadata();
              this.CircuitHandler.WorldMetadata.BlockActivators.Add(componentLocation, blockActivator);
            } else {
              // Will do nothing if already deactivated.
              if (!blockActivator.IsActivated)
                return true;

              blockActivator.RegisteredInactiveBlocks.Clear();
            }
              }

              blockActivator.IsActivated = signal;
              if (signal && blockActivator.RegisteredInactiveBlocks.Count == 0)
            return true;

              blockActivatorToRegister = blockActivator;
              blockActivatorLocationToRegister = componentLocation;
              if (componentPaint == AdvancedCircuits.Paint_BlockActivator_Replace)
            blockActivatorModeToRegister = BlockActivatorMode.ReplaceBlocks;

              break;
            }
            case AdvancedCircuits.BlockType_WirelessTransmitter: {
              if (!portTile.active() || portTile.type != (int)AdvancedCircuits.BlockType_InputPort)
            return false;

              WirelessTransmitterConfig transmitterConfig;
              if (
            (
              this.CircuitHandler.Config.WirelessTransmitterConfigs.TryGetValue(componentPaint, out transmitterConfig) ||
              this.CircuitHandler.Config.WirelessTransmitterConfigs.TryGetValue(PaintColor.None, out transmitterConfig)
            ) && (
              transmitterConfig.Cooldown == 0 ||
              WorldGen.checkMech(componentLocation.X, componentLocation.Y, transmitterConfig.Cooldown)
            )
              ) {
            if (
              transmitterConfig.TriggerPermission != null &&
              this.TriggeringPlayer != TSPlayer.Server &&
              !this.TriggeringPlayer.Group.HasPermission(transmitterConfig.TriggerPermission)
            ) {
              this.Result.WarnReason = CircuitWarnReason.InsufficientPermissionToSignalComponent;
              this.Result.WarnRelatedComponentType = AdvancedCircuits.BlockType_WirelessTransmitter;
              return true;
            }

            string sendingTransmitterOwner;
            if (!this.CircuitHandler.WorldMetadata.WirelessTransmitters.TryGetValue(componentLocation, out sendingTransmitterOwner))
              return false;

            bool isBroadcasting = (transmitterConfig.Network == 0);
            double sendingSquareRange = 0;
            if (transmitterConfig.Range > 0)
              sendingSquareRange = Math.Pow(transmitterConfig.Range + 1, 2);

            DPoint portOffset = new DPoint(portLocation.X - componentLocation.X, portLocation.Y - componentLocation.Y);
            foreach (KeyValuePair<DPoint,string> pair in this.CircuitHandler.WorldMetadata.WirelessTransmitters) {
              DPoint receivingTransmitterLocation = pair.Key;
              if (receivingTransmitterLocation == componentLocation)
                continue;

              string receivingTransmitterOwner = pair.Value;
              if (receivingTransmitterOwner != sendingTransmitterOwner)
                continue;

              Tile transmitterTile = TerrariaUtils.Tiles[receivingTransmitterLocation];
              if (!transmitterTile.active() || transmitterTile.type != (int)AdvancedCircuits.BlockType_WirelessTransmitter || transmitterTile.HasWire())
                continue;

              if (
                sendingSquareRange > 0 &&
                sendingSquareRange <= (
                  Math.Pow(receivingTransmitterLocation.X - componentLocation.X, 2) +
                  Math.Pow(receivingTransmitterLocation.Y - componentLocation.Y, 2)
                )
              )
                continue;

              DPoint outputPortLocation = receivingTransmitterLocation.OffsetEx(portOffset.X, portOffset.Y);
              Tile outputPortTile = TerrariaUtils.Tiles[outputPortLocation];
              if (!outputPortTile.HasWire() || (outputPortTile.active() && outputPortTile.type == (int)AdvancedCircuits.BlockType_InputPort))
                continue;

              if (!isBroadcasting) {
                PaintColor receiverPaint = (PaintColor)TerrariaUtils.Tiles[receivingTransmitterLocation].color();
                WirelessTransmitterConfig receiverConfig;
                if (!this.CircuitHandler.Config.WirelessTransmitterConfigs.TryGetValue(receiverPaint, out receiverConfig))
                  receiverConfig = this.CircuitHandler.Config.WirelessTransmitterConfigs[PaintColor.None];

                if (receiverConfig.Network != 0 && receiverConfig.Network != transmitterConfig.Network)
                  continue;
              }

              bool portOutputSignal = outputSignal;
              if (outputPortTile.active() && outputPortTile.type == (int)AdvancedCircuits.BlockType_NOTGate)
                portOutputSignal = !portOutputSignal;
              else if (outputPortTile.active() && outputPortTile.type == (int)AdvancedCircuits.BlockType_XORGate)
                portOutputSignal = false;

              foreach (WireColor wireColor in AdvancedCircuits.EnumerateWireColors()) {
                if (!outputPortTile.HasWire(wireColor))
                  continue;

                this.QueuedRootBranches.Add(new RootBranchProcessData(receivingTransmitterLocation, outputPortLocation, AdvancedCircuits.BoolToSignal(portOutputSignal), wireColor) {
                  BlockActivator = rootBranch.BlockActivator,
                  BlockActivatorLocation = rootBranch.BlockActivatorLocation,
                  BlockActivatorMode = rootBranch.BlockActivatorMode,
                  TeleporterLocation = rootBranch.TeleporterLocation
                });
              }
            }

            return true;
              }

              break;
            }
            default:
              return false;
              }

              if (componentPorts == null)
            componentPorts = new List<DPoint>(AdvancedCircuits.EnumerateComponentPortLocations(measureData));

              for (int i = 0; i < componentPorts.Count; i++) {
            DPoint port = componentPorts[i];
            // A component shouldn't send a signal through a port where it just received one.
            if (port == portLocation) {
              componentPorts.RemoveAt(i--);
              continue;
            }

            portTile = TerrariaUtils.Tiles[port];
            if (!portTile.HasWire() || (portTile.active() && portTile.type == (int)AdvancedCircuits.BlockType_InputPort))
              componentPorts.RemoveAt(i--);
              }

              foreach (DPoint port in componentPorts) {
            portTile = TerrariaUtils.Tiles[port];
            bool portOutputSignal = outputSignal;
            if (
              portTile.active() && portTile.type == (int)AdvancedCircuits.BlockType_NOTGate &&
              measureData.BlockType != AdvancedCircuits.BlockType_NOTGate
            ) {
              portOutputSignal = !portOutputSignal;
            } else if (
              portTile.active() && portTile.type == (int)AdvancedCircuits.BlockType_XORGate &&
              measureData.BlockType != AdvancedCircuits.BlockType_XORGate
            ) {
              portOutputSignal = false;
            }

            foreach (WireColor wireColor in AdvancedCircuits.EnumerateWireColors()) {
              if (!portTile.HasWire(wireColor))
            continue;

              RootBranchProcessData newRootBranch = new RootBranchProcessData(
            componentLocation, port, AdvancedCircuits.BoolToSignal(portOutputSignal), wireColor
              );
              if (blockActivatorToRegister != null) {
            newRootBranch.BlockActivator = blockActivatorToRegister;
            newRootBranch.BlockActivatorLocation = blockActivatorLocationToRegister;
            newRootBranch.BlockActivatorMode = blockActivatorModeToRegister;
              }
              newRootBranch.TeleporterLocation = rootBranch.TeleporterLocation;

              this.QueuedRootBranches.Add(newRootBranch);
            }
              }

              return true;
        }
 private void SendGatePortStatesInfo(TSPlayer player, GateStateMetadata gateState)
 {
     player.SendMessage("Top Port: " + this.GatePortStateToString(gateState.PortStates[0]), Color.LightGray);
       player.SendMessage("Left Port: " + this.GatePortStateToString(gateState.PortStates[2]), Color.LightGray);
       player.SendMessage("Bottom Port: " + this.GatePortStateToString(gateState.PortStates[1]), Color.LightGray);
       player.SendMessage("Right Port: " + this.GatePortStateToString(gateState.PortStates[3]), Color.LightGray);
 }