mirror of
https://github.com/DRE2N/DungeonsXL.git
synced 2024-11-28 05:26:29 +01:00
Rewrite break / place game rules; resolves #1041
This commit is contained in:
parent
16f138aadd
commit
2c7ae708ec
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2021 Daniel Saukel
|
||||||
|
*
|
||||||
|
* This library is free software: you can redistribute it and/or modify it under the
|
||||||
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||||
|
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package de.erethon.dungeonsxl.api.dungeon;
|
||||||
|
|
||||||
|
import de.erethon.dungeonsxl.api.world.GameWorld;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for whether a block may be broken.
|
||||||
|
*
|
||||||
|
* @author Daniel Saukel
|
||||||
|
*/
|
||||||
|
public interface BuildMode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the pre-set breaking rules.
|
||||||
|
*/
|
||||||
|
static class Registry {
|
||||||
|
/**
|
||||||
|
* Entry keys must be lowercase.
|
||||||
|
*/
|
||||||
|
public static final Map<String, BuildMode> ENTRIES = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
ENTRIES.put("true", TRUE);
|
||||||
|
ENTRIES.put("false", FALSE);
|
||||||
|
ENTRIES.put("placed", PLACED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All blocks except for protected ones may be broken.
|
||||||
|
*/
|
||||||
|
static final BuildMode TRUE = (Player player, GameWorld gameWorld, Block block) -> true;
|
||||||
|
/**
|
||||||
|
* Blocks may not be broken.
|
||||||
|
*/
|
||||||
|
static final BuildMode FALSE = (Player player, GameWorld gameWorld, Block block) -> false;
|
||||||
|
/**
|
||||||
|
* Blocks placed by players may be broken.
|
||||||
|
*/
|
||||||
|
static final BuildMode PLACED = (Player player, GameWorld gameWorld, Block block) -> gameWorld.getPlacedBlocks().contains(block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the block can be broken or placed by the player.
|
||||||
|
* <p>
|
||||||
|
* The plugin protects dungeon signs before checking this.
|
||||||
|
*
|
||||||
|
* @param player the player who breaks or places the block
|
||||||
|
* @param gameWorld the world the block is in
|
||||||
|
* @param block the block
|
||||||
|
* @return if the block can be broken or placed by the player
|
||||||
|
*/
|
||||||
|
boolean check(Player player, GameWorld gameWorld, Block block);
|
||||||
|
|
||||||
|
}
|
@ -15,14 +15,19 @@
|
|||||||
package de.erethon.dungeonsxl.api.dungeon;
|
package de.erethon.dungeonsxl.api.dungeon;
|
||||||
|
|
||||||
import de.erethon.caliburn.item.ExItem;
|
import de.erethon.caliburn.item.ExItem;
|
||||||
|
import de.erethon.caliburn.item.VanillaItem;
|
||||||
import de.erethon.caliburn.mob.ExMob;
|
import de.erethon.caliburn.mob.ExMob;
|
||||||
import de.erethon.dungeonsxl.api.DungeonsAPI;
|
import de.erethon.dungeonsxl.api.DungeonsAPI;
|
||||||
|
import de.erethon.dungeonsxl.api.world.GameWorld;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A functional interface to deserialize a raw value read from a configuration.
|
* A functional interface to deserialize a raw value read from a configuration.
|
||||||
@ -79,6 +84,28 @@ public interface ConfigReader<V> {
|
|||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
};
|
};
|
||||||
|
static final ConfigReader<BuildMode> BUILD_MODE_READER = (api, value) -> {
|
||||||
|
if (value instanceof Boolean) {
|
||||||
|
return (Boolean) value ? BuildMode.TRUE : BuildMode.FALSE;
|
||||||
|
} else if (value instanceof String) {
|
||||||
|
return BuildMode.Registry.ENTRIES.get(((String) value).toLowerCase());
|
||||||
|
} else if (value instanceof List) {
|
||||||
|
return (Player p, GameWorld w, Block b) -> ((List) value).contains(VanillaItem.get(b.getType()).getId());
|
||||||
|
} else {
|
||||||
|
Map<ExItem, HashSet<ExItem>> whitelist = TOOL_BLOCK_MAP_READER.read(api, value);
|
||||||
|
if (whitelist == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (Player p, GameWorld w, Block b) -> {
|
||||||
|
ExItem type = VanillaItem.get(b.getType());
|
||||||
|
ExItem breakTool = api.getCaliburn().getExItem(p.getItemInHand());
|
||||||
|
return whitelist.containsKey(type)
|
||||||
|
&& (whitelist.get(type) == null
|
||||||
|
|| whitelist.get(type).isEmpty()
|
||||||
|
|| whitelist.get(type).contains(breakTool));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a game rule state from the configuration.
|
* Reads a game rule state from the configuration.
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
*/
|
*/
|
||||||
package de.erethon.dungeonsxl.api.dungeon;
|
package de.erethon.dungeonsxl.api.dungeon;
|
||||||
|
|
||||||
|
import de.erethon.caliburn.CaliburnAPI;
|
||||||
import de.erethon.caliburn.item.ExItem;
|
import de.erethon.caliburn.item.ExItem;
|
||||||
|
import de.erethon.caliburn.item.VanillaItem;
|
||||||
import de.erethon.caliburn.mob.ExMob;
|
import de.erethon.caliburn.mob.ExMob;
|
||||||
import de.erethon.commons.chat.MessageUtil;
|
import de.erethon.commons.chat.MessageUtil;
|
||||||
import de.erethon.commons.misc.EnumUtil;
|
import de.erethon.commons.misc.EnumUtil;
|
||||||
@ -22,6 +24,7 @@ import de.erethon.commons.misc.NumberUtil;
|
|||||||
import de.erethon.dungeonsxl.api.DungeonsAPI;
|
import de.erethon.dungeonsxl.api.DungeonsAPI;
|
||||||
import de.erethon.dungeonsxl.api.Requirement;
|
import de.erethon.dungeonsxl.api.Requirement;
|
||||||
import de.erethon.dungeonsxl.api.Reward;
|
import de.erethon.dungeonsxl.api.Reward;
|
||||||
|
import de.erethon.dungeonsxl.api.world.GameWorld;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
@ -33,7 +36,9 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.bukkit.Difficulty;
|
import org.bukkit.Difficulty;
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a game rule for a {@link Game}.
|
* Represents a game rule for a {@link Game}.
|
||||||
@ -99,16 +104,7 @@ public class GameRule<V> {
|
|||||||
/**
|
/**
|
||||||
* If players can build and destroy blocks in this world.
|
* If players can build and destroy blocks in this world.
|
||||||
*/
|
*/
|
||||||
public static final GameRule<Boolean> BREAK_BLOCKS = new GameRule<>(Boolean.class, "breakBlocks", false);
|
public static final GameRule<BuildMode> BREAK_BLOCKS = new GameRule<>(BuildMode.class, "breakBlocks", BuildMode.FALSE, ConfigReader.BUILD_MODE_READER);
|
||||||
/**
|
|
||||||
* If players may destroy blocks they placed themselves.
|
|
||||||
*/
|
|
||||||
public static final GameRule<Boolean> BREAK_PLACED_BLOCKS = new GameRule<>(Boolean.class, "breakPlacedBlocks", false);
|
|
||||||
/**
|
|
||||||
* A whitelist of breakable blocks. breakBlocks is supposed to be set to "true" if this should be used.
|
|
||||||
*/
|
|
||||||
public static final GameRule<Map<ExItem, HashSet<ExItem>>> BREAK_WHITELIST
|
|
||||||
= new MapGameRule<>("breakWhitelist", new HashMap<>(), ConfigReader.TOOL_BLOCK_MAP_READER, HashMap::new);
|
|
||||||
/**
|
/**
|
||||||
* A blacklist of block types players cannot interact with.
|
* A blacklist of block types players cannot interact with.
|
||||||
*/
|
*/
|
||||||
@ -125,11 +121,7 @@ public class GameRule<V> {
|
|||||||
/**
|
/**
|
||||||
* If blocks may be placed.
|
* If blocks may be placed.
|
||||||
*/
|
*/
|
||||||
public static final GameRule<Boolean> PLACE_BLOCKS = new GameRule<>(Boolean.class, "placeBlocks", false);
|
public static final GameRule<BuildMode> PLACE_BLOCKS = new GameRule<>(BuildMode.class, "placeBlocks", BuildMode.FALSE, ConfigReader.BUILD_MODE_READER);
|
||||||
/**
|
|
||||||
* A whitelist of placeable blocks. placeBlocks is supposed to be set to "true" if this should be used.
|
|
||||||
*/
|
|
||||||
public static final GameRule<Set<ExItem>> PLACE_WHITELIST = new CollectionGameRule<>("placeWhitelist", new HashSet<>(), ConfigReader.EX_ITEM_SET_READER, HashSet::new);
|
|
||||||
/**
|
/**
|
||||||
* A set of blocks that do not fade.
|
* A set of blocks that do not fade.
|
||||||
*
|
*
|
||||||
|
@ -20,6 +20,7 @@ import de.erethon.dungeonsxl.api.mob.DungeonMob;
|
|||||||
import de.erethon.dungeonsxl.api.player.PlayerGroup;
|
import de.erethon.dungeonsxl.api.player.PlayerGroup;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A playable resource instance. There may be any amount of GameWorlds per {@link ResourceWorld}.
|
* A playable resource instance. There may be any amount of GameWorlds per {@link ResourceWorld}.
|
||||||
@ -118,4 +119,11 @@ public interface GameWorld extends InstanceWorld {
|
|||||||
*/
|
*/
|
||||||
void setClassesEnabled(boolean enabled);
|
void setClassesEnabled(boolean enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of the blocks that have been placed by players in the current game.
|
||||||
|
*
|
||||||
|
* @return a collection of the blocks that have been placed by players in the current game
|
||||||
|
*/
|
||||||
|
Collection<Block> getPlacedBlocks();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,6 @@
|
|||||||
package de.erethon.dungeonsxl.world;
|
package de.erethon.dungeonsxl.world;
|
||||||
|
|
||||||
import de.erethon.caliburn.CaliburnAPI;
|
import de.erethon.caliburn.CaliburnAPI;
|
||||||
import de.erethon.caliburn.item.ExItem;
|
|
||||||
import de.erethon.caliburn.item.VanillaItem;
|
|
||||||
import de.erethon.dungeonsxl.DungeonsXL;
|
import de.erethon.dungeonsxl.DungeonsXL;
|
||||||
import de.erethon.dungeonsxl.api.dungeon.Dungeon;
|
import de.erethon.dungeonsxl.api.dungeon.Dungeon;
|
||||||
import de.erethon.dungeonsxl.api.dungeon.Game;
|
import de.erethon.dungeonsxl.api.dungeon.Game;
|
||||||
@ -58,7 +56,6 @@ import java.util.Collection;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@ -69,6 +66,7 @@ import org.bukkit.entity.Hanging;
|
|||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import de.erethon.dungeonsxl.api.dungeon.BuildMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Frank Baumann, Milan Albrecht, Daniel Saukel
|
* @author Frank Baumann, Milan Albrecht, Daniel Saukel
|
||||||
@ -202,6 +200,11 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
|||||||
return dSign;
|
return dSign;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Block> getPlacedBlocks() {
|
||||||
|
return placedBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the placeableBlocks
|
* @return the placeableBlocks
|
||||||
*/
|
*/
|
||||||
@ -361,8 +364,7 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
|||||||
public int getMobCount() {
|
public int getMobCount() {
|
||||||
int mobCount = 0;
|
int mobCount = 0;
|
||||||
|
|
||||||
signs:
|
signs: for (DungeonSign sign : getDungeonSigns().toArray(new DungeonSign[getDungeonSigns().size()])) {
|
||||||
for (DungeonSign sign : getDungeonSigns().toArray(new DungeonSign[getDungeonSigns().size()])) {
|
|
||||||
if (!(sign instanceof MobSign)) {
|
if (!(sign instanceof MobSign)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -529,7 +531,9 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!getRules().getState(GameRule.BREAK_BLOCKS) && !getRules().getState(GameRule.BREAK_PLACED_BLOCKS)) {
|
BuildMode mode = getRules().getState(GameRule.BREAK_BLOCKS);
|
||||||
|
|
||||||
|
if (mode == BuildMode.FALSE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,21 +551,7 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<ExItem, HashSet<ExItem>> whitelist = getRules().getState(GameRule.BREAK_WHITELIST);
|
return !mode.check(player, this, block);
|
||||||
ExItem material = VanillaItem.get(block.getType());
|
|
||||||
ExItem breakTool = caliburn.getExItem(player.getItemInHand());
|
|
||||||
|
|
||||||
if (getRules().getState(GameRule.BREAK_PLACED_BLOCKS) && placedBlocks.contains(block)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (whitelist != null && whitelist.containsKey(material)
|
|
||||||
&& (whitelist.get(material) == null
|
|
||||||
|| whitelist.get(material).isEmpty()
|
|
||||||
|| whitelist.get(material).contains(breakTool))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -579,6 +569,10 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (getRules().getState(GameRule.PLACE_BLOCKS).check(player, this, block)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
PlaceableBlock placeableBlock = null;
|
PlaceableBlock placeableBlock = null;
|
||||||
for (PlaceableBlock gamePlaceableBlock : placeableBlocks) {
|
for (PlaceableBlock gamePlaceableBlock : placeableBlocks) {
|
||||||
if (gamePlaceableBlock.canPlace(block, caliburn.getExItem(hand))) {
|
if (gamePlaceableBlock.canPlace(block, caliburn.getExItem(hand))) {
|
||||||
@ -586,7 +580,7 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!getRules().getState(GameRule.PLACE_BLOCKS) && placeableBlock == null) {
|
if (placeableBlock == null) {
|
||||||
// Workaround for a bug that would allow 3-Block-high jumping
|
// Workaround for a bug that would allow 3-Block-high jumping
|
||||||
Location loc = player.getLocation();
|
Location loc = player.getLocation();
|
||||||
if (loc.getY() > block.getY() + 1.0 && loc.getY() <= block.getY() + 1.5) {
|
if (loc.getY() > block.getY() + 1.0 && loc.getY() <= block.getY() + 1.5) {
|
||||||
@ -599,20 +593,10 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (placeableBlock != null) {
|
|
||||||
placeableBlock.onPlace();
|
placeableBlock.onPlace();
|
||||||
}
|
|
||||||
|
|
||||||
Set<ExItem> whitelist = getRules().getState(GameRule.PLACE_WHITELIST);
|
|
||||||
if (whitelist.isEmpty() || whitelist.contains(VanillaItem.get(block.getType()))) {
|
|
||||||
placedBlocks.add(block);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user