add crop funtions + legacy block translation

This commit is contained in:
jascotty2 2019-09-11 16:58:55 -05:00
parent 8c4cbbd201
commit ee36d95cb4
4 changed files with 359 additions and 25 deletions

View File

@ -31,7 +31,7 @@ public enum CompatibleMaterial {
*/
ACACIA_BOAT("BOAT_ACACIA"),
ACACIA_BUTTON(),
ACACIA_DOOR("ACACIA_DOOR_ITEM"), // TODO: ACACIA_DOOR & WOODEN_DOOR are the legacy block variants
ACACIA_DOOR("ACACIA_DOOR_ITEM"),
ACACIA_FENCE(),
ACACIA_FENCE_GATE(),
ACACIA_LEAVES("LEAVES_2", (byte) 0),
@ -133,7 +133,7 @@ public enum CompatibleMaterial {
BRAIN_CORAL_FAN,
BRAIN_CORAL_WALL_FAN,
BREAD,
BREWING_STAND,
BREWING_STAND("BREWING_STAND_ITEM"),
/**
* minecraft:brick (item)
*/
@ -175,7 +175,7 @@ public enum CompatibleMaterial {
CARTOGRAPHY_TABLE,
CARVED_PUMPKIN("JACK_O_LANTERN"),
CAT_SPAWN_EGG(),
CAULDRON,
CAULDRON("CAULDRON_ITEM"),
CAVE_AIR(),
CAVE_SPIDER_SPAWN_EGG("MONSTER_EGG", (byte) 59),
CHAINMAIL_BOOTS,
@ -462,7 +462,7 @@ public enum CompatibleMaterial {
IRON_BLOCK,
IRON_BOOTS,
IRON_CHESTPLATE,
IRON_DOOR, // TODO: legacy block id is IRON_DOOR_BLOCK
IRON_DOOR,
IRON_HELMET,
IRON_HOE,
IRON_HORSE_ARMOR("IRON_BARDING"),
@ -1009,6 +1009,7 @@ public enum CompatibleMaterial {
private final String modern, modern2, legacy;
private final LegacyMaterialAnalouge compatibleMaterial;
private final LegacyMaterialBlockType legacyBlockMaterial;
private final boolean legacyRequiresData;
// some materials (I'm looking at you, GREEN_DYE) have changed ID more than once
// minVersion is the min for modern, and minVersion2 is min to use legacyCompat1
@ -1029,9 +1030,20 @@ public enum CompatibleMaterial {
}
}
for (CompatibleMaterial m : values()) {
if (!m.usesCompatibility() && !lookupMap.containsKey(m.legacy)) {
if (!m.usesCompatibility()) {
if (m.legacy != null && !lookupMap.containsKey(m.legacy)) {
lookupMap.put(m.legacy, m);
}
if (m.modern2 != null && !lookupMap.containsKey(m.modern2)) {
lookupMap.put(m.modern2, m);
}
if (m.legacyBlockMaterial != null && !lookupMap.containsKey(m.legacyBlockMaterial.blockMaterialName)) {
lookupMap.put(m.legacyBlockMaterial.blockMaterialName, m);
}
if (m.legacyBlockMaterial != null && !lookupMap.containsKey(m.legacyBlockMaterial.alternateBlockMaterialName)) {
lookupMap.put(m.legacyBlockMaterial.alternateBlockMaterialName, m);
}
}
}
}
@ -1078,7 +1090,7 @@ public enum CompatibleMaterial {
} else if (legacyMaterial != null && (compatibleMaterial == null || ServerVersion.isServerVersionAtLeast(compatibleMaterial.versionLessThan))) {
// we're using a server that has the legacy value available
material = Material.getMaterial(legacyMaterial);
data = legacyRequiresData ? legacyData : null;
data = legacyRequiresData ? this.legacyData : null;
} else if (compatibleMaterial != null) {
// no match: use a proxy
material = compatibleMaterial.material;
@ -1087,21 +1099,30 @@ public enum CompatibleMaterial {
material = null;
data = null;
}
if (material != null && ServerVersion.isServerVersionBelow(ServerVersion.V1_13) && (compatibleMaterial == null || material != compatibleMaterial.material)) {
legacyBlockMaterial = LegacyMaterialBlockType.getMaterial(this.modern);
} else {
legacyBlockMaterial = null;
}
}
/**
* Get the Bukkit Material for this material
*
* @return
* @return the Bukkit Material for this material
*/
public Material getMaterial() {
return material;
}
/**
* Get an item that resembles this material for the current server version
*
* @return
* @return the Bukkit Material required to create a block
*/
public Material getBlockMaterial() {
return legacyBlockMaterial != null ? legacyBlockMaterial.getBlockMaterial() : (isBlock() ? material : AIR.material);
}
/**
* @return an item that resembles this material for the current server version
*/
public ItemStack getItem() {
if (usesCompatibility()) {
@ -1974,8 +1995,6 @@ public enum CompatibleMaterial {
switch (this) {
case ACACIA_WOOD:
case BIRCH_WOOD:
case BREWING_STAND:
case CAULDRON:
case DARK_OAK_WOOD:
case JUNGLE_WOOD:
case OAK_WOOD:
@ -2030,6 +2049,28 @@ public enum CompatibleMaterial {
return false;
}
/**
* @return true if this is a block that has a growth state
*/
public boolean isCrop() {
switch (this) {
case BEETROOTS:
case CACTUS:
case CARROTS:
case CHORUS_FLOWER:
// FROSTED_ICE is Ageable, but not a crop
case KELP:
case MELON_STEM:
case NETHER_WART:
case POTATOES:
case PUMPKIN_STEM:
case SUGAR_CANE:
case WHEAT:
return true;
}
return false;
}
public static CompatibleMaterial getSpawnEgg(EntityType type) {
if(type == EntityType.MUSHROOM_COW) {
return MOOSHROOM_SPAWN_EGG;

View File

@ -0,0 +1,102 @@
package com.songoda.core.compatibility;
import java.util.HashMap;
import java.util.Map;
import org.bukkit.Material;
/**
* Starting in Minecraft 1.13, separate materials for blocks and items were
* phased out. This provides a translation for those values.
*
* @since 2019-09-12
* @author jascotty2
*/
public enum LegacyMaterialBlockType {
ACACIA_DOOR("ACACIA_DOOR", true),
BED("BED_BLOCK", true),
BIRCH_DOOR("BIRCH_DOOR", true),
FURNACE("FURNACE", "BURNING_FURNACE"),
CAKE("CAKE_BLOCK"),
CAULDRON("CAULDRON_BLOCK"),
COMPARATOR("REDSTONE_COMPARATOR_OFF", "REDSTONE_COMPARATOR_ON"),
DARK_OAK_DOOR("DARK_OAK_DOOR", true),
DAYLIGHT_DETECTOR("DAYLIGHT_DETECTOR", "DAYLIGHT_DETECTOR_INVERTED"),
/*
< DOUBLE_STEP,
< DOUBLE_STONE_SLAB2,
*/
FLOWER_POT("FLOWER_POT"),
IRON_DOOR("IRON_DOOR_BLOCK", true),
JUNGLE_DOOR("JUNGLE_DOOR", true),
NETHER_WART("NETHER_WARTS"),
/*
< PURPUR_DOUBLE_SLAB
*/
REDSTONE_LAMP("REDSTONE_LAMP_OFF", "REDSTONE_LAMP_ON"),
REDSTONE_ORE("REDSTONE_ORE", "GLOWING_REDSTONE_ORE"),
REDSTONE_TORCH("REDSTONE_TORCH_ON", "REDSTONE_TORCH_OFF"),
SPRUCE_DOOR("SPRUCE_DOOR"),
/*
< STATIONARY_LAVA,
< STATIONARY_WATER,
*/
SUGAR_CANE("SUGAR_CANE_BLOCK"),
WHEAT("CROPS");
final String blockMaterialName;
final String alternateBlockMaterialName;
final Material blockMaterial, alternateBlockMaterial;
final boolean requiresData; // some blocks require data to render properly (double blocks)
final static Map<String, LegacyMaterialBlockType> lookupTable = new HashMap();
static {
for (LegacyMaterialBlockType t : values()) {
lookupTable.put(t.name(), t);
}
}
private LegacyMaterialBlockType(String blockMaterial) {
this(blockMaterial, null, false);
}
private LegacyMaterialBlockType(String blockMaterial, boolean requiresData) {
this(blockMaterial, null, requiresData);
}
private LegacyMaterialBlockType(String blockMaterial, String alternateMaterial) {
this(blockMaterial, alternateMaterial, false);
}
private LegacyMaterialBlockType(String blockMaterial, String alternateMaterial, boolean requiresData) {
this.blockMaterialName = blockMaterial;
this.alternateBlockMaterialName = alternateMaterial;
this.requiresData = requiresData;
this.blockMaterial = Material.getMaterial(blockMaterialName);
this.alternateBlockMaterial = Material.getMaterial(alternateBlockMaterialName);
}
public String getBlockMaterialName() {
return blockMaterialName;
}
public String getAlternateMaterialName() {
return alternateBlockMaterialName;
}
public Material getBlockMaterial() {
return blockMaterial;
}
public Material getAlternateBlockMaterial() {
return alternateBlockMaterial;
}
public boolean requiresData() {
return requiresData;
}
public static LegacyMaterialBlockType getMaterial(String lookup) {
return lookupTable.get(lookup);
}
}

View File

@ -1,5 +1,7 @@
package com.songoda.core.utils;
import com.songoda.core.compatibility.CompatibleMaterial;
import com.songoda.core.compatibility.ServerVersion;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.EnumSet;
@ -7,11 +9,14 @@ import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
import org.bukkit.CropState;
import org.bukkit.Effect;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.material.Crops;
public class BlockUtils {
@ -342,6 +347,136 @@ public class BlockUtils {
}
}
/**
* Checks if a crop is at its max growth stage
*
* @param block The crop block to check
* @return true if the block is a crop and at its max growth stage
*/
public static boolean isCropFullyGrown(Block block) {
if (block == null) {
return false;
} else if (!useLegacy) {
return BlockUtilsModern._isCropFullyGrown(block);
}
CompatibleMaterial mat = CompatibleMaterial.getMaterial(block.getType());
if (mat == null || !mat.isCrop()) {
return false;
} else {
return block.getData() >= (mat == CompatibleMaterial.BEETROOTS ? 3 : 7);
}
}
/**
* Gets the max growth stage for the given block
*
* @param block The crop block to check
* @return The max growth stage of the given crop type, or -1 if not a crop
*/
public static int getMaxGrowthStage(Block block) {
if (block == null) {
return -1;
} else if (!useLegacy) {
return BlockUtilsModern._getMaxGrowthStage(block);
}
CompatibleMaterial mat = CompatibleMaterial.getMaterial(block.getType());
if (mat == null || !mat.isCrop()) {
return -1;
} else {
return mat == CompatibleMaterial.BEETROOTS ? 3 : 7;
}
}
/**
* Gets the max growth stage for the given material
*
* @param material The material of the crop
* @return The max growth stage of the given crop type
*/
public static int getMaxGrowthStage(Material material) {
if (material == null) {
return -1;
} else if (!useLegacy) {
return BlockUtilsModern._getMaxGrowthStage(material);
}
CompatibleMaterial mat = CompatibleMaterial.getMaterial(material);
if (mat == null || !mat.isCrop()) {
return -1;
} else {
return mat == CompatibleMaterial.BEETROOTS ? 3 : 7;
}
}
/**
* Sets the max growth stage for the given block
*
* @param block The crop block to change
* @param stage new growth stage to use
*/
public static void setGrowthStage(Block block, int stage) {
if (block == null) {
} else if (!useLegacy) {
BlockUtilsModern._setGrowthStage(block, stage);
} else {
CompatibleMaterial mat = CompatibleMaterial.getMaterial(block.getType());
if (mat != null && mat.isCrop()) {
try {
legacySetBlockData.invoke(block, (byte) Math.max(0, Math.min(stage, mat == CompatibleMaterial.BEETROOTS ? 3 : 7)));
} catch (Exception ex) {
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
}
}
}
}
/**
* Increments the growth stage for the given block
*
* @param block The crop block to grow
*/
public static void incrementGrowthStage(Block block) {
if (block == null) {
} else if (!useLegacy) {
BlockUtilsModern._incrementGrowthStage(block);
} else {
CompatibleMaterial mat = CompatibleMaterial.getMaterial(block.getType());
if (mat != null && mat.isCrop() && block.getData() < (mat == CompatibleMaterial.BEETROOTS ? 3 : 7)) {
try {
legacySetBlockData.invoke(block, (byte) block.getData() + 1);
} catch (Exception ex) {
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
}
}
}
}
/**
* Sets a crop's growth back to stage 0
*
* @param block The crop block to set
*/
public static void resetGrowthStage(Block block) {
if (block == null) {
} else if (!useLegacy) {
BlockUtilsModern._resetGrowthStage(block);
} else {
CompatibleMaterial mat = CompatibleMaterial.getMaterial(block.getType());
if (mat != null && mat.isCrop()) {
try {
legacySetBlockData.invoke(block, (byte) 0);
} catch (Exception ex) {
Logger.getLogger(BlockUtils.class.getName()).log(Level.SEVERE, "Unexpected method error", ex);
}
}
}
}
/**
* Check to see if this material does not impede player/mob movement at all.
*
* @param m material to check
* @return true if this material doesn't have a solid hitbox
*/
public static boolean canPassThrough(Material m) {
switch (m.name()) {
@ -355,8 +490,6 @@ public class BlockUtils {
case "ATTACHED_MELON_STEM":
case "ATTACHED_PUMPKIN_STEM":
case "AZURE_BLUET":
//case "BAMBOO_SAPLING":
//case "BARRIER": // could let robots pass through barriers
case "BEETROOTS":
case "BIRCH_BUTTON":
case "BIRCH_PRESSURE_PLATE":
@ -400,7 +533,7 @@ public class BlockUtils {
case "DETECTOR_RAIL":
case "END_PORTAL":
case "FERN":
case "FIRE": // probably should take damage
case "FIRE":
case "FIRE_CORAL_FAN":
case "FIRE_CORAL_WALL_FAN":
case "GRASS":
@ -522,6 +655,13 @@ public class BlockUtils {
return false;
}
/**
* Check to see if a player can walk into this material<br />
* This includes blocks like slabs and stairs
*
* @param m material to check
* @return true if this is a block that can be walked though or up
*/
public static boolean canWalkTo(Material m) {
switch (m.name()) {
case "ACACIA_BUTTON":
@ -539,8 +679,6 @@ public class BlockUtils {
case "ATTACHED_MELON_STEM":
case "ATTACHED_PUMPKIN_STEM":
case "AZURE_BLUET":
//case "BAMBOO_SAPLING":
//case "BARRIER": // could let robots pass through barriers
case "BEETROOTS":
case "BIRCH_BUTTON":
case "BIRCH_DOOR":
@ -569,7 +707,7 @@ public class BlockUtils {
case "BUBBLE_CORAL_FAN":
case "BUBBLE_CORAL_WALL_FAN":
case "CAKE":
case "CAMPFIRE": // could take damage from walking over?
case "CAMPFIRE":
case "CARROTS":
case "CAVE_AIR":
case "COBBLESTONE_SLAB":
@ -614,7 +752,7 @@ public class BlockUtils {
case "END_STONE_BRICK_SLAB":
case "END_STONE_BRICK_STAIRS":
case "FERN":
case "FIRE": // probably should take damage
case "FIRE":
case "FIRE_CORAL_FAN":
case "FIRE_CORAL_WALL_FAN":
case "FLOWER_POT":
@ -767,7 +905,7 @@ public class BlockUtils {
case "SPRUCE_STAIRS":
case "SPRUCE_TRAPDOOR":
case "SPRUCE_WALL_SIGN":
case "STONECUTTER": // technically can step on, so sure
case "STONECUTTER":
case "STONE_BRICK_SLAB":
case "STONE_BRICK_STAIRS":
case "STONE_BUTTON":

View File

@ -1,8 +1,10 @@
package com.songoda.core.utils;
import org.bukkit.Effect;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Ageable;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.AnaloguePowerable;
@ -158,4 +160,55 @@ public class BlockUtilsModern {
return null;
}
protected static boolean _isCropFullyGrown(Block block) {
BlockData data = block.getBlockData();
if(data instanceof Ageable) {
return ((Ageable) data).getAge() == ((Ageable) data).getMaximumAge();
}
return false;
}
protected static int _getMaxGrowthStage(Block block) {
BlockData data = block.getBlockData();
if(data instanceof Ageable) {
return ((Ageable) data).getMaximumAge();
}
return -1;
}
protected static int _getMaxGrowthStage(Material material) {
BlockData data = material.createBlockData();
if(data instanceof Ageable) {
return ((Ageable) data).getMaximumAge();
}
return -1;
}
public static void _setGrowthStage(Block block, int stage) {
BlockData data = block.getBlockData();
if (data instanceof Ageable) {
((Ageable) data).setAge(Math.max(0, Math.min(stage, ((Ageable) data).getMaximumAge())));
block.setBlockData(data);
}
}
public static void _incrementGrowthStage(Block block) {
BlockData data = block.getBlockData();
if (data instanceof Ageable) {
final int max = ((Ageable) data).getMaximumAge();
final int age = ((Ageable) data).getAge();
if (age < max) {
((Ageable) data).setAge(age + 1);
block.setBlockData(data);
}
}
}
public static void _resetGrowthStage(Block block) {
BlockData data = block.getBlockData();
if (data instanceof Ageable) {
((Ageable) data).setAge(0);
block.setBlockData(data);
}
}
}