mirror of
https://github.com/songoda/SongodaCore.git
synced 2025-02-12 01:21:33 +01:00
add crop funtions + legacy block translation
This commit is contained in:
parent
8c4cbbd201
commit
ee36d95cb4
@ -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,11 +1030,22 @@ public enum CompatibleMaterial {
|
||||
}
|
||||
}
|
||||
for (CompatibleMaterial m : values()) {
|
||||
if (!m.usesCompatibility() && !lookupMap.containsKey(m.legacy)) {
|
||||
lookupMap.put(m.legacy, m);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CompatibleMaterial() {
|
||||
this(ServerVersion.UNKNOWN, null, null);
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Bukkit Material required to create a block
|
||||
*/
|
||||
public Material getBlockMaterial() {
|
||||
return legacyBlockMaterial != null ? legacyBlockMaterial.getBlockMaterial() : (isBlock() ? material : AIR.material);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an item that resembles this material for the current server version
|
||||
*
|
||||
* @return
|
||||
* @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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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":
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user