public static DPoint OffsetPolar(this DPoint point, float angle, float steps)
 {
     return(point.OffsetEx((int)(Math.Cos(angle) * steps), (int)(Math.Sin(angle) * steps)));
 }
        public virtual bool HandleChestPlace(TSPlayer player, DPoint location, ChestStyle chestStyle)
        {
            if (this.IsDisposed)
            return false;
              //if (chestIndex != -1 || !player.IsLoggedIn)
              //  return false;

              for (int x = 0; x < 2; x++) {
            DPoint tileBeneathLocation = location.OffsetEx(x, 1);
            if (
              TerrariaUtils.Tiles[tileBeneathLocation].active() && (
            TerrariaUtils.Tiles[tileBeneathLocation].type == (int)BlockType.ActiveStone ||
            TerrariaUtils.Tiles[tileBeneathLocation].type == (int)BlockType.IceRodBlock
              )
            ) {
              TSPlayer.All.SendData(PacketTypes.Tile, string.Empty, 0, location.X, location.Y);

              int itemType = (int)TerrariaUtils.Tiles.GetItemTypeFromChestType(chestStyle);
              Item.NewItem(location.X * TerrariaUtils.TileSize, location.Y * TerrariaUtils.TileSize, 32, 32, itemType);

              player.SendErrorMessage("Chests can not be placed on active stone or ice blocks.");
              return true;
            }
              }

              return this.HandlePostTileEdit(player, TileEditType.PlaceTile, BlockType.Chest, location, (int)chestStyle);
        }
        protected virtual void ProcessTile(
            RootBranchProcessData rootBranch, DPoint tileLocation, DPoint adjacentTileLocation, SignalType signal
            )
        {
            if (this.IsCancellationPending)
            return;

              Tile tile = TerrariaUtils.Tiles[tileLocation];

              // If the tile has no wire it might be a AC-Component and thus the adjacent tile would be its port.
              if (!tile.HasWire(rootBranch.WireColor) && tile.active()) {
            if (!this.IsAdvancedCircuit || adjacentTileLocation == DPoint.Empty)
              return;
            if (!AdvancedCircuits.IsPortDefiningComponentBlock((BlockType)tile.type))
              return;
            if (signal == SignalType.Swap)
              throw new ArgumentException("A Port can not receive a Swap signal.", "signal");

            ObjectMeasureData acComponentMeasureData = TerrariaUtils.Tiles.MeasureObject(tileLocation);
            // The origin sender can only signal itself if it is a timer.
            if (
              acComponentMeasureData.OriginTileLocation == this.SenderMeasureData.OriginTileLocation &&
              tile.type != (int)BlockType.XSecondTimer
            ) {
              return;
            }

            int componentSignalCounter;
            this.PortDefiningComponentSignalCounter.TryGetValue(acComponentMeasureData.OriginTileLocation, out componentSignalCounter);
            if (componentSignalCounter > CircuitProcessor.PortDefiningComponentSignalMaximum) {
              this.Result.CancellationReason = CircuitCancellationReason.SignaledSameComponentTooOften;
              this.Result.CancellationRelatedComponentType = acComponentMeasureData.BlockType;
              return;
            }

            if (
              AdvancedCircuits.IsOriginSenderComponent((BlockType)tile.type) &&
              rootBranch.SignaledComponentLocations.Contains(acComponentMeasureData.OriginTileLocation)
            )
              return;

            if (this.SignalPortDefiningComponent(
              rootBranch, acComponentMeasureData, adjacentTileLocation, AdvancedCircuits.SignalToBool(signal).Value
            )) {
              rootBranch.SignaledComponentLocations.Add(acComponentMeasureData.OriginTileLocation);

              if (componentSignalCounter == default(int))
            this.PortDefiningComponentSignalCounter.Add(acComponentMeasureData.OriginTileLocation, 1);
              else
            this.PortDefiningComponentSignalCounter[acComponentMeasureData.OriginTileLocation] = componentSignalCounter + 1;

              this.Result.SignaledPortDefiningComponentsCounter++;
            }

            return;
              }

              if (!tile.HasWire(rootBranch.WireColor))
            return;

              try {
            // Actuator Handling
            if (tile.actuator() && (tile.type != (int)BlockType.LihzahrdBrick || tileLocation.Y <= Main.worldSurface || NPC.downedPlantBoss)) {
              bool currentState = tile.inActive();
              bool newState;
              if (signal == SignalType.Swap)
            newState = !currentState;
              else
            newState = AdvancedCircuits.SignalToBool(signal).Value;

              if (newState != currentState) {
            if (newState)
              WorldGen.DeActive(tileLocation.X, tileLocation.Y);
            else
              WorldGen.ReActive(tileLocation.X, tileLocation.Y);
              }
            }

            // Block Activator tile activation / deactivation.
            if (rootBranch.BlockActivator != null) {
              Tile blockActivatorTile = TerrariaUtils.Tiles[rootBranch.BlockActivatorLocation];
              if (tile.wall == blockActivatorTile.wall) {
            Tile tileAbove = TerrariaUtils.Tiles[tileLocation.OffsetEx(0, -1)];
            if (!tileAbove.active() || tileAbove.type != (int)BlockType.Chest) {
              if (
                signal == SignalType.Off && tile.active() && AdvancedCircuits.IsCustomActivatableBlock((BlockType)tile.type)
              ) {
                if (rootBranch.BlockActivator.RegisteredInactiveBlocks.Count > this.CircuitHandler.Config.BlockActivatorConfig.MaxChangeableBlocks) {
                  this.Result.WarnReason = CircuitWarnReason.BlockActivatorChangedTooManyBlocks;
                  return;
                }

                rootBranch.BlockActivator.RegisteredInactiveBlocks.Add(tileLocation, (BlockType)tile.type);

                tile.type = 0;
                tile.active(false);
                tile.frameX = -1;
                tile.frameY = -1;
                tile.frameNumber(0);
                this.TilesToFrameOnPost.Add(tileLocation);

                return;
              } else if (
                signal == SignalType.On && (rootBranch.BlockActivatorMode == BlockActivatorMode.ReplaceBlocks || !tile.active())
              ) {
                BlockType registeredBlockType;
                if (rootBranch.BlockActivator.RegisteredInactiveBlocks.TryGetValue(tileLocation, out registeredBlockType)) {
                  rootBranch.BlockActivator.RegisteredInactiveBlocks.Remove(tileLocation);

                  tile.type = (byte)registeredBlockType;
                  tile.active(true);
                  this.TilesToFrameOnPost.Add(tileLocation);

                  return;
                }
              }
            }
              }
            }

            if (!tile.active())
              return;

            ObjectMeasureData componentMeasureData = TerrariaUtils.Tiles.MeasureObject(tileLocation);
            if (rootBranch.SignaledComponentLocations.Contains(componentMeasureData.OriginTileLocation))
              return;

            // The origin sender can never signal itself if wired directly.
            if (componentMeasureData.OriginTileLocation == this.SenderMeasureData.OriginTileLocation)
              return;

            // Switches and Levers can not be signaled if they are wired directly.
            if (tile.type == (int)BlockType.Switch || tile.type == (int)BlockType.Lever)
              return;

            if (this.SignalComponent(ref componentMeasureData, rootBranch, signal)) {
              rootBranch.SignaledComponentLocations.Add(componentMeasureData.OriginTileLocation);
              this.Result.SignaledComponentsCounter++;
            }
              } finally {
            this.CircuitLength++;

            if (this.CircuitLength >= this.CircuitHandler.Config.MaxCircuitLength) {
              this.Result.CancellationReason = CircuitCancellationReason.ExceededMaxLength;
              this.PluginTrace.WriteLineInfo(
            "Processing of the circuit at {0} was cancelled because the signal reached the maximum transfer length of {1} wires.",
            this.SenderMeasureData.OriginTileLocation, this.CircuitHandler.Config.MaxCircuitLength
              );
            }
              }
        }
    private void AC_WirelessTransmitter2(TestContext context) {
      DPoint testOffset = new DPoint(440, 362);

      this.Config.WirelessTransmitterConfigs[ComponentConfigProfile.Default].Range = 5;
      this.Config.WirelessTransmitterConfigs[ComponentConfigProfile.Default].Cooldown = 0;

      this.MetadataHandler.Metadata.WirelessTransmitters.Clear();
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(10, 0), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(7, 1), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(0, 5), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(2, 5), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(4, 5), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(6, 5), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(9, 5), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(11, 5), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(13, 5), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(9, 9), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(3, 10), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(1, 11), this.GetTestPlayer().Name);

      context.Phase = "1";
      this.QuickProcessCircuit(testOffset.X + 6, testOffset.Y + 12);
      TAssert.IsObjectActive(testOffset.X + 10, testOffset.Y + 1);
      TAssert.IsObjectInactive(testOffset.X + 7, testOffset.Y + 2);
      TAssert.IsObjectActive(testOffset.X, testOffset.Y + 6);
      TAssert.IsObjectInactive(testOffset.X + 2, testOffset.Y + 6);
      TAssert.IsObjectInactive(testOffset.X + 4, testOffset.Y + 6);
      TAssert.IsObjectInactive(testOffset.X + 9, testOffset.Y + 6);
      TAssert.IsObjectInactive(testOffset.X + 11, testOffset.Y + 6);
      TAssert.IsObjectActive(testOffset.X + 13, testOffset.Y + 6);
      TAssert.IsObjectInactive(testOffset.X + 9, testOffset.Y + 10);
      TAssert.IsObjectInactive(testOffset.X + 3, testOffset.Y + 11);
      TAssert.IsObjectActive(testOffset.X + 1, testOffset.Y + 12);

      context.Phase = "2";
      this.QuickProcessCircuit(testOffset.X + 6, testOffset.Y + 12);
      TAssert.IsObjectActive(testOffset.X + 10, testOffset.Y + 1);
      TAssert.IsObjectActive(testOffset.X + 7, testOffset.Y + 2);
      TAssert.IsObjectActive(testOffset.X, testOffset.Y + 6);
      TAssert.IsObjectActive(testOffset.X + 2, testOffset.Y + 6);
      TAssert.IsObjectActive(testOffset.X + 4, testOffset.Y + 6);
      TAssert.IsObjectActive(testOffset.X + 9, testOffset.Y + 6);
      TAssert.IsObjectActive(testOffset.X + 11, testOffset.Y + 6);
      TAssert.IsObjectActive(testOffset.X + 13, testOffset.Y + 6);
      TAssert.IsObjectActive(testOffset.X + 9, testOffset.Y + 10);
      TAssert.IsObjectActive(testOffset.X + 3, testOffset.Y + 11);
      TAssert.IsObjectActive(testOffset.X + 1, testOffset.Y + 12);

      context.Phase = "3";
      this.QuickProcessCircuit(testOffset.X + 6, testOffset.Y + 12);
      TAssert.IsObjectActive(testOffset.X + 10, testOffset.Y + 1);
      TAssert.IsObjectInactive(testOffset.X + 7, testOffset.Y + 2);
      TAssert.IsObjectActive(testOffset.X, testOffset.Y + 6);
      TAssert.IsObjectInactive(testOffset.X + 2, testOffset.Y + 6);
      TAssert.IsObjectInactive(testOffset.X + 4, testOffset.Y + 6);
      TAssert.IsObjectInactive(testOffset.X + 9, testOffset.Y + 6);
      TAssert.IsObjectInactive(testOffset.X + 11, testOffset.Y + 6);
      TAssert.IsObjectActive(testOffset.X + 13, testOffset.Y + 6);
      TAssert.IsObjectInactive(testOffset.X + 9, testOffset.Y + 10);
      TAssert.IsObjectInactive(testOffset.X + 3, testOffset.Y + 11);
      TAssert.IsObjectActive(testOffset.X + 1, testOffset.Y + 12);
    }
    private void AC_WirelessTransmitter(TestContext context) {
      DPoint testOffset = new DPoint(422, 371);

      context.Phase = "1-1";
      this.Config.WirelessTransmitterConfigs[ComponentConfigProfile.Default].Range = 3;
      this.Config.WirelessTransmitterConfigs[ComponentConfigProfile.Default].Cooldown = 0;
      this.MetadataHandler.Metadata.WirelessTransmitters.Clear();
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset, this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(2, 0), this.GetTestPlayer().Name);

      this.QuickProcessCircuit(testOffset.X, testOffset.Y + 3);
      TAssert.IsObjectInactive(testOffset.X + 2, testOffset.Y + 3);

      context.Phase = "1-2";
      this.QuickProcessCircuit(testOffset.X, testOffset.Y + 3);
      TAssert.IsObjectActive(testOffset.X + 2, testOffset.Y + 3);

      context.Phase = "1-3";
      this.QuickProcessCircuit(testOffset.X, testOffset.Y + 3);
      TAssert.IsObjectInactive(testOffset.X + 2, testOffset.Y + 3);

      context.Phase = "2-1";
      testOffset.Offset(5, 0);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset, this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(2, 0), this.GetTestPlayer().Name);

      this.QuickProcessCircuit(testOffset.X, testOffset.Y + 3);
      TAssert.IsObjectActive(testOffset.X + 2, testOffset.Y + 3);

      context.Phase = "2-2";
      this.QuickProcessCircuit(testOffset.X, testOffset.Y + 3);
      TAssert.IsObjectActive(testOffset.X + 2, testOffset.Y + 3);

      context.Phase = "2-3";
      this.QuickProcessCircuit(testOffset.X, testOffset.Y + 3);
      TAssert.IsObjectActive(testOffset.X + 2, testOffset.Y + 3);

      context.Phase = "3-1";
      this.Config.WirelessTransmitterConfigs[ComponentConfigProfile.Default].Range = 6;
      testOffset.Offset(5, 0);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset, this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(2, 0), this.GetTestPlayer().Name);
      this.MetadataHandler.Metadata.WirelessTransmitters.Add(testOffset.OffsetEx(4, 0), this.GetTestPlayer().Name);

      this.QuickProcessCircuit(testOffset.X, testOffset.Y + 3);
      TAssert.IsObjectInactive(testOffset.X + 2, testOffset.Y + 3);
      TAssert.IsObjectActive(testOffset.X + 4, testOffset.Y + 3);

      context.Phase = "3-2";
      this.QuickProcessCircuit(testOffset.X, testOffset.Y + 3);
      TAssert.IsObjectActive(testOffset.X + 2, testOffset.Y + 3);
      TAssert.IsObjectInactive(testOffset.X + 4, testOffset.Y + 3);

      context.Phase = "3-3";
      this.QuickProcessCircuit(testOffset.X, testOffset.Y + 3);
      TAssert.IsObjectInactive(testOffset.X + 2, testOffset.Y + 3);
      TAssert.IsObjectActive(testOffset.X + 4, testOffset.Y + 3);
    }
 private void SendFakeWireCross(TSPlayer player, DPoint crossLocation)
 {
     this.SendFakeTileWire(player, crossLocation);
       this.SendFakeTileWire(player, crossLocation.OffsetEx(-1, 0));
       this.SendFakeTileWire(player, crossLocation.OffsetEx(1, 0));
       this.SendFakeTileWire(player, crossLocation.OffsetEx(0, -1));
       this.SendFakeTileWire(player, crossLocation.OffsetEx(0, 1));
 }
        /// <remarks>
        ///   <p>
        ///     A object is considered any tile type the player is not blocked from passing through plus 
        ///     Active Stone, Boulders, Wood Platforms and Dart Traps. However, this method will still measure
        ///     any other block type too.
        ///   </p>
        ///   <p>
        ///     The origin tile of most objects is their most top left tile. Exceptions are trees and glowing mushrooms where 
        ///     the origin tile is their middle stump. Vines have their origin tile at the root on top. Doors have their origin
        ///     tile at their top bracing.
        ///   </p>
        /// </remarks>
        public ObjectMeasureData MeasureObject(DPoint anyTileLocation)
        {
            Tile tile = TerrariaUtils.Tiles[anyTileLocation];
              if (!tile.active()) {
            throw new ArgumentException(string.Format(
              "The tile at location {0} can not be measured because its not active", anyTileLocation
            ));
              }

              DPoint objectSize = this.GetObjectSize((BlockType)tile.type);
              DPoint textureTileSize = this.GetBlockTextureTileSize((BlockType)tile.type);
              DPoint textureFrameLocation = DPoint.Empty;

              switch ((BlockType)tile.type) {
            case BlockType.Undefined2:
              if (tile.frameY <= 72)
            objectSize = new DPoint(1, 2);

              break;
            case BlockType.Undefined15: {
              if (tile.frameY >= 36)
            objectSize = new DPoint(2, 2);

              break;
            }
              }

              DPoint originTileLocation;
              switch ((BlockType)tile.type) {
            case BlockType.Cactus: {
              // Removed dynamic measuring support for Cactus due to Terraria bugs...
              originTileLocation = anyTileLocation;
              textureFrameLocation = new DPoint(tile.frameX / textureTileSize.X, tile.frameY / textureTileSize.Y);
              break;
            }
            case BlockType.Tree:
            case BlockType.GiantGlowingMushroom: {
            //case Terraria.TileId_Cactus: {
              // We consider the origin tile of Trees, Giant Glowing Mushrooms and Cacti their most bottom tile (stump) instead
              // of the most top left tile.
              DPoint anyTrunkTileLocation = anyTileLocation;
              if (tile.type == (int)BlockType.Tree) {
            if (this.IsLeftTreeBranch(tile))
              anyTrunkTileLocation = anyTileLocation.OffsetEx(1, 0);
            else if (this.IsRightTreeBranch(tile))
              anyTrunkTileLocation = anyTileLocation.OffsetEx(-1, 0);
              } else if (tile.type == (int)BlockType.Cactus) {
            if (this.IsLeftCactusBranch(tile))
              anyTrunkTileLocation = anyTileLocation.OffsetEx(1, 0);
            else if (this.IsRightCactusBranch(tile))
              anyTrunkTileLocation = anyTileLocation.OffsetEx(-1, 0);
              }

              // Go all the way down to the tree's stump.
              DPoint currentTileLocation = anyTrunkTileLocation;
              while (true) {
            Tile currentTile = TerrariaUtils.Tiles[currentTileLocation.OffsetEx(0, 1)];

            if (currentTile.active() && currentTile.type == tile.type)
              currentTileLocation.Y++;
            else
              break;
              }
              DPoint treeStumpLocation = currentTileLocation;
              objectSize = new DPoint(3, (treeStumpLocation.Y - anyTrunkTileLocation.Y) + 1);

              // Now measure the tree's size by going it up.
              currentTileLocation = anyTrunkTileLocation;
              while (true) {
            Tile currentTile = TerrariaUtils.Tiles[currentTileLocation.OffsetEx(0, -1)];

            if (currentTile.active() && currentTile.type == tile.type) {
              currentTileLocation.Y--;
              objectSize.Y++;
            } else {
              break;
            }
              }

              originTileLocation = treeStumpLocation;
              textureFrameLocation = new DPoint(tile.frameX / textureTileSize.X, tile.frameY / textureTileSize.Y);
              break;
            }
            case BlockType.Vine:
            case BlockType.JungleVine:
            case BlockType.HallowedVine:
            case BlockType.Undefined14: {
              DPoint currentTileLocation = anyTileLocation;

              while (true) {
            Tile currentTile = TerrariaUtils.Tiles[currentTileLocation.OffsetEx(0, -1)];

            if (currentTile.type == tile.type) {
              currentTileLocation.Y--;
              objectSize.Y++;
            } else {
              break;
            }
              }
              originTileLocation = currentTileLocation;
              objectSize = new DPoint(1, (anyTileLocation.Y - originTileLocation.Y) + 1);

              // Now measure the vines's size by going it down.
              currentTileLocation = anyTileLocation;
              while (true) {
            Tile currentTile = TerrariaUtils.Tiles[currentTileLocation.OffsetEx(0, 1)];

            if (currentTile.type == tile.type) {
              currentTileLocation.Y++;
              objectSize.Y++;
            } else {
              break;
            }
              }

              textureFrameLocation = new DPoint(tile.frameX / textureTileSize.X, tile.frameY / textureTileSize.Y);
              break;
            }
            case BlockType.DoorOpened:
            case BlockType.TrapdoorOpen: {
              int textureTileX = tile.frameX / textureTileSize.X;

              if (this.GetDoorDirection(anyTileLocation) == Direction.Right ||
            this.GetDoorDirection(anyTileLocation) == Direction.Up) {
            originTileLocation = anyTileLocation.OffsetEx(-textureTileX, -(tile.frameY / textureTileSize.Y));
              } else {
            originTileLocation = anyTileLocation.OffsetEx(
              -(textureTileX - objectSize.X) + 1, -(tile.frameY / textureTileSize.Y)
            );
            textureFrameLocation = new DPoint(1, 0);
              }

              break;
            }
            default: {
              if (objectSize.X == 1 && objectSize.Y == 1) {
            originTileLocation = anyTileLocation;
            textureFrameLocation = new DPoint(tile.frameX / textureTileSize.X, tile.frameY / textureTileSize.Y);
              } else {
            int textureTileX = tile.frameX / textureTileSize.X;
            int textureTileY = tile.frameY / textureTileSize.Y;
            int textureFrameX = textureTileX / objectSize.X;
            int textureFrameY = textureTileY / objectSize.Y;

            originTileLocation = anyTileLocation.OffsetEx(
              -(textureTileX - (textureFrameX * objectSize.X)),
              -(textureTileY - (textureFrameY * objectSize.Y))
            );

            textureFrameLocation = new DPoint(textureFrameX, textureFrameY);
              }

              break;
            }
              }

              return new ObjectMeasureData(
            (BlockType)tile.type, originTileLocation, objectSize, textureTileSize, textureFrameLocation
              );
        }
