Rename to Extra Hoppers and convert to Kotlin

This commit is contained in:
Shadowfacts 2017-01-14 18:51:05 -05:00
parent 4aef4e6f8c
commit 8634678fe8
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
32 changed files with 724 additions and 527 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
.DS_Store .DS_Store
todo.txt
/download /download
/eclipseBin /eclipseBin

View File

@ -8,6 +8,7 @@ buildscript {
} }
dependencies { dependencies {
classpath "net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT" classpath "net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}"
} }
} }
@ -16,6 +17,7 @@ plugins {
} }
apply plugin: "net.minecraftforge.gradle.forge" apply plugin: "net.minecraftforge.gradle.forge"
apply plugin: "kotlin"
version = mc_version + "-" + mod_version version = mc_version + "-" + mod_version
@ -28,7 +30,8 @@ minecraft {
mappings = mcp_mappings mappings = mcp_mappings
replaceIn "Funnels.java" replaceIn "ExtraHoppers.kt"
replaceIn "Reference.kt"
replace "@VERSION@", mod_version replace "@VERSION@", mod_version
useDepAts = true useDepAts = true
@ -59,6 +62,7 @@ repositories {
dependencies { dependencies {
deobfCompile group: "net.shadowfacts", name: "ShadowMC", version: mc_version + "-" + shadowmc_version deobfCompile group: "net.shadowfacts", name: "ShadowMC", version: mc_version + "-" + shadowmc_version
deobfCompile group: "net.shadowfacts", name: "Forgelin", version: forgelin_version
deobfCompile group: "mezz.jei", name: "jei_" + mc_version, version: jei_version deobfCompile group: "mezz.jei", name: "jei_" + mc_version, version: jei_version
} }

View File

@ -1,10 +1,14 @@
mod_version = 1.2.1 mod_version = 1.3.0
group = net.shadowfacts group = net.shadowfacts
archivesBaseName = Funnels archivesBaseName = ExtraHoppers
mc_version = 1.11 mc_version = 1.11
mcp_mappings = snapshot_20161120 mcp_mappings = snapshot_20170113
forge_version = 13.19.1.2188 forge_version = 13.19.1.2199
kotlin_version = 1.0.6
shadowmc_version = 3.7.4
forgelin_version = 1.2.0
jei_version = 4.1.1.208
shadowmc_version = 3.7.0
jei_version = 4.0.5.202

View File

@ -1,121 +0,0 @@
package net.shadowfacts.funnels;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.PropertyDirection;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.fluids.FluidActionResult;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.shadowfacts.shadowmc.block.BlockTE;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
/**
* @author shadowfacts
*/
public class BlockFunnel extends BlockTE<TileEntityFunnel> {
public static final PropertyDirection FACING = PropertyDirection.create("facing", side -> side != EnumFacing.UP);
protected static final AxisAlignedBB BASE_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 0.625D, 1.0D);
protected static final AxisAlignedBB SOUTH_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 0.125D);
protected static final AxisAlignedBB NORTH_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.875D, 1.0D, 1.0D, 1.0D);
protected static final AxisAlignedBB WEST_AABB = new AxisAlignedBB(0.875D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D);
protected static final AxisAlignedBB EAST_AABB = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.125D, 1.0D, 1.0D);
public BlockFunnel() {
super(Material.IRON, "funnel");
setCreativeTab(CreativeTabs.MISC);
setHardness(3.5f);
setResistance(8);
setSoundType(SoundType.METAL);
setDefaultState(getDefaultState()
.withProperty(FACING, EnumFacing.DOWN));
}
@Override
public AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) {
return FULL_BLOCK_AABB;
}
@Override
public void addCollisionBoxToList(IBlockState state, World worldIn, BlockPos pos, AxisAlignedBB entityBox, List<AxisAlignedBB> collidingBoxes, @Nullable Entity entityIn) {
addCollisionBoxToList(pos, entityBox, collidingBoxes, BASE_AABB);
addCollisionBoxToList(pos, entityBox, collidingBoxes, EAST_AABB);
addCollisionBoxToList(pos, entityBox, collidingBoxes, WEST_AABB);
addCollisionBoxToList(pos, entityBox, collidingBoxes, SOUTH_AABB);
addCollisionBoxToList(pos, entityBox, collidingBoxes, NORTH_AABB);
}
@Override
protected BlockStateContainer createBlockState() {
return new BlockStateContainer(this, FACING);
}
@Override
public int getMetaFromState(IBlockState state) {
return state.getValue(FACING).getIndex();
}
@Override
public IBlockState getStateFromMeta(int meta) {
return getDefaultState().withProperty(FACING, EnumFacing.getFront(meta));
}
@Override
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer, EnumHand hand) {
EnumFacing side = facing.getOpposite();
if (side == EnumFacing.UP) side = EnumFacing.DOWN;
return getDefaultState().withProperty(FACING, side);
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) {
if (!player.isSneaking()) {
TileEntityFunnel te = getTileEntity(world, pos);
ItemStack stack = player.getHeldItem(hand);
FluidActionResult result = FluidUtil.interactWithFluidHandler(stack, te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, EnumFacing.NORTH), player);
if (result.isSuccess()) {
player.setHeldItem(hand, result.getResult());
te.save();
return true;
}
}
return false;
}
@Override
public boolean isOpaqueCube(IBlockState state) {
return false;
}
@Override
public Class<TileEntityFunnel> getTileEntityClass() {
return TileEntityFunnel.class;
}
@Nonnull
@Override
public TileEntityFunnel createTileEntity(World world, IBlockState state) {
return new TileEntityFunnel();
}
}

