diff --git a/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/compat/bukkit/MCAccessBukkitModern.java b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/compat/bukkit/MCAccessBukkitModern.java index 300af9fb..5efaa87a 100644 --- a/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/compat/bukkit/MCAccessBukkitModern.java +++ b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/compat/bukkit/MCAccessBukkitModern.java @@ -21,8 +21,10 @@ import org.bukkit.Material; import fr.neatmonster.nocheatplus.compat.BridgeMaterial; import fr.neatmonster.nocheatplus.compat.blocks.init.BlockInit; +import fr.neatmonster.nocheatplus.compat.bukkit.model.BukkitDoor; import fr.neatmonster.nocheatplus.compat.bukkit.model.BukkitFence; import fr.neatmonster.nocheatplus.compat.bukkit.model.BukkitGate; +import fr.neatmonster.nocheatplus.compat.bukkit.model.BukkitTrapDoor; import fr.neatmonster.nocheatplus.compat.bukkit.model.BukkitShapeModel; import fr.neatmonster.nocheatplus.compat.bukkit.model.BukkitShulkerBox; import fr.neatmonster.nocheatplus.compat.bukkit.model.BukkitSlab; @@ -39,6 +41,8 @@ public class MCAccessBukkitModern extends MCAccessBukkit { protected final Map shapeModels = new HashMap(); // Blocks that change shape based on interaction or redstone. + private static final BukkitShapeModel MODEL_DOOR = new BukkitDoor(); + private static final BukkitShapeModel MODEL_TRAP_DOOR = new BukkitTrapDoor(); private static final BukkitShapeModel MODEL_GATE = new BukkitGate( 0.375, 1.5); private static final BukkitShapeModel MODEL_SHULKER_BOX = new BukkitShulkerBox(); @@ -55,29 +59,42 @@ public class MCAccessBukkitModern extends MCAccessBukkit { 0.375, 1.5); - // Static blocks. + // Static blocks (random heights). private static final BukkitShapeModel MODEL_FLOWER_POT = new BukkitStatic( 0.33, 0.375); // TODO: XZ really? private static final BukkitShapeModel MODEL_GROUND_HEAD= new BukkitStatic( 0.25, 0.5); // TODO: XZ-really? 275 ? private static final BukkitShapeModel MODEL_SINGLE_CHEST = new BukkitStatic( - 0.062, .875); + 0.062, .875); // TODO: 0.0625? + private static final BukkitShapeModel MODEL_CACTUS = new BukkitStatic( + 0.0625, 1.0); + private static final BukkitShapeModel MODEL_LILY_PAD = new BukkitStatic( + 0.09375); + + // Static blocks with full xz-bounds sorted by height. private static final BukkitShapeModel MODEL_XZ100_HEIGHT16_1 = new BukkitStatic( 0.0625); - private static final BukkitShapeModel MODEL_XZ100_HEIGHT16_9 = new BukkitStatic( - 0.5625); - private static final BukkitShapeModel MODEL_XZ100_HEIGHT16_15 = new BukkitStatic( - 0.9375); private static final BukkitShapeModel MODEL_XZ100_HEIGHT8_1 = new BukkitStatic( 0.125); private static final BukkitShapeModel MODEL_XZ100_HEIGHT8_3 = new BukkitStatic( 0.375); + private static final BukkitShapeModel MODEL_XZ100_HEIGHT16_9 = new BukkitStatic( + 0.5625); + private static final BukkitShapeModel MODEL_XZ100_HEIGHT4_3 = new BukkitStatic( + 0.75); + private static final BukkitShapeModel MODEL_XZ100_HEIGHT16_15 = new BukkitStatic( + 0.9375); - // TODO: enchanting table - // TODO: doors, trap doors - // TODO: Portals, end portal frame, ... + /* + * TODO: + * BREWING_STAND, CAULDRON, CONDUIT, HOPPER, END_PORTAL_FRAME, + * CHORUS_FLOWER, CHORUS_PLANT, COCOA, + * DRAGON_EGG, TURTLE_EGG, SEA_PICKLE, + * VINE, LADDER, + * CAKE, + */ + // TODO: anvils, dead coral fans // TODO: END_ROD: 0.075 + 0.3, 0.925 - 0.3 / 1.0 -> BukkitCenteredFacing +- - // TODO: wall heads, chorus flower, other static, CAKE? public MCAccessBukkitModern() { super(); @@ -115,12 +132,11 @@ public class MCAccessBukkitModern extends MCAccessBukkit { processedBlocks.add(mat); } - // 16/15 height, full xz bounds. - for (Material mat : new Material[] { - Material.GRASS_PATH, BridgeMaterial.FARMLAND - }) { - addModel(mat, MODEL_XZ100_HEIGHT16_15); - } + // Cactus. + addModel(Material.CACTUS, MODEL_CACTUS); + + // Lily pad + addModel(BridgeMaterial.LILY_PAD, MODEL_LILY_PAD); // 1/8 height. for (Material mat : new Material[] { @@ -137,6 +153,20 @@ public class MCAccessBukkitModern extends MCAccessBukkit { addModel(mat, MODEL_XZ100_HEIGHT8_3); } + // 3/4 height. + for (Material mat : new Material[] { + BridgeMaterial.ENCHANTING_TABLE + }) { + addModel(mat, MODEL_XZ100_HEIGHT4_3); + } + + // 16/15 height, full xz bounds. + for (Material mat : new Material[] { + Material.GRASS_PATH, BridgeMaterial.FARMLAND + }) { + addModel(mat, MODEL_XZ100_HEIGHT16_15); + } + // Thin fence: Glass panes, iron bars. for (final Material mat : MaterialUtil.addBlocks( MaterialUtil.GLASS_PANES, BridgeMaterial.IRON_BARS)) { @@ -172,7 +202,7 @@ public class MCAccessBukkitModern extends MCAccessBukkit { addModel(mat, MODEL_FLOWER_POT); } - // Carpets + // Carpets. for (final Material mat : MaterialUtil.CARPETS) { addModel(mat, MODEL_XZ100_HEIGHT16_1); } @@ -182,6 +212,16 @@ public class MCAccessBukkitModern extends MCAccessBukkit { addModel(mat, MODEL_GROUND_HEAD); } + // Doors. + for (final Material mat : MaterialUtil.ALL_DOORS) { + addModel(mat, MODEL_DOOR); + } + + // Trapdoors. + for (final Material mat : MaterialUtil.ALL_TRAP_DOORS) { + addModel(mat, MODEL_TRAP_DOOR); + } + // Sort to processed by flags. for (final Material mat : Material.values()) { final long flags = BlockProperties.getBlockFlags(mat); diff --git a/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/compat/bukkit/model/BukkitDoor.java b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/compat/bukkit/model/BukkitDoor.java new file mode 100644 index 00000000..388d3eb2 --- /dev/null +++ b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/compat/bukkit/model/BukkitDoor.java @@ -0,0 +1,144 @@ +/* + * This program 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. + * + * 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.compat.bukkit.model; + +import org.bukkit.World; +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.type.Door; +import org.bukkit.block.data.type.Door.Hinge; + +import fr.neatmonster.nocheatplus.utilities.map.BlockCache; + +public class BukkitDoor implements BukkitShapeModel { + + /** + * + * @param facing + * @param hinge + * @param isOpen + * @return The block face of the block the door is standing on, indicating + * where the door is. + */ + private static final BlockFace getWhereTheDoorIsFace( + final BlockFace facing, final Hinge hinge, + final boolean isOpen) { + // For idiots: + /* + * Facing: Door is closing the opposite side of the block, so the + * "outside" is south. + */ + /* + * Hinge: Looking into the facing direction, hinge is left or right. + */ + // Bukkit.getServer().broadcastMessage("hinge=" + hinge + // + " / facing=" + facing + // + " / open=" + isOpen); + // Let's play north and south: + switch (facing) { + case NORTH: + if (isOpen) { + if (hinge == Hinge.LEFT) { + return BlockFace.WEST; + } + else { + return BlockFace.EAST; + } + } + else { + return BlockFace.SOUTH; + } + case SOUTH: + if (isOpen) { + if (hinge == Hinge.LEFT) { + return BlockFace.EAST; + } + else { + return BlockFace.WEST; + } + } + else { + return BlockFace.NORTH; + } + case EAST: + if (isOpen) { + if (hinge == Hinge.LEFT) { + return BlockFace.NORTH; + } + else { + return BlockFace.SOUTH; + } + } + else { + return BlockFace.WEST; + } + case WEST: + if (isOpen) { + if (hinge == Hinge.LEFT) { + return BlockFace.SOUTH; + } + else { + return BlockFace.NORTH; + } + } + else { + return BlockFace.EAST; + } + default: + // Invalid + return BlockFace.SELF; + } + } + + //private static final double doorWidthClosed = 0.2125; + private static final double doorWidthOpen = 0.1875; + + @Override + public double[] getShape(final BlockCache blockCache, + final World world, final int x, final int y, final int z) { + final Block block = world.getBlockAt(x, y, z); + final BlockState state = block.getState(); + final BlockData blockData = state.getBlockData(); + if (blockData instanceof Door) { + final Door door = (Door) blockData; + final boolean isOpen = door.isOpen(); + final double doorWidth = doorWidthOpen; // isOpen ? doorWidthOpen : doorWidthClosed; + switch(getWhereTheDoorIsFace(door.getFacing(), + door.getHinge(), isOpen)) { + case NORTH: + return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, doorWidth}; + case SOUTH: + return new double[] {0.0, 0.0, 1.0 - doorWidth, 1.0, 1.0, 1.0}; + case EAST: + return new double[] {1.0 - doorWidth, 0.0, 0.0, 1.0, 1.0, 1.0}; + case WEST: + return new double[] {0.0, 0.0, 0.0, doorWidth, 1.0, 1.0}; + default: + break; + } + + } + return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0}; + } + + @Override + public int getFakeData(final BlockCache blockCache, + final World world, final int x, final int y, final int z) { + return 0; + } + +} diff --git a/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/compat/bukkit/model/BukkitTrapDoor.java b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/compat/bukkit/model/BukkitTrapDoor.java new file mode 100644 index 00000000..2e1f1e72 --- /dev/null +++ b/NCPCompatBukkit/src/main/java/fr/neatmonster/nocheatplus/compat/bukkit/model/BukkitTrapDoor.java @@ -0,0 +1,78 @@ +/* + * This program 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. + * + * 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package fr.neatmonster.nocheatplus.compat.bukkit.model; + +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.Bisected.Half; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Openable; +import org.bukkit.block.data.type.TrapDoor; + +import fr.neatmonster.nocheatplus.utilities.map.BlockCache; + +public class BukkitTrapDoor implements BukkitShapeModel { + + private static final double closedHeight = 0.1875; + private static final double openWidth = 0.1875; + + @Override + public double[] getShape(final BlockCache blockCache, + final World world, final int x, final int y, final int z) { + final Block block = world.getBlockAt(x, y, z); + final BlockState state = block.getState(); + final BlockData blockData = state.getBlockData(); + if (blockData instanceof TrapDoor) { + final TrapDoor trapDoor = (TrapDoor) blockData; + if (trapDoor.isOpen()) { + switch(trapDoor.getFacing()) { + case NORTH: + return new double[] {0.0, 0.0, 1.0 - openWidth, 1.0, 1.0, 1.0}; + case SOUTH: + return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, openWidth}; + case EAST: + return new double[] {0.0, 0.0, 0.0, openWidth, 1.0, 1.0}; + case WEST: + return new double[] {1.0 - openWidth, 0.0, 0.0, 1.0, 1.0, 1.0}; + default: + break; + } + } + else { + return trapDoor.getHalf() == Half.BOTTOM + ? new double[] {0.0, 0.0, 0.0, 1.0, closedHeight, 1.0} + : new double[] {0.0, 1.0 - closedHeight, 0.0, 1.0, 1.0, 1.0}; + + } + } + return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0}; + } + + @Override + public int getFakeData(final BlockCache blockCache, + final World world, final int x, final int y, final int z) { + final Block block = world.getBlockAt(x, y, z); + final BlockState state = block.getState(); + final BlockData blockData = state.getBlockData(); + if (blockData instanceof Openable) { + return ((Openable) blockData).isOpen() ? 0x4 : 0; + } + else { + return 0; + } + } + +} diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_11.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_11.java index 7c34de7f..e1943724 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_11.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_11.java @@ -18,6 +18,7 @@ import fr.neatmonster.nocheatplus.compat.blocks.BlockPropertiesSetup; import fr.neatmonster.nocheatplus.compat.blocks.init.BlockInit; import fr.neatmonster.nocheatplus.config.WorldConfigProvider; import fr.neatmonster.nocheatplus.logging.StaticLog; +import fr.neatmonster.nocheatplus.utilities.map.BlockFlags; import fr.neatmonster.nocheatplus.utilities.map.BlockProperties; import fr.neatmonster.nocheatplus.utilities.map.BlockProperties.BlockProps; @@ -31,14 +32,15 @@ public class BlocksMC1_11 implements BlockPropertiesSetup { @Override public void setupBlockProperties(WorldConfigProvider worldConfigProvider) { - long solidFlags = BlockProperties.F_SOLID | BlockProperties.F_GROUND; // 218 OBSERVER // Wiki (16-11-25): 17.5, 2.65, 1.32, 0.9, 0.7, 0.45 - BlockProperties.setBlockProps("OBSERVER", new BlockProps(BlockProperties.woodPickaxe, 6, - BlockProperties.secToMs(15.0, 2.2, 1.1, 0.7, 0.55, 0.45))); - BlockProperties.setBlockFlags("OBSERVER", solidFlags); + BlockProperties.setBlockProps("OBSERVER", + new BlockProps(BlockProperties.woodPickaxe, 6, + BlockProperties.secToMs(15.0, 2.2, 1.1, 0.7, 0.55, 0.45))); + BlockProperties.setBlockFlags("OBSERVER", + BlockFlags.FULLY_SOLID_BOUNDS); // ALL SORTS OF SHULKER BOXES - + StaticLog.logInfo("Added block-info for Minecraft 1.11 blocks."); } diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_5.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_5.java index fb54ffcb..119f595a 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_5.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_5.java @@ -82,7 +82,9 @@ public class BlocksMC1_5 implements BlockPropertiesSetup { | BlockProperties.F_XZ100); // 152 Block of Redstone - BlockInit.setAs("REDSTONE_BLOCK", BridgeMaterial.ENCHANTING_TABLE); + BlockInit.setPropsAs("REDSTONE_BLOCK", BridgeMaterial.ENCHANTING_TABLE); + BlockProperties.setBlockFlags("REDSTONE_BLOCK", + BlockFlags.FULLY_SOLID_BOUNDS); // 153 Nether Quartz Ore BlockInit.setAs(BridgeMaterial.NETHER_QUARTZ_ORE, Material.COAL_ORE); diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_9.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_9.java index 4917e1d8..c9aa2700 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_9.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/compat/blocks/init/vanilla/BlocksMC1_9.java @@ -75,8 +75,7 @@ public class BlocksMC1_9 implements BlockPropertiesSetup { BlockInit.setAs(BridgeMaterial.END_STONE_BRICKS, Material.SANDSTONE); // 207(BEETROOT_BLOCK) - BlockFlags.addFlags(BridgeMaterial.BEETROOTS, ground); - BlockProperties.setBlockProps(BridgeMaterial.BEETROOTS, instant); + BlockInit.setInstantPassable(BridgeMaterial.BEETROOTS); // 208(GRASS_PATH / SOLID+GROUND) BlockInit.setAs("GRASS_PATH", BridgeMaterial.GRASS_BLOCK); // Later it'll be lower! diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/BlockFlags.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/BlockFlags.java index 8dafe70e..775743c4 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/BlockFlags.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/BlockFlags.java @@ -34,6 +34,9 @@ public class BlockFlags { /** SOLID and GROUND set. Treatment of SOLID/GROUND may be changed later. */ public static final long SOLID_GROUND = BlockProperties.F_SOLID | BlockProperties.F_GROUND; + /** Full bounds and solid (+ground). */ + public static final long FULLY_SOLID_BOUNDS = FULL_BOUNDS | SOLID_GROUND; + /** * Set flags of id same as already set with flags for the given material. * (Uses BlockProperties.) diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/BlockProperties.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/BlockProperties.java index e847447c..f7228263 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/BlockProperties.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/BlockProperties.java @@ -1451,6 +1451,9 @@ public class BlockProperties { setBlock(mat, indestructibleType); } } + + setBlockFlags(Material.BEDROCK, BlockFlags.FULLY_SOLID_BOUNDS); + // 95 Locked chest // blocks[95] = indestructibleType; // Locked chest (prevent crash with 1.7). if (BridgeMaterial.has("locked_chest")) { diff --git a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/MaterialUtil.java b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/MaterialUtil.java index 835a44dc..1b1fee17 100644 --- a/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/MaterialUtil.java +++ b/NCPCore/src/main/java/fr/neatmonster/nocheatplus/utilities/map/MaterialUtil.java @@ -148,6 +148,18 @@ public class MaterialUtil { public static final Set ALL_BUTTONS = Collections.unmodifiableSet( BridgeMaterial.getBySuffix("_button", AlmostBoolean.YES, "legacy")); + public static final Set ALL_DOORS = Collections.unmodifiableSet( + BridgeMaterial.getByPrefixAndSuffix( + null, Arrays.asList("_door"), AlmostBoolean.YES, + "trap", "legacy") + ); + + public static final Set ALL_TRAP_DOORS = Collections.unmodifiableSet( + BridgeMaterial.getByPrefixAndSuffix( + null, Arrays.asList("trapdoor", "trap_door"), AlmostBoolean.YES, + "legacy") + ); + public static final Set ALL_PRESSURE_PLATES = Collections.unmodifiableSet( BridgeMaterial.getBySuffix("_pressure_plate", AlmostBoolean.YES, "legacy")); @@ -326,17 +338,17 @@ public class MaterialUtil { "sandstone", "command_block" ), AlmostBoolean.YES, "legacy"), - "observer", "structure_block", - "note_block", "tnt", + "barrier", "structure_block", + "note_block", "tnt", "piston", "sticky_piston", "piston_base", "piston_sticky_base", - "dispenser", "dropper", "furnace", + "dispenser", "dropper", "furnace", "observer", "pumpkin", "melon_block", "hay_block", "bone_block", "nether_wart_block", "snow_block", "ice", "magma_block", "diamond_block", "gold_block", "iron_block", "coal_block", "emerald_block", "lapis_block", "redstone_block", "purpur_block", "smooth_stone", "smooth_quartz", "quartz_block", - "quartz_pillar", + "quartz_pillar", "bookshelf", "sand", "stone", "gravel", "dirt", "grass_block", "grass", "sea_lantern", "redstone_lamp", "glowstone", "sponge", "wet_sponge" )); @@ -450,18 +462,17 @@ public class MaterialUtil { Arrays.asList("coral_fan", "coral_wall_fan", "coral"), AlmostBoolean.YES, "dead", "legacy"), BridgeMaterial.getAllBlocks("attached_melon_stem", "attached_pumpkin_stem", - "allium", "dandelion", "dandelion_yellow", "double_plant", "fern", - "kelp", "kelp_plant", "large_fern", "lilac", "melon_stem", - "nether_wart", "nether_warts", "oxeye_daisy", "peony", "poppy", - "red_rose", "rose_red", "seagrass", "sunflower", "tall_seagrass", - "yellow_flower" - // TODO: Ground or not: "beetroots", "beetroot_block" + "allium", "dandelion", "dandelion_yellow", + "double_plant", "fern", "kelp", "kelp_plant", "large_fern", + "lilac", "melon_stem", "nether_wart", "nether_warts", + "oxeye_daisy", "peony", "poppy", "red_rose", "rose_red", + "seagrass", "sunflower", "tall_seagrass", "yellow_flower" ), new HashSet(Arrays.asList(BridgeMaterial.TALL_GRASS, BridgeMaterial.WHEAT_CROPS, BridgeMaterial.CARROTS, BridgeMaterial.POTATOES, BridgeMaterial.GRASS, Material.PUMPKIN_STEM, Material.MELON_STEM, - BridgeMaterial.SUGAR_CANE)) + BridgeMaterial.SUGAR_CANE, BridgeMaterial.BEETROOTS)) )); /**