How do I get if a beacon is active?

Discussion in 'Spigot Plugin Development' started by Stuperfied, Jun 2, 2016.

  1. Anyone know how to detect if a beacon is active?

    Hopefully without going into craftbukkit.
     
  2. by active do you mean making a beam or giving people effects?
     
  3. Please be more specific.
     
  4. basing on what the title is, I think he meant that to check if the beacon has already activated the beam.
     
  5. check the underneath blocks?
     
  6. I think the client decides whether to render a beacon active or not based purely on the blocks under it. I would therefore check to see if the block below the beacon is one which would activate it. Eg. iron block, etc
     
  7. well bro we're not judging you goodluck for your project I hope you made a magic BeaconActivateEvent.
     
  8. try this https://bukkit.org/threads/util-beacon-blockstate-api-sort-of.164451/
     
  9. hmm, looks like it but my head hurts with all that reflection. Well I understand most of it, hopefully enough to use it.

    So basically in a nut shell, there are no public getter or setter methods available and this class is accessing the class methods directly to get the information. (I hope I used the terminology correctly.)

    tileEntityBeacon.setAccessible(true);
    primary.setAccessible(true);
    secondary.setAccessible(true);

    Cracking, I like it!
     
  10. Ok, so I gather that im meant to use that to check its tier? Does that mean that tier 0 is inactive? How many tiers are there?
     
  11. Problem...
    I copied the code exactly and it worked immediately however.

    When detecting a beacon under my feet.
    Test 1: place beacon on dirt, stand on beacon. - "The beacons Tier is: 0"
    Test 2: place beacon on 9 iron blocks. The beacon emits light however - "The beacons Tier is: 0"
    Test 3: place 1 iron in the beacon on the 9 iron blocks which is shining and select an effect. - "The beacons Tier is: 0"
    Test 4: place the beacon on 34 blocks of iron and activate with 2nd level of potion effects. - "The beacons Tier is: 0"
    Test 5: Stand on dirt, instead of beacon. - no message displayed.

    Code (Text):

    if (block.getType().equals(Material.BEACON)) {
            BeaconState state = new BeaconState(block);
            int tier = state.getTier();
            player.sendMessage("The beacons Tier is: " + tier);
    }
     
    What am I doing wrong?
    Error NPE
    BeaconState.getTier(BeaconState.java:153

    which is:
    return ((Integer) tier.invoke(blockState)).intValue();
     
  12. Although these may work with a CraftBukkit server, I have now tested both methods under Spigot 1.9.4 and neither of them worked.

    Code (Text):

    if (block.getType().equals(Material.BEACON)) {
                    BeaconTools test = new BeaconTools();  // Ref: https://github.com/SocialCraft/Pret...stirante/PrettyScaryLib/BeaconHelper.java#L91
                    if (test.isActive(block)) {
                        player.sendMessage("The beacon is active");
                    } else {
                        player.sendMessage("The beacon is not active");
                    }
                    BeaconState state = new BeaconState(block);  // Ref: https://bukkit.org/threads/util-beacon-blockstate-api-sort-of.164451/
                    int tier = state.getTier();
                    player.sendMessage("The beacons Tier is: " + tier);
    }
     
    BeaconTools:
    NoSuchFieldException: e

    BeaconState:
    NPE
     
    #13 Stuperfied, Jun 3, 2016
    Last edited: Jun 3, 2016
  13. Hack a little this, hack a little that...

    Code (Text):
    fields = TileEntityBeacon.class.getDeclaredFields();
                int i = 0;
                for (Field field : fields) {
                    System.out.println("field " + i + "Name: " + field.getName() + "Type: " + field.getType());
                    i++;
                }
                active = TileEntityBeacon.class.getDeclaredField("k");
                active.setAccessible(true);
                int value = (Integer) active.get(beacon);
                System.out.println("field: " + active.getName() + " = " + value);
                return true; //(Boolean) active.get(beacon);
     
    Its k and j peoples.....

    1. f = interface java.util.Set
    2. g = interface java.util.List
    3. j = boolean
    4. k = int
    5. l = net.minecraft.server.v1_9_R2.MobEffectList
    6. m = net.minecraft.server.v1_9_R2.MobEffectList
    7. inventorySlotType = net.minecraft.server.v1_9_R2.ItemStack
    8. o = class java.lang.String
    9. transactionType = interface java.util.List
    10. maxStackType = int
     
    #14 Stuperfied, Jun 3, 2016
    Last edited: Jun 3, 2016
  14. Ok, so I made a few changes. Getting the tier from this code now works with my new update. As for the rest of it... Well I fiddled a little but have not tested anything so the rest may still be broken but I have contacted the original developer about getting it updated properly.

    My changes are noted in the code.

    Code (Text):

    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import org.bukkit.Bukkit;
    import org.bukkit.block.Block;
    import org.bukkit.block.BlockState;
    import org.bukkit.entity.LivingEntity;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.potion.PotionEffectType;
    /**
    *
    * @author Foodyling
    */
    public class BeaconState {
        public static class ReflectionUtil {
            private static final String MC_VERSION = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
            public static Class<?> forClassName(String name) {
                try {
                    return Class.forName(name.replace("%MC_VERSION%", MC_VERSION));
                } catch (Throwable error) {
                    return null;
                }
            }
            public static Method getMethod(Class<?> clazz, String methodName, Class<?>... params) {
                try {
                    return clazz.getMethod(methodName, params);
                } catch (Throwable error) {
                    return null;
                }
            }
            public static Field getField(Class<?> clazz, String fieldName) {
                try {
                    return clazz.getDeclaredField(fieldName);
                } catch (Throwable error) {
                    return null;
                }
            }
        }
     
        private static final Class<?> beaconState = ReflectionUtil.forClassName("net.minecraft.server.%MC_VERSION%.TileEntityBeacon"),
                craftBeacon = ReflectionUtil.forClassName("org.bukkit.craftbukkit.%MC_VERSION%.block.CraftBeacon"),
                entityHuman = ReflectionUtil.forClassName("net.minecraft.server.%MC_VERSION%.EntityHuman");

        private static final Field tileEntityBeacon = ReflectionUtil.getField(craftBeacon, "beacon"),
                tier = ReflectionUtil.getField(beaconState, "k"),
                primary = ReflectionUtil.getField(beaconState, "l"),
                secondary = ReflectionUtil.getField(beaconState, "m");

        private static final Method getName = ReflectionUtil.getMethod(beaconState, "getName"),
                setName = ReflectionUtil.getMethod(beaconState, "o", String.class),
                getItem = ReflectionUtil.getMethod(beaconState, "g", int.class),
                setItem = ReflectionUtil.getMethod(beaconState, "f", int.class, ItemStack.class);
       /*
        *  // Self explanatory
        private static final Class<?> beaconState = ReflectionUtil.forClassName("net.minecraft.server.%MC_VERSION%.TileEntityBeacon"),
                                      craftBeacon = ReflectionUtil.forClassName("org.bukkit.craftbukkit.%MC_VERSION%.block.CraftBeacon"),
                                      entityHuman = ReflectionUtil.forClassName("net.minecraft.server.%MC_VERSION%.EntityHuman");
     
        private static final Field tileEntityBeacon = ReflectionUtil.getField(craftBeacon, "beacon"),
                                  primary = ReflectionUtil.getField(beaconState, "f"),
                                  secondary = ReflectionUtil.getField(beaconState, "g");
     
        private static final Method getName = ReflectionUtil.getMethod(beaconState, "getName"),
                                    setName = ReflectionUtil.getMethod(beaconState, "a", String.class),
                                    tier = ReflectionUtil.getMethod(beaconState, "l"),
                                    getItem = ReflectionUtil.getMethod(beaconState, "getItem", int.class),
                                    setItem = ReflectionUtil.getMethod(beaconState, "setItem", int.class, ItemStack.class);
       */
        static {
            tileEntityBeacon.setAccessible(true);
            tier.setAccessible(true); // <-- set to accessible
            primary.setAccessible(true);
            secondary.setAccessible(true);
        }
     
        private final Block block;
        private final Object blockState;
     
        public BeaconState(Block block) {
            this(block.getState());
        }
     
        public BeaconState(BlockState state) {
            if (craftBeacon.isInstance(state)) {
                try {
                    this.block = state.getBlock();
                    this.blockState = tileEntityBeacon.get(craftBeacon.cast(state));
                } catch (Throwable error) {
                    throw new IllegalArgumentException("BlockState must be a instance of org.bukkit.craftbukkit.block.CraftBeacon");            
                }
            } else {
                throw new IllegalArgumentException("BlockState must be a instance of org.bukkit.craftbukkit.block.CraftBeacon");
            }
        }
     
        public static BeaconState asBeacon(Block block) {
            return new BeaconState(block);
        }
     
        public static BeaconState asBeacon(BlockState state) {
            return new BeaconState(state);
        }
     
        public Block getBlock() {
            return block;
        }
     
        public String getName() {
            try {
                return (String) getName.invoke(blockState);
            } catch (Throwable error) {
                return null;
            }
        }
     
        public void setName(String name) {
            try {
                setName.invoke(blockState, name);
            } catch (Throwable error) {
                error.printStackTrace();
            }
        }
     
        public PotionEffectType getPrimary() {
            try {
                return PotionEffectType.getById(primary.getInt(blockState));
            } catch (Throwable error) {
                return null;
            }
        }
     
        public PotionEffectType getSecondary() {
            try {
                return PotionEffectType.getById(secondary.getInt(blockState));
            } catch (Throwable error) {
                return null;
            }
        }
     
        public void setPrimary(PotionEffectType type) {
            try {
                primary.setInt(blockState, type.getId());
            } catch (Throwable error) {
                error.printStackTrace();
            }
        }
     
        public void setSecondary(PotionEffectType type) {
            try {
                secondary.setInt(blockState, type.getId());
            } catch (Throwable error) {
                error.printStackTrace();
            }
        }
     
        public void setBoth(PotionEffectType type) {
            setPrimary(type);
            setSecondary(type);
        }
     
        public int getTier() {
            try {
                // return ((Integer) tier.invoke(blockState)).intValue();
                return ((Integer) tier.getInt(blockState)).intValue(); // is now a Field, not a Method
            } catch (Throwable error) {
                error.printStackTrace();
                return 0;
            }
        }
     
        public ItemStack getItem() {
            try {
                return (ItemStack) getItem.invoke(blockState, 0);
            } catch (Throwable error) {
                return null;
            }
        }
     
        public void setItem(ItemStack stack) {
            try {
                setItem.invoke(blockState, 0, stack);
            } catch (Throwable error) {
         
            }
        }
     
        public boolean applicableFor(LivingEntity entity) {
            if (entityHuman.isInstance(entity)) {
                return entity.getLocation().distanceSquared(block.getLocation()) <= 4096;
            }
            return false;
        }
    }
     
    For others wishing to know why im not focusing on the boolean. Tier is zero for inactive beacons, so if you place a solid block above a tier 4 active beacon, the tier is now zero as the beacon deactivates.
     
    #15 Stuperfied, Jun 3, 2016
    Last edited: Jun 3, 2016
  15. There is an API-Version available: Beacon#getPrimaryEffect() should return null when the beacon is deactivated and not null else
     
  16. This has nothing to do with the request. The user specified that he wants to know whenever the beacon emits a beam, not if it gives effect(s).
     
  17. But it should only emit effects when it’s active (the beacon emits a beam). Was just an idea thou, not sure if that’s working
     
  18. Rather you should be checking for Beacon#getTier() as stated here:
    Code (Text):
    Returns the tier of the beacon pyramid (0-4). The tier refers to the beacon's power level, based on how many layers of blocks are in the pyramid. Tier 1 refers to a beacon with one layer of 9 blocks under it.
    Which means a tier of 0 will be deemed as inactive aka no beam. This was stated already in the last post that solved this in 2016 btw, the only difference is it was using NMS because there wasn't a beacon API that long ago. This thread is 4 years ago, the person who bumped it isn't even the owner of the thread so they should rather have made a new one instead.
     
    • Agree Agree x 1