View File

@ -1,51 +0,0 @@
package net.shadowfacts.funnels;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fluids.*;
import net.minecraftforge.fluids.capability.IFluidHandler;
/**
* @author shadowfacts
*/
public class FluidUtils {
public static boolean isFluidBlock(World world, BlockPos pos) {
IBlockState state = world.getBlockState(pos);
if (state.getBlock() instanceof BlockLiquid) {
return state.getValue(BlockLiquid.LEVEL) == 0;
}
if (state.getBlock() instanceof IFluidBlock) {
return ((IFluidBlock)state.getBlock()).canDrain(world, pos);
}
return false;
}
public static FluidStack drainFluidBlock(World world, BlockPos pos, boolean doDrain) {
FluidStack stack = null;
IBlockState state = world.getBlockState(pos);
if (state.getBlock() instanceof BlockLiquid && state.getValue(BlockLiquid.LEVEL) == 0) {
if (state.getBlock() == Blocks.WATER || state.getBlock() == Blocks.FLOWING_WATER) {
stack = new FluidStack(FluidRegistry.WATER, Fluid.BUCKET_VOLUME);
if (doDrain) world.setBlockToAir(pos);
} else if (state.getBlock() == Blocks.LAVA|| state.getBlock() == Blocks.FLOWING_LAVA) {
stack = new FluidStack(FluidRegistry.LAVA, Fluid.BUCKET_VOLUME);
if (doDrain) world.setBlockToAir(pos);
}
} else if (state.getBlock() instanceof IFluidBlock) {
stack = ((IFluidBlock)state.getBlock()).drain(world, pos, doDrain);
}
return stack;
}
}

View File

@ -1,49 +0,0 @@
package net.shadowfacts.funnels;
import net.minecraft.init.Items;
import net.minecraft.item.ItemBlock;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.oredict.ShapedOreRecipe;
/**
* @author shadowfacts
*/
@Mod(modid = Funnels.modId, name = Funnels.name, version = Funnels.version, dependencies = "required-after:shadowmc@[3.4.0,);", guiFactory = "net.shadowfacts.funnels.GUIFactory")
public class Funnels {
public static final String modId = "funnels";
public static final String name = "Funnels";
public static final String version = "@VERSION@";
// Content
public static BlockFunnel funnel;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
FunnelsConfig.init(event.getModConfigurationDirectory());
FunnelsConfig.load();
funnel = GameRegistry.register(new BlockFunnel());
GameRegistry.register(new ItemBlock(funnel).setRegistryName(funnel.getRegistryName()));
GameRegistry.registerTileEntity(TileEntityFunnel.class, "funnel");
if (event.getSide() == Side.CLIENT) {
preInitClient();
}
GameRegistry.addRecipe(new ShapedOreRecipe(funnel, "I I", "I I", " B ", 'I', "ingotIron", 'B', Items.BUCKET));
}
@SideOnly(Side.CLIENT)
private void preInitClient() {
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityFunnel.class, new TESRFunnel());
funnel.initItemModel();
}
}

View File

@ -1,35 +0,0 @@
package net.shadowfacts.funnels;
import net.minecraftforge.common.config.Configuration;
import net.shadowfacts.config.Config;
import net.shadowfacts.config.ConfigManager;
import java.io.File;
/**
* @author shadowfacts
*/
@Config(name = Funnels.modId)
public class FunnelsConfig {
static Configuration config;
@Config.Prop
public static int size = 1000;
@Config.Prop
public static boolean pickupWorldFluids = true;
@Config.Prop
public static boolean placeFluidsInWorld = true;
public static void init(File configDir) {
config = new Configuration(new File(configDir, "shadowfacts/Funnels.cfg"));
}
public static void load() {
ConfigManager.load(FunnelsConfig.class, Configuration.class, config);
if (config.hasChanged()) config.save();
}
}

View File

@ -1,15 +0,0 @@
package net.shadowfacts.funnels;
import net.minecraft.client.gui.GuiScreen;
import net.shadowfacts.shadowmc.config.GUIConfig;
/**
* @author shadowfacts
*/
public class FunnelsConfigGUI extends GUIConfig {
public FunnelsConfigGUI(GuiScreen parent) {
super(parent, Funnels.modId, FunnelsConfig.config);
}
}

View File

@ -1,34 +0,0 @@
package net.shadowfacts.funnels;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraftforge.fml.client.IModGuiFactory;
import java.util.Set;
/**
* @author shadowfacts
*/
public class GUIFactory implements IModGuiFactory {
@Override
public void initialize(Minecraft minecraftInstance) {
}
@Override
public Class<? extends GuiScreen> mainConfigGuiClass() {
return FunnelsConfigGUI.class;
}
@Override
public Set<RuntimeOptionCategoryElement> runtimeGuiCategories() {
return null;
}
@Override
public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) {
return null;
}
}

View File