Exemple #8
0
    /// <remarks>
    ///   <p>
    ///     A object is considered any tile type the player is not blocked from passing through plus 
    ///     Active Stone, Boulders, Wood Platforms and Dart Traps. However, this method will still measure
    ///     any other block type too.
    ///   </p>
    ///   <p>
    ///     The origin tile of most objects is their most top left tile. Exceptions are trees and glowing mushrooms where 
    ///     the origin tile is their middle stump. Vines have their origin tile at the root on top. Doors have their origin
    ///     tile at their top bracing.
    ///   </p>
    /// </remarks>
    public ObjectMeasureData MeasureObject(DPoint anyTileLocation) {
      ITile tile = TerrariaUtils.Tiles[anyTileLocation];
      if (!tile.active())
        throw new ArgumentException($"The tile at location {anyTileLocation} can not be measured because its not active");

      TileObjectData objectData = TileObjectData.GetTileData(tile);
      DPoint objectSize = new DPoint(1, 1);
      DPoint textureTileSize = new DPoint(TerrariaUtils.DefaultTextureTileSize, TerrariaUtils.DefaultTextureTileSize);
      if (objectData != null) {
        objectSize = new DPoint(objectData.Width, objectData.Height);
        textureTileSize = new DPoint(objectData.CoordinateWidth + objectData.CoordinatePadding, objectData.CoordinateHeights[0] + objectData.CoordinatePadding);
      }
      DPoint textureFrameLocation = DPoint.Empty;

      DPoint originTileLocation;
      switch (tile.type) {
        case TileID.Cactus: {
          // Removed dynamic measuring support for Cactus due to Terraria bugs...
          originTileLocation = anyTileLocation;
          textureFrameLocation = new DPoint(tile.frameX / textureTileSize.X, tile.frameY / textureTileSize.Y);
          break;
        }
        case TileID.Trees: 
        case TileID.MushroomTrees: {
          // Consider the origin tile of Trees, Giant Glowing Mushrooms and Cacti their most bottom tile (stump) instead
          // of the most top left tile.
          DPoint anyTrunkTileLocation = anyTileLocation;
          if (tile.type == TileID.Trees) {
            if (this.IsLeftTreeBranch(tile))
              anyTrunkTileLocation = anyTileLocation.OffsetEx(1, 0);
            else if (this.IsRightTreeBranch(tile))
              anyTrunkTileLocation = anyTileLocation.OffsetEx(-1, 0);
          } else if (tile.type == TileID.Cactus) {
            if (this.IsLeftCactusBranch(tile))
              anyTrunkTileLocation = anyTileLocation.OffsetEx(1, 0);
            else if (this.IsRightCactusBranch(tile))
              anyTrunkTileLocation = anyTileLocation.OffsetEx(-1, 0);
          }

          // Go all the way down to the tree's stump.
          DPoint currentTileLocation = anyTrunkTileLocation;
          while (true) {
            ITile currentTile = TerrariaUtils.Tiles[currentTileLocation.OffsetEx(0, 1)];

            if (currentTile.active() && currentTile.type == tile.type)
              currentTileLocation.Y++;
            else 
              break;
          }
          DPoint treeStumpLocation = currentTileLocation;
          objectSize = new DPoint(3, (treeStumpLocation.Y - anyTrunkTileLocation.Y) + 1);

          // Now measure the tree's size by going it up.
          currentTileLocation = anyTrunkTileLocation;
          while (true) {
            ITile currentTile = TerrariaUtils.Tiles[currentTileLocation.OffsetEx(0, -1)];

            if (currentTile.active() && currentTile.type == tile.type) {
              currentTileLocation.Y--;
              objectSize.Y++;
            } else {
              break;
            }
          }

          originTileLocation = treeStumpLocation;
          textureFrameLocation = new DPoint(tile.frameX / textureTileSize.X, tile.frameY / textureTileSize.Y);
          break;
        }
        case TileID.Vines:
        case TileID.JungleVines:
        case TileID.HallowedVines:
        case TileID.CrimsonVines: {
          DPoint currentTileLocation = anyTileLocation;

          while (true) {
            ITile currentTile = TerrariaUtils.Tiles[currentTileLocation.OffsetEx(0, -1)];

            if (currentTile.type == tile.type) {
              currentTileLocation.Y--;
              objectSize.Y++;
            } else {
              break;
            }
          }
          originTileLocation = currentTileLocation;
          objectSize = new DPoint(1, (anyTileLocation.Y - originTileLocation.Y) + 1);

          // Now measure the vines's size by going it down.
          currentTileLocation = anyTileLocation;
          while (true) {
            ITile currentTile = TerrariaUtils.Tiles[currentTileLocation.OffsetEx(0, 1)];

            if (currentTile.type == tile.type) {
              currentTileLocation.Y++;
              objectSize.Y++;
            } else {
              break;
            }
          }

          textureFrameLocation = new DPoint(tile.frameX / textureTileSize.X, tile.frameY / textureTileSize.Y);
          break;
        }
        case TileID.OpenDoor: 
        case TileID.TrapdoorOpen: {
          int textureTileX = tile.frameX / textureTileSize.X;

          if (this.GetDoorDirection(anyTileLocation) == Direction.Right ||
            this.GetDoorDirection(anyTileLocation) == Direction.Up) {
            originTileLocation = anyTileLocation.OffsetEx(-textureTileX, -(tile.frameY / textureTileSize.Y));
          } else {
            originTileLocation = anyTileLocation.OffsetEx(
              -(textureTileX - objectSize.X) + 1, -(tile.frameY / textureTileSize.Y)
            );
            textureFrameLocation = new DPoint(1, 0);
          }

          break;
        }
        default: {
          if (objectSize.X == 1 && objectSize.Y == 1) {
            originTileLocation = anyTileLocation;
            textureFrameLocation = new DPoint(tile.frameX / textureTileSize.X, tile.frameY / textureTileSize.Y);
          } else {
            int textureTileX = tile.frameX / textureTileSize.X;
            int textureTileY = tile.frameY / textureTileSize.Y;
            int textureFrameX = textureTileX / objectSize.X;
            int textureFrameY = textureTileY / objectSize.Y;

            originTileLocation = anyTileLocation.OffsetEx(
              -(textureTileX - (textureFrameX * objectSize.X)),
              -(textureTileY - (textureFrameY * objectSize.Y))
            );

            textureFrameLocation = new DPoint(textureFrameX, textureFrameY);
          }

          break;
        }
      }

      return new ObjectMeasureData(
        tile.type, originTileLocation, objectSize, textureTileSize, textureFrameLocation
      );
    }