Skip to content

Commit

Permalink
1.13 block setting system. Already supports torch auto-facing, beds c…
Browse files Browse the repository at this point in the history
…oming soon.
  • Loading branch information
bensku committed Sep 3, 2018
1 parent 0c2ee82 commit 3a97ac2
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ public interface BlockCompat {
static final BlockCompat INSTANCE = Skript.isRunningMinecraft(1, 13)
? new NewBlockCompat() : new MagicBlockCompat();

static final BlockSetter SETTER = INSTANCE.getSetter();

/**
* Gets block values from a block state. They can be compared to other
* values if needed, but cannot be used to retrieve any other data.
Expand Down Expand Up @@ -93,6 +95,13 @@ default BlockValues getBlockValues(FallingBlock entity) {
@Nullable
BlockValues createBlockValues(Material type, Map<String, String> states);

/**
* Gets block setter that understands block values produced by this
* compatibility layer.
* @return Block setter.
*/
BlockSetter getSetter();

/**
* Checks whether the given material implies emptiness. On Minecraft 1.13+,
* there are several blocks that do so.
Expand Down
69 changes: 69 additions & 0 deletions src/main/java/ch/njol/skript/bukkitutil/block/BlockSetter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* This file is part of Skript.
*
* Skript is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Skript 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Skript. If not, see <http://www.gnu.org/licenses/>.
*
*
* Copyright 2011-2017 Peter Güttinger and contributors
*/
package ch.njol.skript.bukkitutil.block;

import org.bukkit.Material;
import org.bukkit.block.Block;
import org.eclipse.jdt.annotation.Nullable;

/**
* Manages setting blocks.
*/
public interface BlockSetter {

/**
* Attempts to automatically correct rotation and direction of the block
* when setting it. Note that this will NOT overwrite any existing data
* supplied in block values.
*/
public static int ROTATE = 1;

/**
* Overrides rotation and direction that might have been specified in block
* values when {@link #ROTATE} is also set.
*/
public static int ROTATE_FORCE = 1 << 1;

/**
* Changes type of the block if that is needed to get the correct rotation.
*/
public static int ROTATE_FIX_TYPE = 1 << 2;

/**
* Takes rotation or direction of the block (depending on the block)
* and attempts to place other parts of it according to those. For example,
* placing beds and doors should be simple enough with this flag.
*/
public static int MULTIPART = 1 << 3;

/**
* When placing the block, apply physics.
*/
public static int APPLY_PHYSICS = 1 << 4;

/**
* Sets the given block.
* @param block Block to set.
* @param type New type of the block.
* @param values Additional block data, such as block states.
* @param flags Flags for block setter.
*/
void setBlock(Block block, Material type, @Nullable BlockValues values, int flags);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@
* Contains all data block has that is needed for comparisions.
*/
public abstract class BlockValues {

public abstract void setBlock(Block block, boolean applyPhysics);


@Override
public abstract boolean equals(@Nullable Object other);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ public MagicBlockValues(Material id, byte data) {
this.data = data;
}

@Override
public void setBlock(Block block, boolean applyPhysics) {
block.setType(id);
try {
Expand Down Expand Up @@ -313,5 +312,10 @@ public boolean isLiquid(Material type) {
public BlockValues getBlockValues(ItemStack stack) {
throw new UnsupportedOperationException("not yet implemented");
}

@Override
public BlockSetter getSetter() {
throw new UnsupportedOperationException("not yet implemented");
}

}
161 changes: 142 additions & 19 deletions src/main/java/ch/njol/skript/bukkitutil/block/NewBlockCompat.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,19 @@
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Rotatable;
import org.bukkit.entity.FallingBlock;
import org.bukkit.inventory.ItemStack;
import org.eclipse.jdt.annotation.Nullable;

import ch.njol.skript.Skript;
import ch.njol.skript.aliases.Aliases;
import ch.njol.skript.aliases.ItemType;
import ch.njol.util.Setter;

/**
* 1.13+ block compat.
Expand All @@ -39,19 +45,13 @@ public class NewBlockCompat implements BlockCompat {

private static class NewBlockValues extends BlockValues {

private Material type;
private BlockData data;
Material type;
BlockData data;

public NewBlockValues(Material type, BlockData data) {
this.type = type;
this.data = data;
}

@Override
public void setBlock(Block block, boolean applyPhysics) {
block.setType(type);
block.setBlockData(data, applyPhysics);
}

@Override
public boolean equals(@Nullable Object other) {
Expand All @@ -73,6 +73,124 @@ public int hashCode() {

}

private static class NewBlockSetter implements BlockSetter {

private ItemType floorTorch;
private ItemType wallTorch;

private ItemType specialTorchSides;
private ItemType specialTorchFloors;

private boolean typesLoaded = false;

/**
* Cached BlockFace values.
*/
private BlockFace[] faces = BlockFace.values();

@SuppressWarnings("null") // Late initialization with loadTypes() to avoid circular dependencies
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 applyPhysics = (flags | APPLY_PHYSICS) != 0;
NewBlockValues ourValues = null;
if (values != null)
ourValues = (NewBlockValues) values;

Class<?> dataType = type.data;

/**
* Set to true when block is placed. If no special logic places
* the block, generic placement will be done.
*/
boolean placed = false;
if (rotate) {
if (rotateFixType || floorTorch.isOfType(type)) {
// 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;
}
}

// 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());
Directional data = (Directional) block.getBlockData();
data.setFacing(face);
block.setBlockData(data, applyPhysics);
placed = true;
}
}
} else if (wallTorch.isOfType(type)) {
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)) {
// Attempt to figure out a better rotation
BlockFace face = findWallTorchSide(block);
if (face != null) { // Found better torch spot
block.setType(type);
data.setFacing(face);
block.setBlockData(data, applyPhysics);
placed = true;
}
}
}
}