@ -1,34 +0,0 @@
package net.shadowfacts.funnels;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
/**
* @author shadowfacts
*/
public class PlayerUtils {
public static boolean disposePlayerItem(ItemStack stack, ItemStack dropStack, EntityPlayer entityplayer, boolean allowDrop, boolean allowReplace) {
if (entityplayer == null || entityplayer.capabilities.isCreativeMode) {
return true;
}
if (allowReplace && stack.getCount() <= 1) {
entityplayer.inventory.setInventorySlotContents(entityplayer.inventory.currentItem, ItemStack.EMPTY);
entityplayer.inventory.addItemStackToInventory(dropStack);
return true;
} else if (allowDrop) {
stack.shrink(1);
if (dropStack != null && !entityplayer.inventory.addItemStackToInventory(dropStack)) {
entityplayer.dropItem(dropStack, false, true);
}
return true;
}
return false;
}
public static boolean disposePlayerItem(ItemStack stack, ItemStack dropStack, EntityPlayer entityplayer, boolean allowDrop) {
return disposePlayerItem(stack, dropStack, entityplayer, allowDrop, true);
}
}

View File

@ -1,59 +0,0 @@
package net.shadowfacts.funnels;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.VertexBuffer;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.fluids.FluidStack;
import net.shadowfacts.shadowmc.util.RenderHelper;
import org.lwjgl.opengl.GL11;
/**
* @author shadowfacts
*/
public class TESRFunnel extends TileEntitySpecialRenderer<TileEntityFunnel> {
@Override
public void renderTileEntityAt(TileEntityFunnel te, double x, double y, double z, float partialTicks, int destroyStage) {
if (te.tank.getFluid() != null) {
FluidStack fluid = te.tank.getFluid();
Tessellator tessellator = Tessellator.getInstance();
VertexBuffer renderer = tessellator.getBuffer();
renderer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE);
int color = fluid.getFluid().getColor(fluid);
int brightness = Minecraft.getMinecraft().world.getCombinedLight(te.getPos(), fluid.getFluid().getLuminosity());
GlStateManager.pushMatrix();
GlStateManager.disableLighting();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
if (Minecraft.isAmbientOcclusionEnabled()) {
GL11.glShadeModel(GL11.GL_SMOOTH);
} else {
GL11.glShadeModel(GL11.GL_FLAT);
}
GlStateManager.translate(x, y, z);
TextureAtlasSprite still = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(fluid.getFluid().getStill(fluid).toString());
RenderHelper.putTexturedQuad(renderer, still, 2/16d, 14/16d, 2/16d, 12/16d, 0, 12/16d, EnumFacing.UP, color, brightness);
tessellator.draw();
GlStateManager.disableBlend();
GlStateManager.enableLighting();
GlStateManager.popMatrix();
}
}
}

View File

@ -1,114 +0,0 @@
package net.shadowfacts.funnels;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.state.IBlockState;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.shadowfacts.shadowmc.ShadowMC;
import net.shadowfacts.shadowmc.capability.CapHolder;
import net.shadowfacts.shadowmc.fluid.FluidTank;
import net.shadowfacts.shadowmc.nbt.AutoSerializeNBT;
import net.shadowfacts.shadowmc.network.PacketUpdateTE;
import net.shadowfacts.shadowmc.tileentity.BaseTileEntity;
/**
* @author shadowfacts
*/
public class TileEntityFunnel extends BaseTileEntity implements ITickable {
@AutoSerializeNBT
@CapHolder(capabilities = IFluidHandler.class)
FluidTank tank = new FluidTank(FunnelsConfig.size);
private int tick;
void save() {
markDirty();
ShadowMC.network.sendToAllAround(new PacketUpdateTE(this), new NetworkRegistry.TargetPoint(world.provider.getDimension(), pos.getX(), pos.getY(), pos.getZ(), 64));
}
@Override
public void update() {
if (!world.isRemote) {
handlers:
{
// up handler -> tank
if (tank.getFluidAmount() < tank.getCapacity()) {
BlockPos handlerPos = pos.up();
TileEntity te = world.getTileEntity(handlerPos);
if (te != null && te.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, EnumFacing.DOWN)) {
IFluidHandler handler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, EnumFacing.DOWN);
tank.fill(handler.drain(tank.getCapacity() - tank.getFluidAmount(), true), true);
save();
break handlers;
}
}
// tank -> front handler
if (tank.getFluidAmount() > 0) {
EnumFacing facing = world.getBlockState(pos).getValue(BlockFunnel.FACING);
BlockPos handlerPos = pos.offset(facing);
TileEntity te = world.getTileEntity(handlerPos);
if (te != null && te.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, facing.getOpposite())) {
IFluidHandler handler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, facing.getOpposite());
tank.drain(handler.fill(tank.drain(20, false), true), true);
save();
}
}
}
tick++;
if (tick % 40 == 0) {
// pickup from world
if (FunnelsConfig.pickupWorldFluids && tank.getFluidAmount() <= tank.getCapacity() - Fluid.BUCKET_VOLUME) {
tick = 0;
if (FluidUtils.isFluidBlock(world, pos.up())) {
FluidStack toDrain = FluidUtils.drainFluidBlock(world, pos.up(), false);
if (toDrain.amount <= tank.getCapacity() - tank.getFluidAmount()) {
tank.fill(FluidUtils.drainFluidBlock(world, pos.up(), true), true);
save();
return;
}
}
}
// place in world
if (FunnelsConfig.placeFluidsInWorld && tank.getFluidAmount() >= Fluid.BUCKET_VOLUME) {
FluidStack fluid = tank.getFluid();
if (fluid.getFluid().canBePlacedInWorld()) {
Block fluidBlock = fluid.getFluid().getBlock();
if (fluidBlock instanceof BlockLiquid) fluidBlock = BlockLiquid.getFlowingBlock(fluidBlock.getMaterial(fluidBlock.getDefaultState()));
BlockPos newPos = pos.offset(world.getBlockState(pos).getValue(BlockFunnel.FACING));
if (fluidBlock.canPlaceBlockAt(world, newPos)) {
tank.drain(Fluid.BUCKET_VOLUME, true);
save();
world.setBlockState(newPos, fluidBlock.getDefaultState());
}
}
}
}
}
}
@Override
public void readFromNBT(NBTTagCompound tag) {
super.readFromNBT(tag);
tank.readFromNBT(tag);
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound tag) {
super.writeToNBT(tag);
tank.writeToNBT(tag);
return tag;
}
}

