1.8.8 Detecting Creation of Custom Portal

Discussion in 'Spigot Plugin Development' started by Daimyo, Apr 2, 2020.

  1. So I'm trying to create a plugin that will create a portal upon placement of blocks in an arrangement.


    Code (Text):
    OXXXO
    XOOOX
    XOOOX
    XOOOX
    OXXXO

    Where X = Block, O = Anything Else
    What would be the most efficient way of accomplishing this?
    Right now I'm thinking:


    Code (Text):
    var options = list of possible block changes relative to block to reach center

    if (block to east is air) {
        remove options where the center of portal isn't to the west
    }

    if (block to south is air {
        remove options where the center of portal isn't up
    }

    etc etc
    Then once I've limited my options as much as possible, test each one for the surrounding blocks based on the center provided by the remaining options.

    But this seems like a lot to do on every block place event where the block matches the same type.
     
  2. In your case, every block can be described by checking its neighbors.
    The blocks in the top and bottom row, must have at least one block next to them that is of the portal material (or two in case of the middle block). If there is a block next to it, that is not of the portal material, check the block below / over that and if that one is the portal material again, you know that you found one of the upper / lower corner blocks and at the same time you can mark the other one as the top left / right corner block.
    The blocks on the sides, must have at least one block over / under them that is part of the portal material. If there is a block over / under it, that is not part of the portal, check the block left / right that one and if that one is the portal material again, you found one the left / right corner blocks.

    You see there is kind of an algorithm behind it, but there is not really a way around at least checking the neighbors (or in case of them not being portal material also that blocks neighbors), to 100% safe say, that the placed block is not part of a portal.

    As soon as you know it can not be part of the portal, you have to jump out.

    Since you want the portal to be formed on the last block being placed instead of using a tool / flint and steel, you will also not get around checking for the completeness of the portal.
    If you use a fixed size, you can make assumptions and from that placed block (after figuring out where exactly it is in the portal) "statically" check the other positions that need to be the portal material.
    If you don't use a fixed / you use a variable size, you have to again build a small algorithm that from your placed block, goes through the portal frame and as soon as it hits a block, that fails to find the next block in the portal, you have to jump out - or after you went through the whole portal and land on the starting block again (meaning you did verify, that you indeed have a full portal), you can form the final portal. Maybe caching / saving its position at this point is a good idea for later Block breaks events.

    Hope this helps you a little bit :)
     
  3. Gotcha, I figured as much. I'll probably switch over to making them confirm the portal creation just so it doesn't destroy server usage.

    Any idea how mods or MC does it?
     
  4. The way vanilla does this is in some sort of recursive way:
    Code (Java):
       @Nullable
       public NetherPortalBlock.Size isPortal(IWorld worldIn, BlockPos pos) {
          NetherPortalBlock.Size netherportalblock$size = new NetherPortalBlock.Size(worldIn, pos, Direction.Axis.X);
          if (netherportalblock$size.isValid() && netherportalblock$size.portalBlockCount == 0) {
             return netherportalblock$size;
          } else {
             NetherPortalBlock.Size netherportalblock$size1 = new NetherPortalBlock.Size(worldIn, pos, Direction.Axis.Z);
             return netherportalblock$size1.isValid() && netherportalblock$size1.portalBlockCount == 0 ? netherportalblock$size1 : null;
          }
       }
    And the inner class NetherPortalBlock.Size (note that some methods are missing):
    Code (Java):
       public static class Size {
          private final IWorld world;
          private final Direction.Axis axis;
          private final Direction rightDir;
          private final Direction leftDir;
          private int portalBlockCount;
          @Nullable
          private BlockPos bottomLeft;
          private int height;
          private int width;

          public Size(IWorld worldIn, BlockPos pos, Direction.Axis axisIn) {
             this.world = worldIn;
             this.axis = axisIn;
             if (axisIn == Direction.Axis.X) {
                this.leftDir = Direction.EAST;
                this.rightDir = Direction.WEST;
             } else {
                this.leftDir = Direction.NORTH;
                this.rightDir = Direction.SOUTH;
             }

             for(BlockPos blockpos = pos; pos.getY() > blockpos.getY() - 21 && pos.getY() > 0 && this.func_196900_a(worldIn.getBlockState(pos.down())); pos = pos.down()) {
                ;
             }

             int i = this.getDistanceUntilEdge(pos, this.leftDir) - 1;
             if (i >= 0) {
                this.bottomLeft = pos.offset(this.leftDir, i);
                this.width = this.getDistanceUntilEdge(this.bottomLeft, this.rightDir);
                if (this.width < 2 || this.width > 21) {
                   this.bottomLeft = null;
                   this.width = 0;
                }
             }

             if (this.bottomLeft != null) {
                this.height = this.calculatePortalHeight();
             }

          }

          public boolean isValid() {
             return this.bottomLeft != null && this.width >= 2 && this.width <= 21 && this.height >= 3 && this.height <= 21;
          }
       }