// Generic block placement
if (!placed) {
block.setType(type);
if (ourValues != null)
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;
}

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

return null; // Can't place torch here legally
}

}

private NewBlockSetter setter = new NewBlockSetter();

@SuppressWarnings("null")
@Nullable
@Override
Expand All @@ -82,6 +200,22 @@ public BlockValues getBlockValues(BlockState block) {
return new NewBlockValues(block.getType(), block.getBlockData());
return null;
}

@Override
@Nullable
public BlockValues getBlockValues(ItemStack stack) {
Material type = stack.getType();
if (BlockData.class.isAssignableFrom(type.data)) { // Block has data
// Create default block data for the type
return new NewBlockValues(type, Bukkit.createBlockData(type));
}
return null;
}

@Override
public BlockSetter getSetter() {
return setter;
}

@Override
public BlockState fallingBlockToState(FallingBlock entity) {
Expand Down Expand Up @@ -127,16 +261,5 @@ public boolean isEmpty(Material type) {
public boolean isLiquid(Material type) {
return type == Material.WATER || type == Material.LAVA;
}

@Override
@Nullable
public BlockValues getBlockValues(ItemStack stack) {
Material type = stack.getType();
if (BlockData.class.isAssignableFrom(type.data)) { // Block has data
// Create default block data for the type
return new NewBlockValues(type, Bukkit.createBlockData(type));
}
return null;
}

}
26 changes: 14 additions & 12 deletions src/main/java/ch/njol/skript/util/BlockUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

import ch.njol.skript.Skript;
import ch.njol.skript.aliases.ItemData;
import ch.njol.skript.bukkitutil.block.BlockCompat;
import ch.njol.skript.bukkitutil.block.BlockSetter;
import ch.njol.skript.bukkitutil.block.BlockValues;
import ch.njol.util.coll.CollectionUtils;

Expand All @@ -51,13 +53,12 @@ public abstract class BlockUtils {
};

public static boolean set(Block block, ItemData type, boolean applyPhysics) {
BlockValues values = type.getBlockValues();
if (values != null)
values.setBlock(block, applyPhysics);
else
block.setType(type.getType(), applyPhysics);
int flags = BlockSetter.ROTATE | BlockSetter.ROTATE_FIX_TYPE | BlockSetter.MULTIPART;
if (applyPhysics)
flags |= BlockSetter.APPLY_PHYSICS;
BlockCompat.SETTER.setBlock(block, type.getType(), type.getBlockValues(), flags);


// TODO advanced features
return true;
}

Expand All @@ -80,12 +81,13 @@ public static Location getLocation(final @Nullable Block b) {
if (b == null)
return null;
final Location l = b.getLocation().add(0.5, 0.5, 0.5);
final Material m = b.getType();
if (Directional.class.isAssignableFrom(m.getData())) {
final BlockFace f = ((Directional) m.getNewData(b.getData())).getFacing();
l.setPitch(Direction.getPitch(Math.sin(f.getModY())));
l.setYaw(Direction.getYaw(Math.atan2(f.getModZ(), f.getModX())));
}
// final Material m = b.getType();
// if (Directional.class.isAssignableFrom(m.getData())) {
// final BlockFace f = ((Directional) m.getNewData(b.getData())).getFacing();
// l.setPitch(Direction.getPitch(Math.sin(f.getModY())));
// l.setYaw(Direction.getYaw(Math.atan2(f.getModZ(), f.getModX())));
// }
// TODO figure out what this code means
return l;
}

Expand Down

0 comments on commit 3a97ac2

Please sign in to comment.