View File

@ -0,0 +1,71 @@
package net.shadowfacts.extrahoppers
import net.minecraftforge.common.config.Configuration
import net.minecraftforge.common.config.Property
import java.io.File
import kotlin.reflect.KProperty
/**
* @author shadowfacts
*/
object EHConfig {
internal lateinit var config: Configuration
private set
// Config values
// Fluid Hopper
var fhSize: Int by ConfigInt("fluidHopper", "size", 1000, 1000, 64000, "The size (in millibuckets) of the Fluid Hopper")
var fhPickupWorldFluids: Boolean by ConfigBool("fluidHopper", "fhPickupWorldFluids", true, "If the Fluid Hopper should pickup fluids placed in the world directly above it.")
var fhPlaceFluidsInWorld: Boolean by ConfigBool("fluidHopper", "fhPlaceFluidsInWorld", true, "If the Fluid Hopper should place fluids in the world directly in front of it.")
fun init(configDir: File) {
config = Configuration(File(configDir, "shadowfacts/ExtraHoppers.cfg"))
val legacy = File(configDir, "shadowfacts/Funnels.cfg")
if (legacy.exists()) {
migrateLegacy(Configuration(legacy))
}
}
private fun migrateLegacy(legacy: Configuration) {
fhSize = legacy.get("general", "size", 1000, "").int
fhPickupWorldFluids = legacy.get("general", "pickupWorldFluids", true, "").boolean
fhPlaceFluidsInWorld = legacy.get("general", "placeFluidsInWorld", true, "").boolean
}
fun save() {
if (config.hasChanged()) {
config.save()
}
}
private class ConfigInt(val category: String, val name: String, val default: Int, val minValue: Int, val maxValue: Int, val comment: String) {
private val prop: Property
get() = config.get(category, name, default, comment, minValue, maxValue)
operator fun getValue(instance: Any, property: KProperty<*>): Int {
return prop.int
}
operator fun setValue(instance: Any, property: KProperty<*>, value: Int) {
prop.set(value)
}
}
private class ConfigBool(val category: String, val name: String, val default: Boolean, val comment: String) {
private val prop: Property
get() = config.get(category, name, default, comment)
operator fun getValue(instance: Any, property: KProperty<*>): Boolean {
return prop.boolean
}
operator fun setValue(instance: Any, property: KProperty<*>, value: Boolean) {
prop.set(value)
}
}
}

View File

@ -0,0 +1,16 @@
package net.shadowfacts.extrahoppers
import net.minecraft.creativetab.CreativeTabs
import net.minecraft.item.ItemStack
/**
* @author shadowfacts
*/
object EHCreativeTab: CreativeTabs(MOD_ID) {
override fun getTabIconItem(): ItemStack {
return ItemStack(ExtraHoppers.blocks.fluidHopper)
// TODO: change me to the wooden hopper
}
}

View File

@ -0,0 +1,57 @@
package net.shadowfacts.extrahoppers
import net.minecraft.item.Item
import net.minecraftforge.fml.client.registry.ClientRegistry
import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.common.event.FMLMissingMappingsEvent
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent
import net.minecraftforge.fml.common.network.NetworkRegistry
import net.minecraftforge.fml.common.registry.GameRegistry
import net.minecraftforge.fml.relauncher.Side
import net.minecraftforge.fml.relauncher.SideOnly
import net.shadowfacts.extrahoppers.block.ModBlocks
import net.shadowfacts.extrahoppers.block.fluid.TileEntityFluidHopper
import net.shadowfacts.extrahoppers.block.fluid.TESRFluidHopper
import net.shadowfacts.extrahoppers.gui.GUIHandler
/**
* @author shadowfacts
*/
@Mod(modid = MOD_ID, name = NAME, version = VERSION, dependencies = "required-after:shadowmc;", modLanguageAdapter = "net.shadowfacts.forgelin.KotlinAdapter", guiFactory = "net.shadowfacts.extrahoppers.gui.EHGUIFactory")
object ExtraHoppers {
// Content
val blocks = ModBlocks
@Mod.EventHandler
fun preInit(event: FMLPreInitializationEvent) {
EHConfig.init(event.modConfigurationDirectory)
EHConfig.save()
blocks.init()
ModRecipes.init()
NetworkRegistry.INSTANCE.registerGuiHandler(ExtraHoppers, GUIHandler)
}
@Mod.EventHandler
@SideOnly(Side.CLIENT)
fun preInitClient(event: FMLPreInitializationEvent) {
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityFluidHopper::class.java, TESRFluidHopper)
}
@Mod.EventHandler
fun missingMappings(event: FMLMissingMappingsEvent) {
event.get().forEach {
if (it.name == "funnels:funnel") {
if (it.type == GameRegistry.Type.BLOCK) {
it.remap(blocks.fluidHopper)
} else {
it.remap(Item.getItemFromBlock(blocks.fluidHopper))
}
}
}
}
}

