package joshie.harvest.buildings; import joshie.harvest.api.buildings.Building; import joshie.harvest.buildings.render.BuildingKey; import joshie.harvest.core.helpers.ChatHelper; import joshie.harvest.core.helpers.EntityHelper; import joshie.harvest.core.helpers.TextHelper; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.util.ActionResult; import net.minecraft.util.EnumActionResult; import net.minecraft.util.EnumFacing; import net.minecraft.util.Rotation; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.Vec3d; import net.minecraft.util.text.TextFormatting; import net.minecraft.world.World; import java.util.List; import java.util.Locale; import java.util.WeakHashMap; public class BuildingHelper { public static Vec3d getPositionEyes(EntityPlayer player, float partialTicks) { if (partialTicks == 1.0F) { return new Vec3d(player.posX, player.posY + (double) player.getEyeHeight(), player.posZ); } else { double d0 = player.prevPosX + (player.posX - player.prevPosX) * (double) partialTicks; double d1 = player.prevPosY + (player.posY - player.prevPosY) * (double) partialTicks + (double) player.getEyeHeight(); double d2 = player.prevPosZ + (player.posZ - player.prevPosZ) * (double) partialTicks; return new Vec3d(d0, d1, d2); } } public static RayTraceResult rayTrace(EntityPlayer player, double blockReachDistance, float partialTicks) { Vec3d vec3d = getPositionEyes(player, partialTicks); Vec3d vec3d1 = player.getLook(partialTicks); Vec3d vec3d2 = vec3d.addVector(vec3d1.xCoord * blockReachDistance, vec3d1.yCoord * blockReachDistance, vec3d1.zCoord * blockReachDistance); RayTraceResult result = player.worldObj.rayTraceBlocks(vec3d, vec3d2, false, false, true); return result == null ? null : result; } @SuppressWarnings("all") public static BlockPos getBlockLookingAt(EntityPlayer player) { RayTraceResult raytrace = BuildingHelper.rayTrace(player, 128, 0F); return raytrace == null ? null : raytrace.getBlockPos(); } private static final WeakHashMap<EntityPlayer, BuildingKey> POSITIONS_SERVER = new WeakHashMap<>(); private static final WeakHashMap<EntityPlayer, ItemStack> STACKS_SERVER = new WeakHashMap<>(); private static BuildingKey POSITION_CLIENT; private static ItemStack STACK_CLIENT; private static void validateOrInvalidateStack(ItemStack stack, EntityPlayer player) { if (player.worldObj.isRemote) { if (STACK_CLIENT != stack) { STACK_CLIENT = stack; POSITION_CLIENT = null; } } else { if (STACKS_SERVER.get(player) != stack) { STACKS_SERVER.put(player, stack); POSITIONS_SERVER.remove(player); } } } private static void setPositionForPlayer(EntityPlayer player, BuildingKey pos) { if (player.worldObj.isRemote) POSITION_CLIENT = pos; else POSITIONS_SERVER.put(player, pos); } private static BuildingKey getPositionForPlayer(EntityPlayer player) { if (player.worldObj.isRemote) return POSITION_CLIENT; else return POSITIONS_SERVER.get(player); } private static boolean isAir(World world, BlockPos pos) { return world.isAirBlock(pos); } private static BuildingKey getCachedKey(EntityPlayer player, BlockPos pos, Building building) { EnumFacing facing = EntityHelper.getFacingFromEntity(player).getOpposite(); Rotation rotation = Rotation.NONE; if (facing == EnumFacing.NORTH) { rotation = Rotation.CLOCKWISE_90; } else if (facing == EnumFacing.SOUTH) { rotation = Rotation.COUNTERCLOCKWISE_90; } else if (facing == EnumFacing.EAST) { rotation = Rotation.CLOCKWISE_180; } else if (facing == EnumFacing.WEST) { rotation = Rotation.NONE; } int length = building.getLength(); int width = building.getWidth(); if (facing == EnumFacing.NORTH) pos = pos.offset(facing, length).offset(EnumFacing.EAST, width); else if (facing == EnumFacing.SOUTH) pos = pos.offset(facing, length).offset(EnumFacing.WEST, width); else if (facing == EnumFacing.EAST) pos = pos.offset(facing, length).offset(EnumFacing.SOUTH, width); else if (facing == EnumFacing.WEST) pos = pos.offset(facing, length).offset(EnumFacing.NORTH, width); return BuildingKey.of(rotation, building, pos); } @SuppressWarnings("deprecation") public static BuildingKey getPositioning(ItemStack stack, World world, RayTraceResult raytrace, Building building, EntityPlayer player, boolean clicked) { validateOrInvalidateStack(stack, player); BlockPos pos = raytrace.getBlockPos().offset(raytrace.sideHit).up(building.getOffsetY()); //Load the saved position BuildingKey key = getPositionForPlayer(player); if (key == null) { if (clicked) { if (!isAir(world, raytrace.getBlockPos()) && raytrace.sideHit == EnumFacing.UP) { setPositionForPlayer(player, getCachedKey(player, pos, building)); if (world.isRemote) { ChatHelper.displayChat(TextFormatting.YELLOW + building.getLocalisedName() + TextFormatting.RESET + " " + TextHelper.translate("town.preview") + "\n-" + TextHelper.translate("town.sneak") +" " + TextFormatting.GREEN + "" + TextHelper.translate("town.confirm") + "\n-" + TextFormatting.RESET + TextHelper.translate("town.click") + " " + TextFormatting.RED + TextHelper.translate("town.cancel")); } } return null; } } else { if (clicked) { if (!player.isSneaking() && world.isRemote) { ChatHelper.displayChat(TextFormatting.RED + building.getLocalisedName() + " " + TextHelper.translate("town.cancelled")); } setPositionForPlayer(player, null); return player.isSneaking() ? key : null; } } return key == null ? raytrace.sideHit != EnumFacing.UP ? null : getCachedKey(player, pos, building) : key; } public static ActionResult<ItemStack> displayErrors(World world, ItemStack stack, List<BuildingError> errors) { if (world.isRemote) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < errors.size(); i++) { String string = TextFormatting.RED + TextHelper.translate("town.failure") + " " + TextFormatting.WHITE + TextHelper.translate("town." + errors.get(i).name().toLowerCase(Locale.ENGLISH)); builder.append(string); if (i < errors.size() + 1) builder.append("\n"); } ChatHelper.displayChat(builder.toString()); } return new ActionResult<>(EnumActionResult.PASS, stack); } }