/* * Copyright (c) 2017 Richard Jones <[email protected]> * All Rights Reserved * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ package net.mechanicalcat.pycode.script; import net.minecraft.block.*; import net.minecraft.block.properties.PropertyDirection; import net.minecraft.block.properties.PropertyEnum; import net.minecraft.block.state.IBlockState; import net.minecraft.command.CommandBlockData; import net.minecraft.command.ICommandSender; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.EnumDyeColor; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.WorldServer; import net.minecraftforge.fml.common.FMLLog; import org.python.core.Py; import javax.annotation.Nullable; import java.util.HashMap; public class PyRegistry { @Nullable public static MyBase myWrapper(World world, ICommandSender object) { if (object instanceof EntityPlayer || object instanceof EntityPlayerMP) { return new MyEntityPlayer((EntityPlayer)object); } else if (object instanceof EntityLivingBase) { return new MyEntityLiving((EntityLivingBase) object); } else if (object instanceof Entity) { return new MyEntity((Entity) object); } else if (object instanceof TileEntity) { BlockPos bp = ((TileEntity) object).getPos(); return new MyBlock(world.getBlockState(bp), bp); } return null; } public static Block getBlock(String blockName) throws BlockTypeError { Block block = Block.REGISTRY.getObject(new ResourceLocation(blockName)); FMLLog.info("getBlock asked for '%s', got '%s'", blockName, block.getUnlocalizedName()); if (block.getUnlocalizedName().equals("tile.air") && !blockName.equals("air")) { throw new BlockTypeError(blockName); } return block; } @Nullable public static EnumFacing getBlockFacing(IBlockState state) { Block block = state.getBlock(); PropertyDirection direction; try { direction = (PropertyDirection)block.getClass().getField("FACING").get(state.getBlock()); } catch (NoSuchFieldException | IllegalAccessException e) { return null; } return state.getValue(direction); } public static String[] BLOCK_VARIATIONS = {"color", "facing", "type", "half", "shape", "seamless"}; public static IBlockState getBlockVariant(ArgParser spec, BlockPos pos, EnumFacing facing, WorldServer world) { String blockName = spec.getString("blockname"); Block block; try { block = PyRegistry.getBlock(blockName); } catch (BlockTypeError e) { throw Py.TypeError("Unknown block " + blockName); } IBlockState block_state = block.getDefaultState(); EnumFacing opposite = facing.getOpposite(); PropertyDirection direction; block_state = modifyBlockStateFromSpec(block_state, spec, facing); // if we haven't had an explicit facing set then try to determine a good one if (!spec.has("facing")) { try { direction = (PropertyDirection)block.getClass().getField("FACING").get(block); if (world.isAirBlock(pos)) { // check whether the next pos along (pos -> farpos) is solid (attachable) BlockPos farpos = pos.offset(facing); if (world.isSideSolid(farpos, opposite, true)) { // attach in faced pos on farpos block_state = block_state.withProperty(direction, opposite); FMLLog.fine("attach in pos=%s facing=%s", pos, opposite); } } } catch (NoSuchFieldException | IllegalAccessException e) { FMLLog.fine("attach in current pos=%s no facing", pos); } } return block_state; } public static IBlockState modifyBlockStateFromSpec(IBlockState block_state, ArgParser spec, EnumFacing facing) { Block block = block_state.getBlock(); String blockName = block.getLocalizedName(); if (spec.has("color")) { String color = spec.getString("color"); EnumDyeColor dye = PythonCode.COLORMAP.get(color); if (dye == null) { throw Py.TypeError(blockName + " color " + color); } PropertyEnum<EnumDyeColor> prop; try { prop = (PropertyEnum<EnumDyeColor>) block.getClass().getField("COLOR").get(block); } catch (NoSuchFieldException | IllegalAccessException e) { throw Py.TypeError(blockName + " cannot be colored"); } block_state = block_state.withProperty(prop, dye); } if (spec.has("facing")) { String s = spec.getString("facing"); EnumFacing blockFacing; if (s.equals("left")) { blockFacing = facing.rotateYCCW(); } else if (s.equals("right")) { blockFacing = facing.rotateY(); } else if (s.equals("back")) { blockFacing = facing.getOpposite(); } else { blockFacing = PythonCode.FACINGMAP.get(s); } if (blockFacing == null) { throw Py.TypeError("Invalid facing " + s); } PropertyDirection direction; try { direction = (PropertyDirection) block_state.getBlock().getClass().getField("FACING").get(block_state.getBlock()); } catch (NoSuchFieldException | IllegalAccessException e) { throw Py.TypeError(blockName + " does not have facing"); } block_state = block_state.withProperty(direction, blockFacing); } if (spec.has("type")) if (block_state.getBlock() instanceof BlockPlanks) { String s = spec.getString("type"); BlockPlanks.EnumType type = PyRegistry.PLANKTYPES.get(s); if (s == null) throw Py.TypeError(blockName + " unknown type " + s); block_state = block_state.withProperty(BlockPlanks.VARIANT, type); } else if (block_state.getBlock() instanceof BlockStoneSlab) { String s = spec.getString("type"); BlockStoneSlab.EnumType type = PyRegistry.STONETYPES.get(s); if (s == null) throw Py.TypeError(blockName + " unknown type " + s); block_state = block_state.withProperty(BlockStoneSlab.VARIANT, type); } if (spec.has("half")) { if (block_state.getBlock() instanceof BlockStairs) { String s = spec.getString("half"); BlockStairs.EnumHalf half; switch (s) { case "top": half = BlockStairs.EnumHalf.TOP; break; case "bottom": half = BlockStairs.EnumHalf.BOTTOM; break; default: throw Py.TypeError(blockName + " unknown half " + s); } block_state = block_state.withProperty(BlockStairs.HALF, half); } else if (block_state.getBlock() instanceof BlockSlab) { String s = spec.getString("half"); BlockSlab.EnumBlockHalf half; switch (s) { case "top": half = BlockSlab.EnumBlockHalf.TOP; break; case "bottom": half = BlockSlab.EnumBlockHalf.BOTTOM; break; default: throw Py.TypeError(blockName + " unknown half " + s); } block_state = block_state.withProperty(BlockSlab.HALF, half); } } if (spec.has("seamless") && block_state.getBlock() instanceof BlockStoneSlab) { block_state = block_state.withProperty(BlockStoneSlab.SEAMLESS, spec.getBoolean("seamless")); } if (spec.has("shape") && block_state.getBlock() instanceof BlockStairs) { String s = spec.getString("shape"); BlockStairs.EnumShape shape; switch (s) { case "straight": shape = BlockStairs.EnumShape.STRAIGHT; break; case "inner_left": shape = BlockStairs.EnumShape.INNER_LEFT; break; case "inner_right": shape = BlockStairs.EnumShape.INNER_RIGHT; break; case "outer_left": shape = BlockStairs.EnumShape.OUTER_LEFT; break; case "outer_right": shape = BlockStairs.EnumShape.OUTER_RIGHT; break; default: throw Py.TypeError(blockName + " unknown shape " + s); } block_state = block_state.withProperty(BlockStairs.SHAPE, shape); } return block_state; } public static HashMap<String, String> FILLER = new HashMap<>(); public static HashMap<String, BlockPlanks.EnumType> PLANKTYPES = new HashMap<>(); public static HashMap<String, BlockStoneSlab.EnumType> STONETYPES = new HashMap<>(); static { FILLER.put("oak", "planks"); FILLER.put("stone", "stone"); FILLER.put("brick", "brick_block"); FILLER.put("stone_brick", "stonebrick"); FILLER.put("nether_brick", "nether_brick"); FILLER.put("sandstone", "sandstone"); FILLER.put("spruce", "planks"); FILLER.put("birch", "planks"); FILLER.put("jungle", "planks"); FILLER.put("acacia", "planks"); FILLER.put("dark_oak", "planks"); FILLER.put("quartz", "quartz_block"); FILLER.put("red_sandstone", "red_sandstone"); FILLER.put("purpur", "purpur_block"); PLANKTYPES.put("oak", BlockPlanks.EnumType.OAK); PLANKTYPES.put("spruce", BlockPlanks.EnumType.SPRUCE); PLANKTYPES.put("birch", BlockPlanks.EnumType.BIRCH); PLANKTYPES.put("jungle", BlockPlanks.EnumType.JUNGLE); PLANKTYPES.put("acacia", BlockPlanks.EnumType.ACACIA); PLANKTYPES.put("dark_oak", BlockPlanks.EnumType.DARK_OAK); STONETYPES.put("stone", BlockStoneSlab.EnumType.STONE); STONETYPES.put("sandstone", BlockStoneSlab.EnumType.SAND); STONETYPES.put("wood_old", BlockStoneSlab.EnumType.WOOD); STONETYPES.put("cobblestone", BlockStoneSlab.EnumType.COBBLESTONE); STONETYPES.put("brick", BlockStoneSlab.EnumType.BRICK); STONETYPES.put("stone_brick", BlockStoneSlab.EnumType.SMOOTHBRICK); STONETYPES.put("nether_brick", BlockStoneSlab.EnumType.NETHERBRICK); STONETYPES.put("quartz", BlockStoneSlab.EnumType.QUARTZ); } }