View File

@ -0,0 +1,16 @@
package net.shadowfacts.extrahoppers
import net.minecraft.init.Items
import net.minecraftforge.fml.common.registry.GameRegistry
import net.minecraftforge.oredict.ShapedOreRecipe
/**
* @author shadowfacts
*/
object ModRecipes {
fun init() {
GameRegistry.addRecipe(ShapedOreRecipe(ExtraHoppers.blocks.fluidHopper, "I I", "I I", " B ", 'I', "ingotIron", 'B', Items.BUCKET))
}
}

View File

@ -0,0 +1,8 @@
package net.shadowfacts.extrahoppers
/**
* @author shadowfacts
*/
const val MOD_ID = "extrahoppers"
const val NAME = "Extra Hoppers"
const val VERSION = "@VERSION@"

View File

@ -0,0 +1,34 @@
package net.shadowfacts.extrahoppers.block
import net.minecraft.block.material.Material
import net.minecraft.block.state.IBlockState
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
import net.shadowfacts.extrahoppers.EHCreativeTab
import net.shadowfacts.shadowmc.block.BlockBase
import net.shadowfacts.shadowmc.tileentity.BaseTileEntity
/**
* @author shadowfacts
*/
abstract class BlockTE<out TE: BaseTileEntity>(name: String, material: Material = Material.ROCK): BlockBase(material, name) {
init {
unlocalizedName = registryName.toString()
setCreativeTab(EHCreativeTab)
}
abstract fun registerTileEntity()
abstract override fun createTileEntity(world: World, state: IBlockState): TE
override fun hasTileEntity(state: IBlockState): Boolean {
return true
}
fun getTileEntity(world: IBlockAccess, pos: BlockPos): TE {
return world.getTileEntity(pos) as TE
}
}

View File

@ -0,0 +1,25 @@
package net.shadowfacts.extrahoppers.block
import net.minecraft.block.Block
import net.shadowfacts.extrahoppers.block.fluid.BlockFluidHopper
import net.shadowfacts.shadowmc.block.ModBlocks
/**
* @author shadowfacts
*/
object ModBlocks: ModBlocks() {
val fluidHopper = BlockFluidHopper()
override fun init() {
register(fluidHopper)
}
override fun <T: Block> register(block: T): T {
if (block is BlockTE<*>) {
block.registerTileEntity()
}
return super.register(block)
}
}

View File

@ -0,0 +1,76 @@
package net.shadowfacts.extrahoppers.block.base
import net.minecraft.block.material.Material
import net.minecraft.block.properties.PropertyDirection
import net.minecraft.block.state.BlockStateContainer
import net.minecraft.block.state.IBlockState
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityLivingBase
import net.minecraft.util.EnumFacing
import net.minecraft.util.EnumHand
import net.minecraft.util.math.AxisAlignedBB
import net.minecraft.util.math.BlockPos
import net.minecraft.world.IBlockAccess
import net.minecraft.world.World
import net.shadowfacts.extrahoppers.block.BlockTE
import net.shadowfacts.shadowmc.tileentity.BaseTileEntity
/**
* @author shadowfacts
*/
abstract class BlockHopperBase<out TE: BaseTileEntity>(name: String, material: Material = Material.ROCK): BlockTE<TE>(name, material = material) {
companion object {
val FACING: PropertyDirection = PropertyDirection.create("facing") { side -> side != EnumFacing.UP }
val BASE_AABB = AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 0.625, 1.0)
val SOUTH_AABB = AxisAlignedBB(0.0, 0.0, 0.0, 1.0, 1.0, 0.125)
val NORTH_AABB = AxisAlignedBB(0.0, 0.0, 0.875, 1.0, 1.0, 1.0)
val WEST_AABB = AxisAlignedBB(0.875, 0.0, 0.0, 1.0, 1.0, 1.0)
val EAST_AABB = AxisAlignedBB(0.0, 0.0, 0.0, 0.125, 1.0, 1.0)
}
init {
defaultState = defaultState.withProperty(FACING, EnumFacing.DOWN)
}
@Deprecated("")
override fun getBoundingBox(state: IBlockState, source: IBlockAccess, pos: BlockPos): AxisAlignedBB {
return FULL_BLOCK_AABB
}
@Deprecated("")
override fun addCollisionBoxToList(state: IBlockState, world: World, pos: BlockPos, entityBox: AxisAlignedBB, collidingBoxes: List<AxisAlignedBB>, entity: Entity?) {
addCollisionBoxToList(pos, entityBox, collidingBoxes, BASE_AABB)
addCollisionBoxToList(pos, entityBox, collidingBoxes, EAST_AABB)
addCollisionBoxToList(pos, entityBox, collidingBoxes, WEST_AABB)
addCollisionBoxToList(pos, entityBox, collidingBoxes, SOUTH_AABB)
addCollisionBoxToList(pos, entityBox, collidingBoxes, NORTH_AABB)
}
override fun createBlockState(): BlockStateContainer {
return BlockStateContainer(this, FACING)
}
override fun getMetaFromState(state: IBlockState): Int {
return state.getValue(FACING).index
}
@Deprecated("")
override fun getStateFromMeta(meta: Int): IBlockState {
return defaultState.withProperty(FACING, EnumFacing.getFront(meta))
}
override fun getStateForPlacement(world: World, pos: BlockPos, facing: EnumFacing, hitX: Float, hitY: Float, hitZ: Float, meta: Int, placer: EntityLivingBase, hand: EnumHand): IBlockState {
var side = facing.opposite
if (side == EnumFacing.UP) side = EnumFacing.DOWN
return defaultState.withProperty(FACING, side)
}
@Deprecated("")
override fun isOpaqueCube(state: IBlockState?): Boolean {
return false
}
}

