Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exposes 'load default aliases' config option and removes hardcoded alias dependencies #6834

Merged
merged 8 commits into from
Jul 1, 2024
11 changes: 10 additions & 1 deletion src/main/java/ch/njol/skript/aliases/Aliases.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import ch.njol.skript.config.Node;
import ch.njol.skript.config.SectionNode;
import ch.njol.skript.entity.EntityData;
import org.bukkit.entity.EntityType;
import org.skriptlang.skript.lang.script.Script;
import ch.njol.skript.lang.parser.ParserInstance;
import ch.njol.skript.localization.ArgsMessage;
Expand Down Expand Up @@ -431,7 +432,6 @@ private static void loadInternal() throws IOException {
Path aliasesPath = zipFs.getPath("/", "aliases-english");
assert aliasesPath != null;
loadDirectory(aliasesPath);
loadMissingAliases();
}
} catch (URISyntaxException e) {
assert false;
Expand All @@ -445,6 +445,9 @@ private static void loadInternal() throws IOException {
assert aliasesFolder != null;
loadDirectory(aliasesFolder);
}

// generate aliases from item names for any missing items
loadMissingAliases();

// Update tracked item types
for (Map.Entry<String, ItemType> entry : trackedTypes.entrySet()) {
Expand Down Expand Up @@ -554,10 +557,16 @@ public static EntityData<?> getRelatedEntity(ItemData data) {
* <p>Item types provided by this method are updated when aliases are
* reloaded. However, this also means they are tracked by aliases system
* and NOT necessarily garbage-collected.
*
* <p>Relying on this method to create item types is not safe,
* as users can change aliases at any point. ItemTypes should instead be created
* via {@link Material}s, {@link org.bukkit.Tag}s, or any other manual method.
*
* @param name Name of item to search from aliases.
* @return An item.
* @throws IllegalArgumentException When item is not found.
*/
@Deprecated(forRemoval = true, since = "2.9.0")
sovdeeth marked this conversation as resolved.
Show resolved Hide resolved
public static ItemType javaItemType(String name) {
ItemType type = parseItemType(name);
if (type == null) {
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/ch/njol/skript/aliases/ItemType.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Skull;
Expand Down Expand Up @@ -172,6 +173,18 @@ public ItemType(Material id) {
add_(new ItemData(id));
}

public ItemType(Material... ids) {
for (Material id : ids) {
add_(new ItemData(id));
}
}

public ItemType(Tag<Material> tag) {
for (Material id : tag.getValues()) {
add_(new ItemData(id));
}
}

public ItemType(Material id, String tags) {
add_(new ItemData(id, tags));
}
Expand Down
59 changes: 58 additions & 1 deletion src/main/java/ch/njol/skript/bukkitutil/ItemUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@
import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemType;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.TreeType;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Fence;
import org.bukkit.block.data.type.Gate;
import org.bukkit.block.data.type.Wall;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
Expand Down Expand Up @@ -219,5 +225,56 @@ public static boolean isAir(Material type) {
public static Material getTreeSapling(TreeType treeType) {
return TREE_TO_SAPLING_MAP.get(treeType);
}



private static final boolean HAS_FENCE_TAGS = !Skript.isRunningMinecraft(1, 14);

/**
* Whether the block is a fence or a wall.
* @param block the block to check.
* @return whether the block is a fence/wall.
*/
public static boolean isFence(Block block) {
// TODO: 1.13 only, so remove in 2.10
if (!HAS_FENCE_TAGS) {
BlockData data = block.getBlockData();
return data instanceof Fence
|| data instanceof Wall
|| data instanceof Gate;
}

Material type = block.getType();
return Tag.FENCES.isTagged(type)
|| Tag.FENCE_GATES.isTagged(type)
|| Tag.WALLS.isTagged(type);
}

/**
* @param material The material to check
* @return whether the material is a full glass block
*/
public static boolean isGlass(Material material) {
switch (material) {
case GLASS:
case RED_STAINED_GLASS:
case ORANGE_STAINED_GLASS:
case YELLOW_STAINED_GLASS:
case LIGHT_BLUE_STAINED_GLASS:
case BLUE_STAINED_GLASS:
case CYAN_STAINED_GLASS:
case LIME_STAINED_GLASS:
case GREEN_STAINED_GLASS:
case MAGENTA_STAINED_GLASS:
case PURPLE_STAINED_GLASS:
case PINK_STAINED_GLASS:
case WHITE_STAINED_GLASS:
case LIGHT_GRAY_STAINED_GLASS:
case GRAY_STAINED_GLASS:
case BLACK_STAINED_GLASS:
case BROWN_STAINED_GLASS:
return true;
default:
return false;
}
}
}
90 changes: 50 additions & 40 deletions src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import ch.njol.skript.aliases.Aliases;
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.aliases.MatchQuality;
import ch.njol.skript.bukkitutil.ItemUtils;
import ch.njol.skript.variables.Variables;
import ch.njol.yggdrasil.Fields;
import org.bukkit.Bukkit;
Expand All @@ -31,10 +32,12 @@
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.BlockSupport;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.type.Bed;
import org.bukkit.block.data.type.Snow;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
Expand Down Expand Up @@ -141,15 +144,6 @@ public void deserialize(@NonNull Fields fields) throws StreamCorruptedException
}

private static class NewBlockSetter implements BlockSetter {

private ItemType floorTorch;
private ItemType wallTorch;

private ItemType specialTorchSides;
private ItemType specialTorchFloors;

private boolean typesLoaded = false;

private static final BlockFace[] CARDINAL_FACES =
new BlockFace[] {BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST};

Expand All @@ -158,14 +152,11 @@ public NewBlockSetter() {}

@Override
public void setBlock(Block block, Material type, @Nullable BlockValues values, int flags) {
if (!typesLoaded)
loadTypes();

boolean rotate = (flags | ROTATE) != 0;
boolean rotateForce = (flags | ROTATE_FORCE) != 0;
boolean rotateFixType = (flags | ROTATE_FIX_TYPE) != 0;
boolean multipart = (flags | MULTIPART) != 0;
boolean applyPhysics = (flags | APPLY_PHYSICS) != 0;
boolean rotate = (flags & ROTATE) != 0;
boolean rotateForce = (flags & ROTATE_FORCE) != 0;
boolean rotateFixType = (flags & ROTATE_FIX_TYPE) != 0;
boolean multipart = (flags & MULTIPART) != 0;
boolean applyPhysics = (flags & APPLY_PHYSICS) != 0;
NewBlockValues ourValues = null;
if (values != null)
ourValues = (NewBlockValues) values;
Expand All @@ -178,39 +169,31 @@ public void setBlock(Block block, Material type, @Nullable BlockValues values, i
*/
boolean placed = false;
if (rotate) {
if (floorTorch.isOfType(type) || (rotateFixType && wallTorch.isOfType(type))) {
if (type == Material.TORCH || (rotateFixType && type == Material.WALL_TORCH)) {
// If floor torch cannot be placed, try a wall torch
Block under = block.getRelative(0, -1, 0);
boolean canPlace = true;
if (!under.getType().isOccluding()) { // Usually cannot be placed, but there are exceptions
// TODO check for stairs and slabs, currently complicated since there is no 'any' alias
if (specialTorchFloors.isOfType(under)) {
canPlace = true;
} else {
canPlace = false;
}
}
boolean canPlace = canSupportFloorTorch(under);

// Can't really place a floor torch, try wall one instead
if (!canPlace) {
BlockFace face = findWallTorchSide(block);
if (face != null) { // Found better torch spot
block.setType(wallTorch.getMaterial());
block.setType(Material.WALL_TORCH);
Directional data = (Directional) block.getBlockData();
data.setFacing(face);
block.setBlockData(data, applyPhysics);
placed = true;
}
}
} else if (wallTorch.isOfType(type)) {
} else if (type == Material.WALL_TORCH) {
Directional data;
if (ourValues != null)
data = (Directional) ourValues.data;
else
data = (Directional) Bukkit.createBlockData(type);

Block relative = block.getRelative(data.getFacing());
if ((!relative.getType().isOccluding() && !specialTorchSides.isOfType(relative)) || rotateForce) {
if ((!canSupportWallTorch(relative, data.getFacing().getOppositeFace())) || rotateForce) {
// Attempt to figure out a better rotation
BlockFace face = findWallTorchSide(block);
if (face != null) { // Found better torch spot
Expand Down Expand Up @@ -294,22 +277,49 @@ public void setBlock(Block block, Material type, @Nullable BlockValues values, i
block.setBlockData(ourValues.data, applyPhysics);
}
}

private void loadTypes() {
floorTorch = Aliases.javaItemType("floor torch");
wallTorch = Aliases.javaItemType("wall torch");

specialTorchSides = Aliases.javaItemType("special torch sides");
specialTorchFloors = Aliases.javaItemType("special torch floors");

typesLoaded = true;

// 1.19+
// TODO: remove in 2.10
private static final boolean HAS_BLOCK_SUPPORT = Skript.classExists("org.bukkit.block.BlockSupport");

/**
* Returns whether this block can support a floor torch.
* @param block The block the torch will be placed on
* @return whether the block can support the torch.
*/
private static boolean canSupportFloorTorch(Block block) {
if (HAS_BLOCK_SUPPORT)
return block.getBlockData().isFaceSturdy(BlockFace.UP, BlockSupport.CENTER);

Material material = block.getType();
return (material.isOccluding()
|| canSupportWallTorch(block, null)
|| ItemUtils.isFence(block)
|| ItemUtils.isGlass(material)
|| material == Material.HOPPER
|| (material == Material.SNOW && (((Snow) block.getBlockData()).getLayers() == 8))
);
}

/**
* Returns whether this block can support a wall torch. In 1.19+, a face can be specified.
* @param block The block the torch will be placed on
* @param face The face the torch will be placed on (only considered in 1.19+)
* @return whether the block face can support the torch.
*/
private static boolean canSupportWallTorch(Block block, @Nullable BlockFace face) {
if (HAS_BLOCK_SUPPORT && face != null)
return block.getBlockData().isFaceSturdy(face, BlockSupport.FULL);

Material material = block.getType();
return material.isOccluding() || material == Material.SOUL_SAND || material == Material.SPAWNER;
}

@Nullable
private BlockFace findWallTorchSide(Block block) {
for (BlockFace face : CARDINAL_FACES) {
Block relative = block.getRelative(face);
if (relative.getType().isOccluding() || specialTorchSides.isOfType(relative))
if (relative.getType().isOccluding() || canSupportWallTorch(relative, face.getOppositeFace()))
return face.getOppositeFace(); // Torch can be rotated towards from this face
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,12 +390,11 @@ public Block get(final BlockBreakEvent e) {
return new DelayedChangeBlock(e.getBlock());
}
}, 0);
ItemType stationaryWater = Aliases.javaItemType("stationary water");
EventValues.registerEventValue(BlockBreakEvent.class, Block.class, new Getter<Block, BlockBreakEvent>() {
@Override
public Block get(final BlockBreakEvent e) {
final BlockState s = e.getBlock().getState();
s.setType(s.getType() == Material.ICE ? stationaryWater.getMaterial() : Material.AIR);
s.setType(s.getType() == Material.ICE ? Material.WATER : Material.AIR);
s.setRawData((byte) 0);
return new BlockStateBlock(s, true);
}
Expand Down Expand Up @@ -758,12 +757,11 @@ public Block get(final PlayerBucketEmptyEvent e) {
return e.getBlockClicked().getRelative(e.getBlockFace());
}
}, -1);
ItemType stationaryLava = Aliases.javaItemType("stationary lava");
EventValues.registerEventValue(PlayerBucketEmptyEvent.class, Block.class, new Getter<Block, PlayerBucketEmptyEvent>() {
@Override
public Block get(final PlayerBucketEmptyEvent e) {
final BlockState s = e.getBlockClicked().getRelative(e.getBlockFace()).getState();
s.setType(e.getBucket() == Material.WATER_BUCKET ? stationaryWater.getMaterial() : stationaryLava.getMaterial());
s.setType(e.getBucket() == Material.WATER_BUCKET ? Material.WATER : Material.LAVA);
s.setRawData((byte) 0);
return new BlockStateBlock(s, true);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,15 +495,14 @@ public boolean supportsOrdering() {
});

// DamageCause - ItemType
ItemType lava = Aliases.javaItemType("lava");
Comparators.registerComparator(DamageCause.class, ItemType.class, new Comparator<DamageCause, ItemType>() {
@Override
public Relation compare(DamageCause dc, ItemType t) {
switch (dc) {
case FIRE:
return Relation.get(t.isOfType(Material.FIRE));
case LAVA:
return Relation.get(t.equals(lava));
return Relation.get(t.getMaterial() == Material.LAVA);
case MAGIC:
return Relation.get(t.isOfType(Material.POTION));
case HOT_FLOOR:
Expand Down
Loading