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;
|
||||
|
||||
import de.erethon.caliburn.item.ExItem;
|
||||
import de.erethon.caliburn.item.VanillaItem;
|
||||
import de.erethon.caliburn.mob.ExMob;
|
||||
import de.erethon.dungeonsxl.api.DungeonsAPI;
|
||||
import de.erethon.dungeonsxl.api.world.GameWorld;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* A functional interface to deserialize a raw value read from a configuration.
|
||||
@ -79,6 +84,28 @@ public interface ConfigReader<V> {
|
||||
}
|
||||
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.
|
||||
|
@ -14,7 +14,9 @@
|
||||
*/
|
||||
package de.erethon.dungeonsxl.api.dungeon;
|
||||
|
||||
import de.erethon.caliburn.CaliburnAPI;
|
||||
import de.erethon.caliburn.item.ExItem;
|
||||
import de.erethon.caliburn.item.VanillaItem;
|
||||
import de.erethon.caliburn.mob.ExMob;
|
||||
import de.erethon.commons.chat.MessageUtil;
|
||||
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.Requirement;
|
||||
import de.erethon.dungeonsxl.api.Reward;
|
||||
import de.erethon.dungeonsxl.api.world.GameWorld;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@ -33,7 +36,9 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.bukkit.Difficulty;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static final GameRule<Boolean> BREAK_BLOCKS = new GameRule<>(Boolean.class, "breakBlocks", false);
|
||||
/**
|
||||
* 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);
|
||||
public static final GameRule<BuildMode> BREAK_BLOCKS = new GameRule<>(BuildMode.class, "breakBlocks", BuildMode.FALSE, ConfigReader.BUILD_MODE_READER);
|
||||
/**
|
||||
* A blacklist of block types players cannot interact with.
|
||||
*/
|
||||
@ -125,11 +121,7 @@ public class GameRule<V> {
|
||||
/**
|
||||
* If blocks may be placed.
|
||||
*/
|
||||
public static final GameRule<Boolean> PLACE_BLOCKS = new GameRule<>(Boolean.class, "placeBlocks", false);
|
||||
/**
|
||||
* 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);
|
||||
public static final GameRule<BuildMode> PLACE_BLOCKS = new GameRule<>(BuildMode.class, "placeBlocks", BuildMode.FALSE, ConfigReader.BUILD_MODE_READER);
|
||||
/**
|
||||
* 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 java.util.Collection;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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.api.dungeon.Dungeon;
|
||||
import de.erethon.dungeonsxl.api.dungeon.Game;
|
||||
@ -58,7 +56,6 @@ import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@ -69,6 +66,7 @@ import org.bukkit.entity.Hanging;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import de.erethon.dungeonsxl.api.dungeon.BuildMode;
|
||||
|
||||
/**
|
||||
* @author Frank Baumann, Milan Albrecht, Daniel Saukel
|
||||
@ -202,6 +200,11 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
||||
return dSign;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Block> getPlacedBlocks() {
|
||||
return placedBlocks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the placeableBlocks
|
||||
*/
|
||||
@ -361,22 +364,21 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
||||
public int getMobCount() {
|
||||
int mobCount = 0;
|
||||
|
||||
signs:
|
||||
for (DungeonSign sign : getDungeonSigns().toArray(new DungeonSign[getDungeonSigns().size()])) {
|
||||
if (!(sign instanceof MobSign)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (de.erethon.dungeonsxl.api.Trigger trigger : sign.getTriggers()) {
|
||||
if (trigger instanceof ProgressTrigger) {
|
||||
if (((ProgressTrigger) trigger).getFloorCount() > getGame().getFloorCount()) {
|
||||
break signs;
|
||||
signs: for (DungeonSign sign : getDungeonSigns().toArray(new DungeonSign[getDungeonSigns().size()])) {
|
||||
if (!(sign instanceof MobSign)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mobCount += ((MobSign) sign).getInitialAmount();
|
||||
}
|
||||
for (de.erethon.dungeonsxl.api.Trigger trigger : sign.getTriggers()) {
|
||||
if (trigger instanceof ProgressTrigger) {
|
||||
if (((ProgressTrigger) trigger).getFloorCount() > getGame().getFloorCount()) {
|
||||
break signs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mobCount += ((MobSign) sign).getInitialAmount();
|
||||
}
|
||||
|
||||
return mobCount;
|
||||
}
|
||||
@ -529,7 +531,9 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -547,21 +551,7 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
||||
}
|
||||
}
|
||||
|
||||
Map<ExItem, HashSet<ExItem>> whitelist = getRules().getState(GameRule.BREAK_WHITELIST);
|
||||
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;
|
||||
return !mode.check(player, this, block);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -579,6 +569,10 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getRules().getState(GameRule.PLACE_BLOCKS).check(player, this, block)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PlaceableBlock placeableBlock = null;
|
||||
for (PlaceableBlock gamePlaceableBlock : placeableBlocks) {
|
||||
if (gamePlaceableBlock.canPlace(block, caliburn.getExItem(hand))) {
|
||||
@ -586,7 +580,7 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!getRules().getState(GameRule.PLACE_BLOCKS) && placeableBlock == null) {
|
||||
if (placeableBlock == null) {
|
||||
// Workaround for a bug that would allow 3-Block-high jumping
|
||||
Location loc = player.getLocation();
|
||||
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;
|
||||
}
|
||||
if (placeableBlock != null) {
|
||||
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 true;
|
||||
placeableBlock.onPlace();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user