View File

@ -0,0 +1,15 @@
package net.shadowfacts.extrahoppers.block.base
import net.minecraft.util.EnumFacing
import net.shadowfacts.shadowmc.tileentity.BaseTileEntity
/**
* @author shadowfacts
*/
abstract class TileEntityHopperBase: BaseTileEntity() {
fun getHopperFacing(): EnumFacing {
return world.getBlockState(pos).getValue(BlockHopperBase.FACING)
}
}

View File

@ -0,0 +1,56 @@
package net.shadowfacts.extrahoppers.block.fluid
import net.minecraft.block.SoundType
import net.minecraft.block.material.Material
import net.minecraft.block.state.IBlockState
import net.minecraft.client.resources.I18n
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.item.ItemStack
import net.minecraft.util.EnumFacing
import net.minecraft.util.EnumHand
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import net.minecraftforge.fluids.FluidUtil
import net.minecraftforge.fluids.capability.CapabilityFluidHandler
import net.minecraftforge.fml.common.registry.GameRegistry
import net.shadowfacts.extrahoppers.block.base.BlockHopperBase
/**
* @author shadowfacts
*/
class BlockFluidHopper: BlockHopperBase<TileEntityFluidHopper>("fluid_hopper", material = Material.IRON) {
init {
setHardness(3.5f)
setResistance(8f)
soundType = SoundType.METAL
}
override fun onBlockActivated(world: World, pos: BlockPos, state: IBlockState, player: EntityPlayer, hand: EnumHand, side: EnumFacing, hitX: Float, hitY: Float, hitZ: Float): Boolean {
// TODO: GUI
if (!player.isSneaking) {
val te = getTileEntity(world, pos)
val stack = player.getHeldItem(hand)
val result = FluidUtil.interactWithFluidHandler(stack, te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, EnumFacing.NORTH), player)
if (result.isSuccess) {
player.setHeldItem(hand, result.getResult())
te.save()
return true
}
}
return false
}
override fun addInformation(stack: ItemStack, player: EntityPlayer, tooltip: MutableList<String>, advanced: Boolean) {
tooltip.add(I18n.format("$unlocalizedName.tooltip"))
}
override fun registerTileEntity() {
GameRegistry.registerTileEntityWithAlternatives(TileEntityFluidHopper::class.java, registryName.toString(), "funnels:funnel")
}
override fun createTileEntity(world: World, state: IBlockState): TileEntityFluidHopper {
return TileEntityFluidHopper()
}
}

View File

@ -0,0 +1,59 @@
package net.shadowfacts.extrahoppers.block.fluid
import net.minecraft.client.Minecraft
import net.minecraft.client.renderer.GlStateManager
import net.minecraft.client.renderer.Tessellator
import net.minecraft.client.renderer.VertexBuffer
import net.minecraft.client.renderer.texture.TextureAtlasSprite
import net.minecraft.client.renderer.texture.TextureMap
import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer
import net.minecraft.client.renderer.vertex.DefaultVertexFormats
import net.minecraft.util.EnumFacing
import net.minecraftforge.fluids.FluidStack
import net.shadowfacts.extrahoppers.block.fluid.TileEntityFluidHopper
import net.shadowfacts.shadowmc.util.RenderHelper
import org.lwjgl.opengl.GL11
/**
* @author shadowfacts
*/
object TESRFluidHopper: TileEntitySpecialRenderer<TileEntityFluidHopper>() {
override fun renderTileEntityAt(te: TileEntityFluidHopper, x: Double, y: Double, z: Double, partialTicks: Float, destroyStage: Int) {
if (te.tank.fluid != null) {
val fluid = te.tank.fluid
val tessellator = Tessellator.getInstance()
val renderer = tessellator.buffer
renderer.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK)
Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.LOCATION_BLOCKS_TEXTURE)
val color = fluid!!.fluid.getColor(fluid)
val brightness = Minecraft.getMinecraft().world.getCombinedLight(te.pos, fluid.fluid.luminosity)
GlStateManager.pushMatrix()
GlStateManager.disableLighting()
GlStateManager.enableBlend()
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA)
if (Minecraft.isAmbientOcclusionEnabled()) {
GL11.glShadeModel(GL11.GL_SMOOTH)
} else {
GL11.glShadeModel(GL11.GL_FLAT)
}
GlStateManager.translate(x, y, z)
val still = Minecraft.getMinecraft().textureMapBlocks.getAtlasSprite(fluid.fluid.getStill(fluid).toString())
RenderHelper.putTexturedQuad(renderer, still, 2 / 16.0, 14 / 16.0, 2 / 16.0, 12 / 16.0, 0.0, 12 / 16.0, EnumFacing.UP, color, brightness)
tessellator.draw()
GlStateManager.disableBlend()
GlStateManager.enableLighting()
GlStateManager.popMatrix()
}
}
}

