Skip to content

Commit

Permalink
Parent/sub-flag support, split up and designate CONTAINER flag as par…
Browse files Browse the repository at this point in the history
…ent flag (#1784)

* Split CONTAINER flag into multiple flags

CONTAINER split into
- CONTAINER (Chest/Minecart Chest)
- BARREL (Barrel)
- COMPOSTER (Composter)
- FLOWER_POT (Flower Pot)
- SHULKER_BOX (Shulker Box)
- TRAPPED_CHEST (Trapped Chest)

Fixes #1777

* Add subflag support

* Create container parent flag, chest subflag

* Remove extra string from when CHEST was CONTAINER

* Fix incorrect flag specified on fired event in IslandToggleClick

* Add missing world subflag event firing

* Remove extra import
  • Loading branch information
jstnf authored Jul 6, 2021
1 parent f88b8d4 commit 0f7866a
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 20 deletions.
50 changes: 50 additions & 0 deletions src/main/java/world/bentobox/bentobox/api/flags/Flag.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package world.bentobox.bentobox.api.flags;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
Expand Down Expand Up @@ -131,6 +132,7 @@ public boolean isGreaterThan(Mode rank) {
private final Addon addon;
private final int cooldown;
private final Mode mode;
private final Set<Flag> subflags;

private Flag(Builder builder) {
this.id = builder.id;
Expand All @@ -147,6 +149,7 @@ private Flag(Builder builder) {
this.cooldown = builder.cooldown;
this.addon = builder.addon;
this.mode = builder.mode;
this.subflags = builder.subflags;
}

public String getID() {
Expand Down Expand Up @@ -200,6 +203,18 @@ public void setSetting(World world, boolean setting) {
.getWorldSettings(world)
.getWorldFlags()
.put(getID(), setting);

// Subflag support
if (hasSubflags()) {
subflags.stream()
.filter(subflag -> subflag.getType().equals(Type.WORLD_SETTING) || subflag.getType().equals(Type.PROTECTION))
.forEach(subflag -> BentoBox.getInstance()
.getIWM()
.getWorldSettings(world)
.getWorldFlags()
.put(subflag.getID(), setting));
}

// Save config file
BentoBox.getInstance().getIWM().getAddon(world).ifPresent(GameModeAddon::saveWorldSettings);
}
Expand All @@ -208,6 +223,7 @@ public void setSetting(World world, boolean setting) {
/**
* Set the original status of this flag for locations outside of island spaces.
* May be overriden by the the setting for this world.
* Does not affect subflags.
* @param defaultSetting - true means it is allowed. false means it is not allowed
*/
public void setDefaultSetting(boolean defaultSetting) {
Expand All @@ -217,6 +233,7 @@ public void setDefaultSetting(boolean defaultSetting) {
/**
* Set the status of this flag for locations outside of island spaces for a specific world.
* World must exist and be registered before this method can be called.
* Does not affect subflags.
* @param defaultSetting - true means it is allowed. false means it is not allowed
*/
public void setDefaultSetting(World world, boolean defaultSetting) {
Expand Down Expand Up @@ -435,6 +452,22 @@ public Mode getMode() {
return mode;
}

/**
* @return whether the flag has subflags (and therefore is a parent flag)
* @since 1.17.0
*/
public boolean hasSubflags() {
return !subflags.isEmpty();
}

/**
* @return the subflags, an empty Set if none
* @since 1.17.0
*/
public Set<Flag> getSubflags() {
return subflags;
}

@Override
public String toString() {
return "Flag [id=" + id + "]";
Expand Down Expand Up @@ -480,6 +513,9 @@ public static class Builder {
// Mode
private Mode mode = Mode.EXPERT;

// Subflags
private Set<Flag> subflags;

/**
* Builder for making flags
* @param id - a unique id that MUST be the same as the enum of the flag
Expand All @@ -488,6 +524,7 @@ public static class Builder {
public Builder(String id, Material icon) {
this.id = id;
this.icon = icon;
this.subflags = new HashSet<>();
}

/**
Expand Down Expand Up @@ -595,6 +632,19 @@ public Builder mode(Mode mode) {
return this;
}

/**
* Add subflags and designate this flag as a parent flag.
* Subflags have their state simultaneously changed with the parent flag.
* Take extra care to ensure that subflags have the same number of possible values as the parent flag.
* @param flags all Flags that are subflags
* @return Builder - flag builder
* @since 1.17.0
*/
public Builder subflags(Flag... flags) {
this.subflags.addAll(Arrays.asList(flags));
return this;
}

/**
* Build the flag
* @return Flag
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ public boolean onClick(Panel panel, User user, ClickType click, int slot) {
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_OFF, 1F, 1F);
// Fire event
Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), flag, island.getFlag(flag)));

// Subflag support
if (flag.hasSubflags()) {
// Fire events for all subflags as well
flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), subflag, island.getFlag(subflag))));
}
} else if (click.equals(ClickType.RIGHT)) {
if (currentRank <= minRank) {
island.setFlag(flag, maxRank);
Expand All @@ -99,6 +105,12 @@ public boolean onClick(Panel panel, User user, ClickType click, int slot) {
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
// Fire event
Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), flag, island.getFlag(flag)));

// Subflag support
if (flag.hasSubflags()) {
// Fire events for all subflags as well
flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager().callEvent(new FlagProtectionChangeEvent(island, user.getUniqueId(), subflag, island.getFlag(subflag))));
}
} else if (click.equals(ClickType.SHIFT_LEFT) && user.isOp()) {
if (!plugin.getIWM().getHiddenFlags(user.getWorld()).contains(flag.getID())) {
plugin.getIWM().getHiddenFlags(user.getWorld()).add(flag.getID());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ public boolean onClick(Panel panel, User user, ClickType click, int slot) {
island.setCooldown(flag);
// Fire event
Bukkit.getPluginManager().callEvent(new FlagSettingChangeEvent(island, user.getUniqueId(), flag, island.isAllowed(flag)));

if (flag.hasSubflags()) {
// Fire events for all subflags as well
flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager().callEvent(new FlagSettingChangeEvent(island, user.getUniqueId(), subflag, island.isAllowed(subflag))));
}
}
});
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ public boolean onClick(Panel panel, User user, ClickType click, int slot) {
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F);
// Fire event
Bukkit.getPluginManager().callEvent(new FlagWorldSettingChangeEvent(user.getWorld(), user.getUniqueId(), flag, flag.isSetForWorld(user.getWorld())));

// Subflag support
if (flag.hasSubflags()) {
// Fire events for all subflags as well
flag.getSubflags().forEach(subflag -> Bukkit.getPluginManager().callEvent(new FlagWorldSettingChangeEvent(user.getWorld(), user.getUniqueId(), subflag, subflag.isSetForWorld(user.getWorld()))));
}
}

// Save world settings
Expand Down
50 changes: 47 additions & 3 deletions src/main/java/world/bentobox/bentobox/database/objects/Island.java
Original file line number Diff line number Diff line change
Expand Up @@ -824,11 +824,28 @@ public void setCreatedDate(long createdDate){

/**
* Set the Island Guard flag rank
* This method affects subflags (if the given flag is a parent flag)
* @param flag - flag
* @param value - Use RanksManager settings, e.g. RanksManager.MEMBER
*/
public void setFlag(Flag flag, int value){
public void setFlag(Flag flag, int value) {
setFlag(flag, value, true);
}

/**
* Set the Island Guard flag rank
* Also specify whether subflags are affected by this method call
* @param flag - flag
* @param value - Use RanksManager settings, e.g. RanksManager.MEMBER
* @param doSubflags - whether to set subflags
*/
public void setFlag(Flag flag, int value, boolean doSubflags) {
flags.put(flag, value);
// Subflag support
if (doSubflags && flag.hasSubflags()) {
// Ensure that a subflag isn't a subflag of itself or else we're in trouble!
flag.getSubflags().forEach(subflag -> setFlag(subflag, value, true));
}
setChanged();
}

Expand Down Expand Up @@ -1132,23 +1149,50 @@ public void showMembers(User user) {

/**
* Toggles a settings flag
* This method affects subflags (if the given flag is a parent flag)
* @param flag - flag
*/
public void toggleFlag(Flag flag) {
toggleFlag(flag, true);
}

/**
* Toggles a settings flag
* Also specify whether subflags are affected by this method call
* @param flag - flag
*/
public void toggleFlag(Flag flag, boolean doSubflags) {
boolean newToggleValue = !isAllowed(flag); // Use for subflags
if (flag.getType().equals(Flag.Type.SETTING) || flag.getType().equals(Flag.Type.WORLD_SETTING)) {
setSettingsFlag(flag, !isAllowed(flag));
setSettingsFlag(flag, newToggleValue, doSubflags);
}
setChanged();
}

/**
* Sets the state of a settings flag
* This method affects subflags (if the given flag is a parent flag)
* @param flag - flag
* @param state - true or false
*/
public void setSettingsFlag(Flag flag, boolean state) {
setSettingsFlag(flag, state, true);
}

/**
* Sets the state of a settings flag
* Also specify whether subflags are affected by this method call
* @param flag - flag
* @param state - true or false
*/
public void setSettingsFlag(Flag flag, boolean state, boolean doSubflags) {
int newState = state ? 1 : -1;
if (flag.getType().equals(Flag.Type.SETTING) || flag.getType().equals(Flag.Type.WORLD_SETTING)) {
flags.put(flag, state ? 1 : -1);
flags.put(flag, newState);
if (doSubflags && flag.hasSubflags()) {
// If we have circular subflags or a flag is a subflag of itself we are in trouble!
flag.getSubflags().forEach(subflag -> setSettingsFlag(subflag, state, true));
}
}
setChanged();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ else if (e.getItem().getType().name().endsWith("_SPAWN_EGG")) {
private void checkClickedBlock(Event e, Player player, Location loc, Material type) {
// Handle pots
if (type.name().startsWith("POTTED")) {
checkIsland(e, player, loc, Flags.CONTAINER);
checkIsland(e, player, loc, Flags.FLOWER_POT);
return;
}
if (Tag.ANVIL.isTagged(type)) {
Expand All @@ -115,7 +115,7 @@ private void checkClickedBlock(Event e, Player player, Location loc, Material ty
return;
}
if (Tag.SHULKER_BOXES.isTagged(type)) {
checkIsland(e, player, loc, Flags.CONTAINER);
checkIsland(e, player, loc, Flags.SHULKER_BOX);
return;
}
if (Tag.TRAPDOORS.isTagged(type)) {
Expand All @@ -136,12 +136,20 @@ private void checkClickedBlock(Event e, Player player, Location loc, Material ty
checkIsland(e, player, loc, Flags.HIVE);
break;
case BARREL:
checkIsland(e, player, loc, Flags.BARREL);
break;
case CHEST:
case CHEST_MINECART:
checkIsland(e, player, loc, Flags.CHEST);
break;
case TRAPPED_CHEST:
checkIsland(e, player, loc, Flags.TRAPPED_CHEST);
break;
case FLOWER_POT:
checkIsland(e, player, loc, Flags.FLOWER_POT);
break;
case COMPOSTER:
checkIsland(e, player, loc, Flags.CONTAINER);
checkIsland(e, player, loc, Flags.COMPOSTER);
break;
case DISPENSER:
checkIsland(e, player, loc, Flags.DISPENSER);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package world.bentobox.bentobox.listeners.flags.protection;

import org.bukkit.Material;
import org.bukkit.block.Barrel;
import org.bukkit.block.Beacon;
import org.bukkit.block.BrewingStand;
import org.bukkit.block.Chest;
import org.bukkit.block.Dispenser;
import org.bukkit.block.Dropper;
import org.bukkit.block.Furnace;
import org.bukkit.block.Hopper;
import org.bukkit.block.ShulkerBox;
import org.bukkit.entity.Animals;
import org.bukkit.entity.NPC;
import org.bukkit.entity.Player;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.inventory.InventoryClickEvent;
Expand Down Expand Up @@ -61,6 +66,29 @@ else if (inventoryHolder instanceof Beacon) {
else if (inventoryHolder instanceof NPC) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.TRADING);
}
else if (inventoryHolder instanceof Barrel) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.BARREL);
}
else if (inventoryHolder instanceof ShulkerBox) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.SHULKER_BOX);
}
else if (inventoryHolder instanceof Chest) {
// To differentiate between a Chest and a Trapped Chest we need to get the Block corresponding to the inventory
Chest chestInventoryHolder = (Chest) inventoryHolder;
try {
if (chestInventoryHolder.getBlock().getType() == Material.TRAPPED_CHEST) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.TRAPPED_CHEST);
} else {
checkIsland(e, player, e.getInventory().getLocation(), Flags.CHEST);
}
} catch (IllegalStateException ignored) {
// Thrown if the Chest corresponds to a block that isn't placed (how did we get here?)
checkIsland(e, player, e.getInventory().getLocation(), Flags.CHEST);
}
}
else if (inventoryHolder instanceof StorageMinecart) {
checkIsland(e, player, e.getInventory().getLocation(), Flags.CHEST);
}
else if (!(inventoryHolder instanceof Player)) {
// All other containers
checkIsland(e, player, e.getInventory().getLocation(), Flags.CONTAINER);
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/world/bentobox/bentobox/lists/Flags.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,14 @@ private Flags() {}
public static final Flag BEACON = new Flag.Builder("BEACON", Material.BEACON).build();
public static final Flag BED = new Flag.Builder("BED", Material.RED_BED).build();
public static final Flag BREWING = new Flag.Builder("BREWING", Material.BREWING_STAND).mode(Flag.Mode.ADVANCED).build();
public static final Flag CONTAINER = new Flag.Builder("CONTAINER", Material.CHEST).mode(Flag.Mode.BASIC).build();
// START CONTAINER split
public static final Flag CHEST = new Flag.Builder("CHEST", Material.CHEST).mode(Flag.Mode.ADVANCED).build();
public static final Flag BARREL = new Flag.Builder("BARREL", Material.BARREL).mode(Flag.Mode.ADVANCED).build();
public static final Flag COMPOSTER = new Flag.Builder("COMPOSTER", Material.COMPOSTER).mode(Flag.Mode.ADVANCED).build();
public static final Flag FLOWER_POT = new Flag.Builder("FLOWER_POT", Material.FLOWER_POT).mode(Flag.Mode.ADVANCED).build();
public static final Flag SHULKER_BOX = new Flag.Builder("SHULKER_BOX", Material.SHULKER_BOX).mode(Flag.Mode.ADVANCED).build();
public static final Flag TRAPPED_CHEST = new Flag.Builder("TRAPPED_CHEST", Material.TRAPPED_CHEST).mode(Flag.Mode.ADVANCED).build();
// END CONTAINER split
public static final Flag DISPENSER = new Flag.Builder("DISPENSER", Material.DISPENSER).mode(Flag.Mode.ADVANCED).build();
public static final Flag DROPPER = new Flag.Builder("DROPPER", Material.DROPPER).mode(Flag.Mode.ADVANCED).build();
public static final Flag HOPPER = new Flag.Builder("HOPPER", Material.HOPPER).mode(Flag.Mode.ADVANCED).build();
Expand All @@ -129,6 +136,9 @@ private Flags() {}
public static final Flag ITEM_FRAME = new Flag.Builder("ITEM_FRAME", Material.ITEM_FRAME).mode(Flag.Mode.ADVANCED).build();
public static final Flag CAKE = new Flag.Builder("CAKE", Material.CAKE).build();
public static final Flag HIVE = new Flag.Builder("HIVE", Material.HONEY_BOTTLE).type(Type.PROTECTION).build();
public static final Flag CONTAINER = new Flag.Builder("CONTAINER", Material.CHEST).mode(Flag.Mode.BASIC)
.subflags(BREWING, BARREL, CHEST, COMPOSTER, FLOWER_POT, SHULKER_BOX, TRAPPED_CHEST, FURNACE, JUKEBOX, DISPENSER, DROPPER, HOPPER, ITEM_FRAME, HIVE)
.build();

/**
* Prevents players from interacting with the Dragon Egg.
Expand Down
Loading

0 comments on commit 0f7866a

Please sign in to comment.