View File

@ -0,0 +1,149 @@
package net.shadowfacts.extrahoppers.block.fluid
import net.minecraft.block.BlockLiquid
import net.minecraft.nbt.NBTTagCompound
import net.minecraft.util.EnumFacing
import net.minecraft.util.ITickable
import net.minecraftforge.fluids.Fluid.BUCKET_VOLUME
import net.minecraftforge.fluids.capability.CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY
import net.minecraftforge.fluids.capability.IFluidHandler
import net.minecraftforge.fml.common.network.NetworkRegistry
import net.shadowfacts.extrahoppers.util.FluidUtils
import net.shadowfacts.extrahoppers.EHConfig
import net.shadowfacts.extrahoppers.block.base.TileEntityHopperBase
import net.shadowfacts.shadowmc.ShadowMC
import net.shadowfacts.shadowmc.capability.CapHolder
import net.shadowfacts.shadowmc.fluid.FluidTank
import net.shadowfacts.shadowmc.nbt.AutoSerializeNBT
import net.shadowfacts.shadowmc.network.PacketUpdateTE
/**
* @author shadowfacts
*/
class TileEntityFluidHopper: TileEntityHopperBase(), ITickable {
companion object {
val HANDLER_COOLDOWN = 8
val WORLD_COOLDOWN = 40
}
@AutoSerializeNBT
@CapHolder(capabilities = arrayOf(IFluidHandler::class))
internal var tank = FluidTank(EHConfig.fhSize)
private var handlerCooldown: Int = HANDLER_COOLDOWN
private var worldCooldown: Int = WORLD_COOLDOWN
internal fun save() {
markDirty()
ShadowMC.network.sendToAllAround(PacketUpdateTE(this), NetworkRegistry.TargetPoint(world.provider.dimension, pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble(), 64.0))
}
override fun update() {
if (!world.isRemote) {
// TODO: redstone me
handlerCooldown--
if (handlerCooldown <= 0) {
handleFluidHandlers()
}
worldCooldown--
if (worldCooldown <= 0) {
handleWorld()
}
}
}
private fun handleFluidHandlers() {
val transferOut = transferOut()
val transferIn = transferIn()
if (transferOut || transferIn) {
handlerCooldown = HANDLER_COOLDOWN
save()
}
}
private fun transferIn(): Boolean {
if (tank.fluidAmount < tank.capacity) {
val handlerPos = pos.up()
val te = world.getTileEntity(handlerPos)
if (te != null && te.hasCapability(FLUID_HANDLER_CAPABILITY, EnumFacing.DOWN)) {
val handler = te.getCapability(FLUID_HANDLER_CAPABILITY, EnumFacing.DOWN)
tank.fill(handler!!.drain(tank.capacity - tank.fluidAmount, true), true)
return true
}
}
return false
}
private fun transferOut(): Boolean {
if (tank.fluidAmount > 0) {
val facing = getHopperFacing()
val handlerPos = pos.offset(facing)
val te = world.getTileEntity(handlerPos)
if (te != null && te.hasCapability(FLUID_HANDLER_CAPABILITY, facing.opposite)) {
val handler = te.getCapability(FLUID_HANDLER_CAPABILITY, facing.opposite)
tank.drain(handler!!.fill(tank.drain(20, false), true), true)
return true
}
}
return false
}
private fun handleWorld() {
val pickup = pickupFromWorld()
val place = placeInWorld()
if (pickup || place) {
worldCooldown = WORLD_COOLDOWN
save()
}
}
private fun pickupFromWorld(): Boolean {
if (EHConfig.fhPickupWorldFluids && tank.fluidAmount <= tank.capacity - BUCKET_VOLUME) {
if (FluidUtils.isFluidBlock(world, pos.up())) {
val toDrain = FluidUtils.drainFluidBlock(world, pos.up(), false)!!
if (toDrain.amount <= tank.capacity - tank.fluidAmount) {
tank.fill(FluidUtils.drainFluidBlock(world, pos.up(), true), true)
return true
}
}
}
return false
}
private fun placeInWorld(): Boolean {
if (EHConfig.fhPlaceFluidsInWorld && tank.fluidAmount >= BUCKET_VOLUME) {
val fluid = tank.fluid
if (fluid!!.fluid.canBePlacedInWorld()) {
var fluidBlock = fluid.fluid.block
if (fluidBlock is BlockLiquid) fluidBlock = BlockLiquid.getFlowingBlock(fluidBlock.getDefaultState().material)
val newPos = pos.offset(getHopperFacing())
if (fluidBlock.canPlaceBlockAt(world, newPos)) {
tank.drain(BUCKET_VOLUME, true)
world.setBlockState(newPos, fluidBlock.defaultState)
return true
}
}
}
return false
}
override fun writeToNBT(tag: NBTTagCompound): NBTTagCompound {
tank.writeToNBT(tag)
tag.setInteger("handlerCooldown", handlerCooldown)
tag.setInteger("worldCooldown", worldCooldown)
return super.writeToNBT(tag)
}
override fun readFromNBT(tag: NBTTagCompound) {
tank.readFromNBT(tag)
handlerCooldown = tag.getInteger("handlerCooldown")
worldCooldown = tag.getInteger("worldCooldown")
super.readFromNBT(tag)
}
}

View File

@ -0,0 +1,11 @@
package net.shadowfacts.extrahoppers.gui
import net.minecraft.client.gui.GuiScreen
import net.shadowfacts.extrahoppers.EHConfig
import net.shadowfacts.extrahoppers.MOD_ID
import net.shadowfacts.shadowmc.config.GUIConfig
/**
* @author shadowfacts
*/
class EHConfigGUI(parent: GuiScreen): GUIConfig(parent, MOD_ID, EHConfig.config)

View File

@ -0,0 +1,29 @@
package net.shadowfacts.extrahoppers.gui
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.GuiScreen
import net.minecraftforge.fml.client.IModGuiFactory
import net.shadowfacts.extrahoppers.gui.EHConfigGUI
/**
* @author shadowfacts
*/
class EHGUIFactory: IModGuiFactory {
override fun initialize(minecraftInstance: Minecraft) {
}
override fun mainConfigGuiClass(): Class<out GuiScreen> {
return EHConfigGUI::class.java
}
override fun runtimeGuiCategories(): Set<IModGuiFactory.RuntimeOptionCategoryElement>? {
return null
}
override fun getHandlerFor(element: IModGuiFactory.RuntimeOptionCategoryElement): IModGuiFactory.RuntimeOptionGuiHandler? {
return null
}
}

View File

@ -0,0 +1,29 @@
package net.shadowfacts.extrahoppers.gui
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.Container
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import net.minecraftforge.fml.common.network.IGuiHandler
/**
* @author shadowfacts
*/
object GUIHandler: IGuiHandler {
val FLUID_HOPPER = 0
override fun getClientGuiElement(ID: Int, player: EntityPlayer, world: World, x: Int, y: Int, z: Int): Any? {
return when (ID) {
else -> null
}
}
override fun getServerGuiElement(ID: Int, player: EntityPlayer, world: World, x: Int, y: Int, z: Int): Container? {
val pos = BlockPos(x, y, z)
return when (ID) {
else -> null
}
}
}

View File

@ -0,0 +1,48 @@
package net.shadowfacts.extrahoppers.util
import net.minecraft.block.BlockLiquid
import net.minecraft.init.Blocks
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import net.minecraftforge.fluids.Fluid
import net.minecraftforge.fluids.FluidRegistry
import net.minecraftforge.fluids.FluidStack
import net.minecraftforge.fluids.IFluidBlock
/**
* @author shadowfacts
*/
object FluidUtils {
fun isFluidBlock(world: World, pos: BlockPos): Boolean {
val state = world.getBlockState(pos)
if (state.block is BlockLiquid) {
return state.getValue(BlockLiquid.LEVEL) == 0
}
if (state.block is IFluidBlock) {
return (state.block as IFluidBlock).canDrain(world, pos)
}
return false
}
fun drainFluidBlock(world: World, pos: BlockPos, doDrain: Boolean): FluidStack? {
var stack: FluidStack? = null
val state = world.getBlockState(pos)
if (state.block is BlockLiquid && state.getValue(BlockLiquid.LEVEL) == 0) {
if (state.block === Blocks.WATER || state.block === Blocks.FLOWING_WATER) {
stack = FluidStack(FluidRegistry.WATER, Fluid.BUCKET_VOLUME)
if (doDrain) world.setBlockToAir(pos)
} else if (state.block === Blocks.LAVA || state.block === Blocks.FLOWING_LAVA) {
stack = FluidStack(FluidRegistry.LAVA, Fluid.BUCKET_VOLUME)
if (doDrain) world.setBlockToAir(pos)
}
} else if (state.block is IFluidBlock) {
stack = (state.block as IFluidBlock).drain(world, pos, doDrain)
}
return stack
}
}

View File

@ -0,0 +1,5 @@
tile.extrahoppers:fluid_hopper.name=Fluid Hopper
tile.extrahoppers:fluid_hopper.tooltip=Formerly the Funnel
extrahoppers.config.gui.title=Extra Hoppers Config
extrahoppers.config.gui.category.general=General

View File

@ -1,4 +0,0 @@
tile.funnel.name=Funnel
Funnels.config.gui.title=Funnels Config
Funnels.config.gui.category.general=General

View File

@ -1,12 +1,12 @@
[ [
{ {
"modid": "Funnels", "modid": "extrahoppers",
"name": "Funnels", "name": "Extra Hoppers",
"version": "$version", "version": "$version",
"mcversion": "$mcversion", "mcversion": "$mcversion",
"description": "Fantastic Fluid funnels", "description": "Extra hoppers and Fantastic Fluid Funnels™",
"credits": "", "credits": "",
"url": "https://github.com/shadowfacts/Funnels", "url": "https://github.com/shadowfacts/ExtraHoppers",
"updateUrl": "", "updateUrl": "",
"authorList": [ "shadowfacts" ], "authorList": [ "shadowfacts" ],
"screenshots": [] "screenshots": []