v1.0.17 release merge.

This commit is contained in:
stfwi 2019-12-29 00:40:01 +01:00
commit 49861d8f0f
1091 changed files with 33006 additions and 384 deletions

View file

@ -4,4 +4,4 @@ org.gradle.jvmargs=-Xmx8G
version_minecraft=1.12.2
version_forge=14.23.5.2768
version_jei=4.10.0.198
version_engineersdecor=1.0.16
version_engineersdecor=1.0.17

View file

@ -1,6 +1,10 @@
{
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
"1.12.2": {
"1.0.17": "[R] Release based on v1.0.17-b3. Release-to-release changes: * Milking machine added. * Reverse recipes for slab slices added. * Texture and model improvements. * Lang file updates. * Minor bug fixes. * Config options added.\n[M] Updated zh_cn lang file (scikirbypoke).\n[A] Added opt-out config for the Small Tree Cutter.",
"1.0.17-b3": "[F] Fixed Small Block Breaker facings to the horizontal range (issue #70, thx JimMiningWorm).",
"1.0.17-b2": "[A] Reverse recipes for slabs and slab slices added.\n[M] Inset Floor Edge Light slightly thinner, looks better.",
"1.0.17-b1": "[A] Added Milking Machine.\n[M] Window placement improved.\n[M] Made Pipe Valve textures slightly darker to fit IE pipes better when shaded.",
"1.0.16": "[R] Release based on v1.0.16-b3. Release-to-release changes: * Added Gas Concrete blocks/walls/stairs/slabs/slab slices. * Added Fluid Collection Funnel * Crafting yield for Clinker/Slag bricks increased. * Block Placer improvements (cocoa planting) and fixes. * Block breaker compat improvements and fixes. * Recipe compat auto detection fixes. * Feature opt-out and tweak config options for mod packs improved.",
"1.0.16-b3": "[M] Increased slag brick recipe yield to 8.\n[A] Small Block Placer can plant Cocoa.\n[F] Fixed Small Block Placer seed detection issue (issue #64, thx Federsavo).\n[F] Fixed incorrectly enabled alternative recipes for fluid accumulator and check valve when IE is installed.\n[M] Slightly nerfed the Small Solar Panel default peak power output (does not affect existing configurations).",
"1.0.16-b2": "[A] Added Gas Concrete (including slab, wall, stairs, and slab slice).\n[A] Added explicit RF-power-required option for Small Block Breaker and Small Tree Cutter (issue #63).\n[M] Increased clinker brick recipe yield to 8 for the master builders needs.\n[F] Fixed item-on-ground display glitch (issue #61, thx Federsavo for the hint).\n[F] Fixed sign bounding boxes (issue #62, thx angela/themartin).",
@ -69,7 +73,7 @@
"1.0.0-b1": "[A] Initial structure.\n[A] Added clinker bricks and clinker brick stairs.\n[A] Added slag bricks and slag brick stairs.\n[A] Added metal rung ladder.\n[A] Added staggered metal steps ladder.\n[A] Added treated wood ladder.\n[A] Added treated wood pole.\n[A] Added treated wood table."
},
"promos": {
"1.12.2-recommended": "1.0.16",
"1.12.2-latest": "1.0.16"
"1.12.2-recommended": "1.0.17",
"1.12.2-latest": "1.0.17"
}
}

View file

@ -10,6 +10,27 @@ Mod sources for Minecraft version 1.12.2.
----
## Version history
-------------------------------------------------------------------
- v1.0.17 [R] Release based on v1.0.17-b3. Release-to-release changes:
* Milking machine added.
* Reverse recipes for slab slices added.
* Texture and model improvements.
* Lang file updates.
* Minor bug fixes.
* Config options added.
-------------------------------------------------------------------
[M] Updated zh_cn lang file (scikirbypoke).
[A] Added opt-out config for the Small Tree Cutter.
- v1.0.17-b3 [F] Fixed Small Block Breaker facings to the horizontal range (issue #70, thx JimMiningWorm).
- v1.0.17-b2 [A] Reverse recipes for slabs and slab slices added.
[M] Inset Floor Edge Light slightly thinner, looks better.
- v1.0.17-b1 [A] Added Milking Machine.
[M] Window placement improved.
[M] Made Pipe Valve textures slightly darker to fit IE pipes better when shaded.
-------------------------------------------------------------------
- v1.0.16 [R] Release based on v1.0.16-b3. Release-to-release changes:
* Added Gas Concrete blocks/walls/stairs/slabs/slab slices.

View file

@ -12,12 +12,11 @@
*/
package wile.engineersdecor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import wile.engineersdecor.blocks.*;
import wile.engineersdecor.detail.ModAuxiliaries;
import wile.engineersdecor.detail.ModConfig;
import wile.engineersdecor.detail.ModTesrs;
import wile.engineersdecor.items.ItemDecor;
import net.minecraft.block.Block;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
@ -32,11 +31,11 @@ import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.common.registry.GameRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import wile.engineersdecor.blocks.*;
import wile.engineersdecor.detail.ModAuxiliaries;
import wile.engineersdecor.detail.ModConfig;
import wile.engineersdecor.detail.ModTesrs;
import wile.engineersdecor.items.ItemDecor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
@SuppressWarnings("unused")
public class ModContent
@ -545,6 +544,7 @@ public class ModContent
STRAIGHT_CHECK_VALVE, STRAIGHT_REDSTONE_VALVE, STRAIGHT_REDSTONE_ANALOG_VALVE, STRAIGHT_PIPE_VALVE_TEI,
SMALL_FLUID_FUNNEL,SMALL_FLUID_FUNNEL_TEI,
PASSIVE_FLUID_ACCUMULATOR, PASSIVE_FLUID_ACCUMULATOR_TEI,
SMALL_MILKING_MACHINE,SMALL_MILKING_MACHINE_TEI,
CLINKER_BRICK_BLOCK,
CLINKER_BRICK_SLAB,
CLINKER_BRICK_STAIRS,
@ -603,7 +603,6 @@ public class ModContent
PANZERGLASS_SLAB, // @todo: check if another class is needed due to is_side_visible
TREATED_WOOD_FLOOR, // @todo: check if textures need improvement
TEST_BLOCK,TEST_BLOCK_TEI,
SMALL_MILKING_MACHINE,SMALL_MILKING_MACHINE_TEI
};
//--------------------------------------------------------------------------------------------------------------------

View file

@ -35,7 +35,7 @@ import java.util.HashSet;
import java.util.Random;
public class BlockDecorBreaker extends BlockDecorDirected
public class BlockDecorBreaker extends BlockDecorDirectedHorizontal
{
public static final PropertyBool ACTIVE = PropertyBool.create("active");

View file

@ -262,11 +262,11 @@ public class BlockDecorPlacer extends BlockDecorDirected
}
// player slots
for(int x=0; x<9; ++x) {
addSlotToContainer(new Slot(playerInventory, x, 8+x*18, 129)); // player slots: 0..8
addSlotToContainer(new Slot(playerInventory, x, 9+x*18, 129)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlotToContainer(new Slot(playerInventory, x+y*9+9, 8+x*18, 71+y*18)); // player slots: 9..35
addSlotToContainer(new Slot(playerInventory, x+y*9+9, 9+x*18, 71+y*18)); // player slots: 9..35
}
}
}

View file

@ -11,11 +11,14 @@ package wile.engineersdecor.blocks;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.BlockRenderLayer;
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.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import javax.annotation.Nonnull;
@ -23,7 +26,6 @@ import javax.annotation.Nullable;
public class BlockDecorWindow extends BlockDecorDirected
{
public BlockDecorWindow(@Nonnull String registryName, long config, @Nullable Material material, float hardness, float resistance, @Nullable SoundType sound, @Nonnull AxisAlignedBB unrotatedAABB)
{ super(registryName, config, material, hardness, resistance, sound, unrotatedAABB); }
@ -58,4 +60,22 @@ public class BlockDecorWindow extends BlockDecorDirected
public boolean doesSideBlockRendering(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing face)
{ return false; }
@Override
public IBlockState getStateForPlacement(World world, BlockPos pos, EnumFacing facing, float hitX, float hitY, float hitZ, int meta, EntityLivingBase placer, EnumHand hand)
{
facing = placer.getHorizontalFacing();
if(Math.abs(placer.getLookVec().y) > 0.9) {
facing = EnumFacing.getDirectionFromEntityLiving(pos, placer);
} else {
for(EnumFacing f: EnumFacing.values()) {
IBlockState st = world.getBlockState(pos.offset(f));
if(st.getBlock() == this) {
facing = st.getValue(FACING);
break;
}
}
}
return getDefaultState().withProperty(FACING, facing);
}
}

View file

@ -213,6 +213,11 @@ public class ModConfig
@Config.RequiresMcRestart
public boolean without_mineral_smelter = false;
@Config.Comment({"Disable the Small Tree Cutter."})
@Config.Name("Without tree cutter")
@Config.RequiresMcRestart
public boolean without_treecutter = false;
@Config.Comment({"Disable the Small Mikling Machine."})
@Config.Name("Without milking machine")
@Config.RequiresMcRestart
@ -534,6 +539,7 @@ public class ModConfig
if(block instanceof BlockDecorMineralSmelter) return optout.without_mineral_smelter;
if(block instanceof BlockDecorMilker) return optout.without_milker;
if(block instanceof BlockDecorPipeValve) return optout.without_valves;
if(block instanceof BlockDecorTreeCutter) return optout.without_treecutter;
// Type based evaluation where later filters may match, too
if(optout.without_slabs && (block instanceof BlockDecorSlab)) return true;

View file

@ -73,7 +73,7 @@ public class RecipeCondModSpecific implements IConditionFactory
return RECIPE_INCLUDE; // no missing given, means include if result and required are all there.
}
} catch(Throwable ex) {
ModEngineersDecor.logger.error("rsgauges::ResultRegisteredCondition failed: " + ex.toString());
ModEngineersDecor.logger.error("ResultRegisteredCondition failed: " + ex.toString());
}
return exclude(); // skip on exception.
}

View file

@ -6,7 +6,7 @@
"variants": {
"normal": [{}],
"inventory": [{}],
"facing": { "north":{"y":0}, "south":{"y":180}, "west":{"y":270}, "east":{"y":90}, "up": {"x":-90}, "down": {"x":90} },
"facing": { "north":{"y":0}, "south":{"y":180}, "west":{"y":270}, "east":{"y":90} },
"active": { "true":{ "model": "engineersdecor:device/small_block_breaker_model_active" }, "false":{}}
}
}

View file

@ -9,8 +9,8 @@ engineersdecor.tooltip.hint.extended=§6[§9SHIFT§r 查看更多信息§6]§r
engineersdecor.tooltip.hint.help=§6[§9CTRL-SHIFT§r 查看帮助§6]§r
engineersdecor.tooltip.slabpickup.help=§r手持同类台阶往上/下看时单击该台阶可无需破坏快速拾起。
#-----------------------------------------------------------------------------------------------------------
engineersdecor.tooltip.requires_rf_power=Requires RF power.
engineersdecor.tooltip.massive_speed_boost_with_rf_power=Apply RF power to magnificently increase the speed.
engineersdecor.tooltip.requires_rf_power=需要RF能量。
engineersdecor.tooltip.massive_speed_boost_with_rf_power=提供RF能量可显著提升速度。
#-----------------------------------------------------------------------------------------------------------
tile.engineersdecor.clinker_brick_block.name=过烧砖块
tile.engineersdecor.clinker_brick_block.help=§6一种放在不同位置贴图有不同变化的砖块。§r\n比原版砖看起来颜色更深色度也更高。
@ -20,8 +20,8 @@ tile.engineersdecor.slag_brick_block.name=炉渣砖块
tile.engineersdecor.slag_brick_block.help=§6一种放在不同位置贴图有不同变化的灰棕色砖块。
tile.engineersdecor.rebar_concrete.name=钢筋混凝土
tile.engineersdecor.rebar_concrete.help=§6钢强化的混凝土。§r昂贵但像黑曜石一样防爬行者爆炸。
tile.engineersdecor.gas_concrete.name=Gas Concrete Block
#tile.engineersdecor.gas_concrete.help=§6Low hardness, high production yield concrete.§r Easy to break decorative concrete block.
tile.engineersdecor.gas_concrete.name=加气混凝土
tile.engineersdecor.gas_concrete.help=§6低硬度高产出的混凝土。§r容易破坏的装饰性混凝土方块。
tile.engineersdecor.panzerglass_block.name=装甲玻璃块
tile.engineersdecor.panzerglass_block.help=§6强化的玻璃方块。§r昂贵防爆。深灰色调有隐约可见的结构线和多种纹理外观无光泽。
tile.engineersdecor.rebar_concrete_tile.name=钢筋混凝土砖
@ -37,8 +37,8 @@ tile.engineersdecor.rebar_concrete_slab.name=钢筋混凝土台阶
tile.engineersdecor.rebar_concrete_slab.help=§6钢强化的混凝土台阶。§r昂贵但像黑曜石一样防爬行者爆炸。
tile.engineersdecor.rebar_concrete_tile_slab.name=钢筋混凝土砖台阶
tile.engineersdecor.rebar_concrete_tile_slab.help=§6钢强化的混凝土砖台阶。§r昂贵但像黑曜石一样防爬行者爆炸。
tile.engineersdecor.gas_concrete_slab.name=Gas Concrete Slab
#tile.engineersdecor.gas_concrete_slab.help=§6Low hardness concrete slab.§r Easy to break decorative concrete.
tile.engineersdecor.gas_concrete_slab.name=加气混凝土台阶
tile.engineersdecor.gas_concrete_slab.help=§6低硬度的混凝土台阶。§r容易破坏的装饰性混凝土。
tile.engineersdecor.panzerglass_slab.name=装甲玻璃台阶
tile.engineersdecor.panzerglass_slab.help=§6强化的玻璃台阶。§r昂贵防爆。深灰色调有隐约可见的结构线和多种纹理。
tile.engineersdecor.treated_wood_floor.name=防腐木地板
@ -48,8 +48,8 @@ tile.engineersdecor.rebar_concrete_wall.name=钢筋混凝土墙
tile.engineersdecor.rebar_concrete_wall.help=§6钢强化的混凝土墙。§r 昂贵但像黑曜石一样防爬行者爆炸。
tile.engineersdecor.concrete_wall.name=混凝土墙
tile.engineersdecor.concrete_wall.help=§6用坚固混凝土制造的墙。
tile.engineersdecor.gas_concrete_wall.name=Gas Concrete Wall
#tile.engineersdecor.gas_concrete_wall.help=§6Low hardness concrete wall.§r Easy to break decorative concrete.
tile.engineersdecor.gas_concrete_wall.name=加气混凝土墙
tile.engineersdecor.gas_concrete_wall.help=§6低硬度的混凝土墙。§r容易破坏的装饰性混凝土。
tile.engineersdecor.clinker_brick_wall.name=过烧砖墙
tile.engineersdecor.clinker_brick_wall.help=§6简单的过烧砖墙。
tile.engineersdecor.slag_brick_wall.name=炉渣砖墙
@ -72,8 +72,8 @@ tile.engineersdecor.rebar_concrete_stairs.name=钢筋混凝土楼梯
tile.engineersdecor.rebar_concrete_stairs.help=§6钢强化的混凝土楼梯。§r昂贵但像黑曜石一样防爬行者爆炸。
tile.engineersdecor.rebar_concrete_tile_stairs.name=钢筋混凝土砖楼梯
tile.engineersdecor.rebar_concrete_tile_stairs.help=§6钢强化的混凝土砖楼梯。§r昂贵但像黑曜石一样防爬行者爆炸。
tile.engineersdecor.gas_concrete_stairs.name=Gas Concrete Stairs
#tile.engineersdecor.gas_concrete_stairs.help=§6Low hardness concrete stairs.§r Easy to break decorative concrete.
tile.engineersdecor.gas_concrete_stairs.name=加气混凝土楼梯
tile.engineersdecor.gas_concrete_stairs.help=§6低硬度的混凝土楼梯。§r容易破坏的装饰性混凝土。
#-----------------------------------------------------------------------------------------------------------
tile.engineersdecor.treated_wood_pole.name=直防腐木杆
tile.engineersdecor.treated_wood_pole.help=§6直杆的一段有着继电器的直径。§r\n\
@ -113,9 +113,9 @@ tile.engineersdecor.iron_inset_light.name=嵌入灯
tile.engineersdecor.iron_inset_light.help=§6小型荧石光源能嵌入地板、天花板或墙里。§r\n\
用于照亮电力光源难以安装的地方。\
亮度与火把一样。
tile.engineersdecor.iron_floor_edge_light.name=Inset Floor Edge Light
#tile.engineersdecor.iron_floor_edge_light.help=§6Small glowstone light source, placed at the edge of a floor block.§r\n\
Useful to light up places where electrical light installations are problematic.
tile.engineersdecor.iron_floor_edge_light.name=嵌入地板边缘灯
tile.engineersdecor.iron_floor_edge_light.help=§6小型荧石光源,置于地板方块边缘。§r\n\
用于照亮电力光源难以安装的地方。
tile.engineersdecor.treated_wood_window.name=防腐木窗
tile.engineersdecor.treated_wood_window.help=§6木框三层玻璃窗。绝缘良好。§r不像玻璃板一样连接到相邻方块。
tile.engineersdecor.treated_wood_windowsill.name=防腐木窗台
@ -158,11 +158,11 @@ tile.engineersdecor.straight_pipe_valve_redstone_analog.help=§6一段直输液
tile.engineersdecor.passive_fluid_accumulator.name=被动流体累积器。
tile.engineersdecor.passive_fluid_accumulator.help=§6基于真空吸力的流体收集器。§r有一个输出面其他面都是输入。\
当从输出面被泵抽取时,从输入面邻接储罐抽取液体。
tile.engineersdecor.small_fluid_funnel.name=Small Fluid Collection Funnel
#tile.engineersdecor.small_fluid_funnel.help=§6Collects fluids above it.§r Has an internal tank with three buckets capacity. Traces \
flowing fluids to nearby source blocks. The fluid can be obtained with fluid transfer systems \
or a bucket. Fills only tanks below (gravity transfer). Compatible with vanilla \
infinite-water-source creation.
tile.engineersdecor.small_fluid_funnel.name=小型流体收集漏斗
tile.engineersdecor.small_fluid_funnel.help=§6收集上方的流体。§r有一个三桶大的内部储罐。会\
追溯流体到附近的源方块。流体可被流体运输系统或桶\
移出。只会装满下方的储罐(重力传输)。与原版\
无限水兼容。
#-----------------------------------------------------------------------------------------------------------
tile.engineersdecor.factory_dropper.name=工厂掉落器
tile.engineersdecor.factory_dropper.help=§6适用于高级工厂自动化的掉落器。§r有十二个轮询选择的储物格。\
@ -171,18 +171,18 @@ tile.engineersdecor.factory_dropper.help=§6适用于高级工厂自动化的掉
还能和外部红石信号触发再进行逻辑与或逻辑或。触发模拟按钮仅作测试用途。\
当内部触发条件满足时,预先打开卷帘门。所有符合条件的物品\
会同时掉落。点击GUI的各处来了解如何运作。
tile.engineersdecor.factory_hopper.name=Factory Hopper
#tile.engineersdecor.factory_hopper.help=§6Hopper suitable for advanced factory automation.§r Can transfer half-stacks, max collection range 9x9.\n\
GUI Slider controls: Collection range (0 to 4), insertion delay (0.5s to 10s), insertion stack size (1 to 32).\n\
GUI Redstone controls: Not inverted / inverted (default), pulse mode / continuous mode (default).
tile.engineersdecor.factory_placer.name=Factory Block Placer
#tile.engineersdecor.factory_placer.help=§6Allows placing blocks and planting crops or trees.§r\n\
GUI Redstone controls: Not inverted / inverted (default), pulse mode / continuous mode (default).\n\
Also supports spike planing from underneath the soil. Spits out items that it cannot place or plant.
tile.engineersdecor.small_block_breaker.name=Factory Block Breaker
#tile.engineersdecor.small_block_breaker.help=§6Breaks blocks in front of it.§r\n\
Can be disabled by applying a redstone signal. \
The time needed to destroy a block depends on the hardness of that block. \
tile.engineersdecor.factory_hopper.name=工厂漏斗
tile.engineersdecor.factory_hopper.help=§6适用于高级工厂自动化的漏斗。§r可一次传输半组物品最大收集范围9x9。\n\
GUI滑动条控制收集距离0到4插入延迟0.5秒到10秒插入一叠物品的大小1到32\n\
GUI红石控制:不反相/反相(默认),脉冲模式/持续模式(默认)。
tile.engineersdecor.factory_placer.name=工厂方块放置器
tile.engineersdecor.factory_placer.help=§6能够放置方块和种植作物或树。§r\n\
GUI红石控制:不反相/反相(默认),脉冲模式/持续模式(默认)。\n\
也支持从耕地下方穿透方块种植。会吐出不能放置或种植的物品。
tile.engineersdecor.small_block_breaker.name=工厂方块破坏器
tile.engineersdecor.small_block_breaker.help=§6破坏其正前方的方块。§r\n\
通入红石信号可以停止破坏。\
破坏一个方块需要的时间取决于其硬度。\
${!block_breaker_requires_power?engineersdecor.tooltip.massive_speed_boost_with_rf_power}\
${block_breaker_requires_power?engineersdecor.tooltip.requires_rf_power}
tile.engineersdecor.small_mineral_smelter.name=小型矿物熔炼炉
@ -199,13 +199,13 @@ tile.engineersdecor.small_tree_cutter.name=小型砍树机
tile.engineersdecor.small_tree_cutter.help=§6砍倒正前方的树。§r\n\
不收集木材。通入红石信号停用。\
提供RF来加快砍树速度。没有的话会很慢。
tile.engineersdecor.small_milking_machine.name=Small Milking Machine
#tile.engineersdecor.small_milking_machine.help=§6Occasionally grooms and milks cows.§r\n\
Has an internal fluid tank. Does not feed the animals. Use buckets to retrieve the milk. \
Pulls/stores milk container items from/to inventories at the back or bottom (preferrs \
extracting from the back and inserting below, but can also put filled vessels back into the \
same inventory). Supports fluid output to tanks or pipes below (only if milk exists as fluid). \
Care that it's not too crowdy in the cow pen, only happy animals stroll by voluntarily.
tile.engineersdecor.small_milking_machine.name=小型挤奶机
tile.engineersdecor.small_milking_machine.help=§6偶尔给奶牛梳理和挤奶。§r\n\
有一个内置流体储罐。不会喂食动物。使用桶获得牛奶。\
从后方或下方的方块物品栏拉取或存储牛奶容器物品(偏好\
从下方输入,从后方输出,但也能将装满的牛奶容器放回原来\
的物品栏)支持将牛奶作为流体输出到下方的储罐和管道(只要牛奶是流体)。\
小心牛栏里不要太拥挤,只有快乐的动物才会自觉地在挤奶机前散步。
#-----------------------------------------------------------------------------------------------------------
tile.engineersdecor.sign_decor.name=标志板(工程师的装饰)
tile.engineersdecor.sign_decor.help=§6这不应该可合成或在JEI看到。用于创造模式的物品栏标签和截屏。
@ -220,14 +220,14 @@ tile.engineersdecor.sign_defense.help=§6用于警告炮塔、特斯拉线圈和
tile.engineersdecor.sign_factoryarea.name=指示牌 "工厂区域"
tile.engineersdecor.sign_factoryarea.help=§6用于指示真的很大的机器所在的建筑和区域。
tile.engineersdecor.sign_exit.name=出口指示牌
#tile.engineersdecor.sign_exit.help=§6There's the door, please ...
tile.engineersdecor.sign_exit.help=§6There's the door, please ...
#-----------------------------------------------------------------------------------------------------------
tile.engineersdecor.halfslab_rebar_concrete.name=强化混凝土切片
tile.engineersdecor.halfslab_rebar_concrete.help=§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。
tile.engineersdecor.halfslab_concrete.name=混凝土切片
tile.engineersdecor.halfslab_concrete.help=§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。
tile.engineersdecor.halfslab_gas_concrete.name=Gas Concrete Slice
#tile.engineersdecor.halfslab_gas_concrete.help=§6Vertically stackable slice.§r Right/left click with the slice stack on the top or bottom surface to add/remove slices.
tile.engineersdecor.halfslab_gas_concrete.name=加气混凝土切片
tile.engineersdecor.halfslab_gas_concrete.help=§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。
tile.engineersdecor.halfslab_treated_wood.name=防腐木切片
tile.engineersdecor.halfslab_treated_wood.help=§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。
tile.engineersdecor.halfslab_sheetmetal_iron.name=铁板金属块切片

View file

@ -7,8 +7,9 @@
},
"elements": [
{
"from": [6, 0.1875, 0.5],
"to": [10, 1.8125, 1],
"from": [6, 0, 0],
"to": [10, 1.8125, 0.375],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 7.5]},
"faces": {
"north": {"uv": [6, 14.1875, 10, 15.8125], "texture": "#light"},
"south": {"uv": [6, 14.1875, 10, 15.8125], "texture": "#light"},
@ -16,9 +17,9 @@
}
},
{
"from": [10, 0.1875, 0.5],
"to": [11, 1.8125, 1],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 8.125]},
"from": [10, 0, 0],
"to": [11, 1.8125, 0.375],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 7.625]},
"faces": {
"north": {"uv": [5, 14.1875, 6, 15.8125], "texture": "#side"},
"east": {"uv": [15, 14.1875, 15.5, 15.8125], "texture": "#side"},
@ -29,9 +30,9 @@
}
},
{
"from": [5, 0.1875, 0.5],
"to": [6, 1.8125, 1],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 8.125]},
"from": [5, 0, 0],
"to": [6, 1.8125, 0.375],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 7.625]},
"faces": {
"north": {"uv": [10, 14.1875, 11, 15.8125], "texture": "#side"},
"east": {"uv": [15, 14.1875, 15.5, 15.8125], "texture": "#side"},
@ -40,30 +41,6 @@
"up": {"uv": [5, 0.5, 6, 1], "texture": "#side"},
"down": {"uv": [5, 15, 6, 15.5], "texture": "#side"}
}
},
{
"from": [5, 0, 0],
"to": [11, 2, 0.5],
"faces": {
"north": {"uv": [5, 14, 11, 16], "texture": "#side"},
"east": {"uv": [15.5, 14, 16, 16], "texture": "#side"},
"south": {"uv": [5, 14, 11, 16], "texture": "#side"},
"west": {"uv": [0, 14, 0.5, 16], "texture": "#side"},
"up": {"uv": [5, 0, 11, 0.5], "texture": "#side"},
"down": {"uv": [5, 15.5, 11, 16], "texture": "#side"}
}
},
{
"from": [5, 0, 0.5],
"to": [11, 0.1875, 1],
"faces": {
"north": {"uv": [5, 15.8125, 11, 16], "texture": "#side"},
"east": {"uv": [15, 15.8125, 15.5, 16], "texture": "#side"},
"south": {"uv": [5, 15.8125, 11, 16], "texture": "#side"},
"west": {"uv": [0.5, 15.8125, 1, 16], "texture": "#side"},
"up": {"uv": [5, 0.5, 11, 1], "texture": "#side"},
"down": {"uv": [5, 15, 11, 15.5], "texture": "#side"}
}
}
],
"display": {

View file

@ -0,0 +1,22 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "immersiveengineering:stone_decoration",
"required": ["engineersdecor:halfslab_concrete"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"SS",
"SS"
],
"key": {
"S": { "item": "engineersdecor:halfslab_concrete" }
},
"result": {
"item": "immersiveengineering:stone_decoration_slab",
"data": 5,
"count": 1
}
}

View file

@ -0,0 +1,22 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "immersiveengineering:sheetmetal_slab",
"required": ["engineersdecor:halfslab_sheetmetal_aluminum"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"SS",
"SS"
],
"key": {
"S": { "item": "engineersdecor:halfslab_sheetmetal_aluminum" }
},
"result": {
"item": "immersiveengineering:sheetmetal_slab",
"data": 1,
"count": 1
}
}

View file

@ -0,0 +1,22 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "immersiveengineering:sheetmetal_slab",
"required": ["engineersdecor:halfslab_sheetmetal_copper"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"SS",
"SS"
],
"key": {
"S": { "item": "engineersdecor:halfslab_sheetmetal_copper" }
},
"result": {
"item": "immersiveengineering:sheetmetal_slab",
"data": 0,
"count": 1
}
}

View file

@ -0,0 +1,22 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "immersiveengineering:sheetmetal_slab",
"required": ["engineersdecor:halfslab_sheetmetal_gold"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"SS",
"SS"
],
"key": {
"S": { "item": "engineersdecor:halfslab_sheetmetal_gold" }
},
"result": {
"item": "immersiveengineering:sheetmetal_slab",
"data": 10,
"count": 1
}
}

View file

@ -0,0 +1,22 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "immersiveengineering:sheetmetal_slab",
"required": ["engineersdecor:halfslab_sheetmetal_iron"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"SS",
"SS"
],
"key": {
"S": { "item": "engineersdecor:halfslab_sheetmetal_iron" }
},
"result": {
"item": "immersiveengineering:sheetmetal_slab",
"data": 9,
"count": 1
}
}

View file

@ -0,0 +1,22 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "immersiveengineering:sheetmetal_slab",
"required": ["engineersdecor:halfslab_sheetmetal_steel"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"SS",
"SS"
],
"key": {
"S": { "item": "engineersdecor:halfslab_sheetmetal_steel" }
},
"result": {
"item": "immersiveengineering:sheetmetal_slab",
"data": 8,
"count": 1
}
}

View file

@ -0,0 +1,22 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "immersiveengineering:treated_wood_slab",
"required": ["engineersdecor:halfslab_treated_wood"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"SS",
"SS"
],
"key": {
"S": { "item": "engineersdecor:halfslab_treated_wood" }
},
"result": {
"item": "immersiveengineering:treated_wood_slab",
"data": 0,
"count": 1
}
}

View file

@ -0,0 +1,21 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "engineersdecor:clinker_brick_block",
"required": ["engineersdecor:clinker_brick_slab"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"B",
"B"
],
"key": {
"B": { "item": "engineersdecor:clinker_brick_slab" }
},
"result": {
"item": "engineersdecor:clinker_brick_block",
"count": 1
}
}

View file

@ -0,0 +1,21 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "engineersdecor:clinker_brick_stained_block",
"required": ["engineersdecor:clinker_brick_stained_slab"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"B",
"B"
],
"key": {
"B": { "item": "engineersdecor:clinker_brick_stained_slab" }
},
"result": {
"item": "engineersdecor:clinker_brick_stained_block",
"count": 1
}
}

View file

@ -0,0 +1,21 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "engineersdecor:gas_concrete",
"required": ["engineersdecor:gas_concrete_slab"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"B",
"B"
],
"key": {
"B": { "item": "engineersdecor:gas_concrete_slab" }
},
"result": {
"item": "engineersdecor:gas_concrete",
"count": 1
}
}

View file

@ -0,0 +1,21 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "engineersdecor:gas_concrete_slab",
"required": ["engineersdecor:halfslab_gas_concrete"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"SS",
"SS"
],
"key": {
"S": { "item": "engineersdecor:halfslab_gas_concrete" }
},
"result": {
"item": "engineersdecor:gas_concrete_slab",
"count": 1
}
}

View file

@ -0,0 +1,21 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "engineersdecor:rebar_concrete_slab",
"required": ["engineersdecor:halfslab_rebar_concrete"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"SS",
"SS"
],
"key": {
"S": { "item": "engineersdecor:halfslab_rebar_concrete" }
},
"result": {
"item": "engineersdecor:rebar_concrete_slab",
"count": 1
}
}

View file

@ -0,0 +1,21 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "engineersdecor:panzerglass_block",
"required": ["engineersdecor:panzerglass_slab"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"B",
"B"
],
"key": {
"B": { "item": "engineersdecor:panzerglass_slab" }
},
"result": {
"item": "engineersdecor:panzerglass_block",
"count": 1
}
}

View file

@ -0,0 +1,21 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "engineersdecor:rebar_concrete",
"required": ["engineersdecor:rebar_concrete_slab"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"B",
"B"
],
"key": {
"B": { "item": "engineersdecor:rebar_concrete_slab" }
},
"result": {
"item": "engineersdecor:rebar_concrete",
"count": 1
}
}

View file

@ -0,0 +1,21 @@
{
"conditions": [
{
"type": "engineersdecor:grc",
"result": "engineersdecor:rebar_concrete_tile",
"required": ["engineersdecor:rebar_concrete_tile_slab"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"B",
"B"
],
"key": {
"B": { "item": "engineersdecor:rebar_concrete_tile_slab" }
},
"result": {
"item": "engineersdecor:rebar_concrete_tile",
"count": 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 624 B

After

Width:  |  Height:  |  Size: 605 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 B

After

Width:  |  Height:  |  Size: 591 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 513 B

Before After
Before After

View file

@ -2,7 +2,7 @@
org.gradle.daemon=false
org.gradle.jvmargs=-Xmx8G
version_minecraft=1.14.4
version_forge_minecraft=1.14.4-28.1.90
version_forge_minecraft=1.14.4-28.1.109
version_fml_mappings=20190719-1.14.3
version_jei=1.14.4:6.0.0.10
version_engineersdecor=1.0.16-b7
version_engineersdecor=1.0.18-b1

View file

@ -1,6 +1,10 @@
{
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
"1.14.4": {
"1.0.18-b1": "[U] Updated to Forge 1.14.4-28.1.109/20190719-1.14.3.\n[A] Added opt-out config for the Small Tree Cutter.",
"1.0.17-b3": "[F] Double newline escapes in lang files fixed (\"\\n\" in a tooltip).\n[M] Updated zh_cn lang file (scikirbypoke).",
"1.0.17-b2": "[A] Reverse recipes for slabs and slab slices added.\n[M] Inset Floor Edge Light slightly thinner, looks better.",
"1.0.17-b1": "[A] Added Milking Machine.\n[A] Added Mineral Smelter gravity fluid transfer.\n[M] Window placement improved.\n[M] Made Pipe Valve textures slightly darker to fit IE pipes better when shaded.\n[F] Levers can be directly attached to redstone controller Pipe Valves.\n[F] Replaced Pipe Valve early load with lazy initialized data (issue #69, thx @Siriuo).",
"1.0.16-b7": "[M] Forge blockstates ported from 1.12 transformed to vanilla.",
"1.0.16-b6": "[A] Made slab slice left-click pickup optional (default enabled).\n[A] Added config option for device drops in creative mode (addresses #67),\n[F] Fixed Panzer Glass Block submerged display (issue #68, thx WenXin20).",
"1.0.16-b5": "[F] Fixed recipe condition bug (issue #65, thx Nachtflame for the report, and gigaherz & killjoy for the help).",
@ -37,6 +41,6 @@
},
"promos": {
"1.14.4-recommended": "",
"1.14.4-latest": "1.0.16-b7"
"1.14.4-latest": "1.0.18-b1"
}
}

View file

@ -11,142 +11,158 @@ Mod sources for Minecraft version 1.14.4.
## Version history
- v1.0.16-b7 [M] Forge blockstates ported from 1.12 transformed to vanilla.
- v1.0.18-b1 [U] Updated to Forge 1.14.4-28.1.109/20190719-1.14.3.
[A] Added opt-out config for the Small Tree Cutter.
- v1.0.16-b6 [A] Made slab slice left-click pickup optional (default enabled).
[A] Added config option for device drops in creative mode (addresses #67),
[F] Fixed Panzer Glass Block submerged display (issue #68, thx WenXin20).
- v1.0.17-b3 [F] Double newline escapes in lang files fixed ("\n" in a tooltip).
[M] Updated zh_cn lang file (scikirbypoke).
- v1.0.16-b5 [F] Fixed recipe condition bug (issue #65, thx Nachtflame for the report,
and gigaherz & killjoy for the help).
- v1.0.17-b2 [A] Reverse recipes for slabs and slab slices added.
[M] Inset Floor Edge Light slightly thinner, looks better.
- v1.0.16-b4 [U] Updated to Forge 1.14.4-28.1.90/20190719-1.14.3.
[M] Increased slag brick recipe yield to 8.
[M] Parent specs in model files adapted.
- v1.0.17-b1 [A] Added Milking Machine.
[A] Added Mineral Smelter gravity fluid transfer.
[M] Window placement improved.
[M] Made Pipe Valve textures slightly darker to fit IE pipes better when shaded.
[F] Levers can be directly attached to redstone controller Pipe Valves.
[F] Replaced Pipe Valve early load with lazy initialized data (issue #69, thx @Siriuo).
- v1.0.16-b3 [A] Config options (opt-outs and tweaks) added.
[M] Increased clinker brick recipe yield to 8 for the builders needs.
- v1.0.16-b7 [M] Forge blockstates ported from 1.12 transformed to vanilla.
- v1.0.16-b2 [A] Added Gas Concrete (including wall, stairs, slab, and slab slice).
[F] Fixed Small Block Breaker active model.
[F] Fixed item-on-ground display glitch (issue #61, thx Federsavo for the hint).
[F] Added two missing recipes.
- v1.0.16-b6 [A] Made slab slice left-click pickup optional (default enabled).
[A] Added config option for device drops in creative mode (addresses #67),
[F] Fixed Panzer Glass Block submerged display (issue #68, thx WenXin20).
- v1.0.16-b1 [U] Updated to Forge 1.14.4-28.1.79/20190719-1.14.3.
[A] Added Fluid Collection Funnel.
- v1.0.16-b5 [F] Fixed recipe condition bug (issue #65, thx Nachtflame for the report,
and gigaherz & killjoy for the help).
- v1.0.15-b3 [A] Added Small Block Breaker.
[M] Mineral Smelter fluid handler/transfer added.
- v1.0.16-b4 [U] Updated to Forge 1.14.4-28.1.90/20190719-1.14.3.
[M] Increased slag brick recipe yield to 8.
[M] Parent specs in model files adapted.
- v1.0.15-b2 [!] Forge version requirement set to 1.14.4-28.1.68 or higher.
[A] Added Factory Block Placer and Planter.
[A] Added Small Tree Cutter.
- v1.0.16-b3 [A] Config options (opt-outs and tweaks) added.
[M] Increased clinker brick recipe yield to 8 for the builders needs.
- v1.0.15-b1 [A] Added Floor Edge Light.
[U] Updated to Forge 1.14.4-28.1.68/20190719-1.14.3.
- v1.0.16-b2 [A] Added Gas Concrete (including wall, stairs, slab, and slab slice).
[F] Fixed Small Block Breaker active model.
[F] Fixed item-on-ground display glitch (issue #61, thx Federsavo for the hint).
[F] Added two missing recipes.
- v1.0.14-b1 [U] Updated to Forge 1.14.4-28.1.40/20190719-1.14.3.
[A] Factory Hopper added (configurable hopper and item collector).
[M] Switched to integrated loot table generation.
[M] Lang file zh_cn updated (scikirbypoke, PR#53).
- v1.0.16-b1 [U] Updated to Forge 1.14.4-28.1.79/20190719-1.14.3.
[A] Added Fluid Collection Funnel.
- v1.0.13-b2 [A] Added Steel Mesh Fence.
[A] Added Broad Window Sill.
- v1.0.15-b3 [A] Added Small Block Breaker.
[M] Mineral Smelter fluid handler/transfer added.
- v1.0.12-b3 [U] Updated to Forge 1.14.4-28.1.10/20190719-1.14.3.
[A] Crafting Table: Added recipe collision resolver,
also applies to crafting history refabrication.
[A] Crafting Table: Added rendering of placed items
on the top surface of the table.
[A] Waterlogging of non-full-blocks added.
- v1.0.15-b2 [!] Forge version requirement set to 1.14.4-28.1.68 or higher.
[A] Added Factory Block Placer and Planter.
[A] Added Small Tree Cutter.
- v1.0.12-b2 [U] Updated to Forge 1.14.4-28.0.105/20190719-1.14.3.
[A] Small Solar Panel added.
[M] Items fall through the Steel Floor Grating like in 1.12.2 version.
[M] Factory Dropper: Added pulse/continuous mode in GUI (issue #51,
thx Aristine for the CR).
- v1.0.15-b1 [A] Added Floor Edge Light.
[U] Updated to Forge 1.14.4-28.1.68/20190719-1.14.3.
- v1.0.12-b1 [U] Updated to Forge 1.14.4-28.0.93/20190719-1.14.3.
[M] Logo location fixed.
- v1.0.14-b1 [U] Updated to Forge 1.14.4-28.1.40/20190719-1.14.3.
[A] Factory Hopper added (configurable hopper and item collector).
[M] Switched to integrated loot table generation.
[M] Lang file zh_cn updated (scikirbypoke, PR#53).
- v1.0.11-b3 [U] Updated to Forge 1.14.4-28.0.81/20190719-1.14.3.
[F] Adapted recipe condition to Forge version (issue #49).
- v1.0.13-b2 [A] Added Steel Mesh Fence.
[A] Added Broad Window Sill.
- v1.0.11-b2 [U] JEI dependency update 1.14.4:6.0.0.10.
[F] Fixed creative ghost block issue (issue #48).
[M] Updated ru_ru lang file (Shellyoung, PR#47).
- v1.0.12-b3 [U] Updated to Forge 1.14.4-28.1.10/20190719-1.14.3.
[A] Crafting Table: Added recipe collision resolver,
also applies to crafting history refabrication.
[A] Crafting Table: Added rendering of placed items
on the top surface of the table.
[A] Waterlogging of non-full-blocks added.
- v1.0.11-b1 [A] Added Steel Table
[A] Added Treated Wood Side Table
[A] Added Exit Sign
[A] Added Steel Floor Grating
[M] Sign orientation fixed, only blocked vertical placement.
- v1.0.12-b2 [U] Updated to Forge 1.14.4-28.0.105/20190719-1.14.3.
[A] Small Solar Panel added.
[M] Items fall through the Steel Floor Grating like in 1.12.2 version.
[M] Factory Dropper: Added pulse/continuous mode in GUI (issue #51,
thx Aristine for the CR).
- v1.0.9-b9 [U] Update to Forge 1.14.4-28.0.40/20190719-1.14.3 for Forge
testing.
- v1.0.12-b1 [U] Updated to Forge 1.14.4-28.0.93/20190719-1.14.3.
[M] Logo location fixed.
- v1.0.9-b8 [U] UPDATE TO 1.14.4. Forge 1.14.4-28.0.11/20190719-1.14.3.
- v1.0.11-b3 [U] Updated to Forge 1.14.4-28.0.81/20190719-1.14.3.
[F] Adapted recipe condition to Forge version (issue #49).
- v1.0.9-b7 [U] Updated to Forge 1.14.3-27.0.60/20190719-1.14.3.
[F] Disabled all early implemented fuild handling of valves
and the Fluid Accumulator to prevent world loading
hang-ups (issue #42, thx TheOhmegha for reporting).
Will be re-enabled after fluid handling released in Forge.
[F] Fixed blockstate model locations for signs and crafting
table (issue #43, thx ProsperCraft for the beta test).
- v1.0.11-b2 [U] JEI dependency update 1.14.4:6.0.0.10.
[F] Fixed creative ghost block issue (issue #48).
[M] Updated ru_ru lang file (Shellyoung, PR#47).
- v1.0.9-b6 [U] Updated to Forge 1.14.3-27.0.50/20190621-1.14.2.
- v1.0.11-b1 [A] Added Steel Table
[A] Added Treated Wood Side Table
[A] Added Exit Sign
[A] Added Steel Floor Grating
[M] Sign orientation fixed, only blocked vertical placement.
- v1.0.9-b5 [A] Added missing recipes for slabs, stained clinker, half-slabs, valves.
[M] Standalone recipes adapted.
[F] Lang files: Fixed double newline escape.
[A] Implicit opt-out of hard IE dependent blocks ported (e.g. Concrete Wall).
[M] Basic mod config features, opt-outs and tweaks ported.
- v1.0.9-b9 [U] Update to Forge 1.14.4-28.0.40/20190719-1.14.3 for Forge
testing.
- v1.0.9-b4 [E] Experimental: Config skel ported (!not all options have effect yet).
[E] Experimental: JEI integration for opt-outs and crafting table ported
(also addresses issue #38).
- v1.0.9-b8 [U] UPDATE TO 1.14.4. Forge 1.14.4-28.0.11/20190719-1.14.3.
- v1.0.9-b3 [F] Additional item drop fixes when blocks are destroyed (issue #39).
- v1.0.9-b7 [U] Updated to Forge 1.14.3-27.0.60/20190719-1.14.3.
[F] Disabled all early implemented fuild handling of valves
and the Fluid Accumulator to prevent world loading
hang-ups (issue #42, thx TheOhmegha for reporting).
Will be re-enabled after fluid handling released in Forge.
[F] Fixed blockstate model locations for signs and crafting
table (issue #43, thx ProsperCraft for the beta test).
- v1.0.9-b2 [U] Updated to Forge 1.14.3-27.0.25/20190621-1.14.2.
[F] Fixed recipe collision of Metal Rung Ladder (issue #37,
thx ProsperCraft for reporting).
[F] Fixed opening crafting table, furni, dropper server crash
issue #35 (thx ProsperCraft also here).
[F] Fixed missing pole/support item drops (issue #36, ProsperCraft).
- v1.0.9-b6 [U] Updated to Forge 1.14.3-27.0.50/20190621-1.14.2.
- v1.0.9-b1 [U] Updated to MC1.14.3, Forge 1.14.3-27.0.17/20190621-1.14.2.
[A] Added Small Mineral Smelter.
- v1.0.9-b5 [A] Added missing recipes for slabs, stained clinker, half-slabs, valves.
[M] Standalone recipes adapted.
[F] Lang files: Fixed double newline escape.
[A] Implicit opt-out of hard IE dependent blocks ported (e.g. Concrete Wall).
[M] Basic mod config features, opt-outs and tweaks ported.
- v1.0.8-b3 [A] Ported slabs and slab slices from 1.12.2.
[A] IE independent ("standalone") recipes ported.
- v1.0.9-b4 [E] Experimental: Config skel ported (!not all options have effect yet).
[E] Experimental: JEI integration for opt-outs and crafting table ported
(also addresses issue #38).
- v1.0.8-b2 [U] Updated to Forge BETA 1.14.2-26.0.63/20190621-1.14.2,
code adapted to new mappings.
[M] Updated 1st/3rd person item model rotations/translations.
- v1.0.9-b3 [F] Additional item drop fixes when blocks are destroyed (issue #39).
- v1.0.8-b1 [V] Feature set of 1.12 ported.
[A] CTRL-SHIFT tooltips ported.
[A] Ported stained clinker block/stairs.
[M] Updated textures.
[I] Issue: Scoped recipe constants still not working.
- v1.0.9-b2 [U] Updated to Forge 1.14.3-27.0.25/20190621-1.14.2.
[F] Fixed recipe collision of Metal Rung Ladder (issue #37,
thx ProsperCraft for reporting).
[F] Fixed opening crafting table, furni, dropper server crash
issue #35 (thx ProsperCraft also here).
[F] Fixed missing pole/support item drops (issue #36, ProsperCraft).
- v1.0.7-b5 [U] Updated to Forge BETA 1.14.2-26.0.35/20190608-1.14.2.
[A] Factory dropper functionality ported.
[A] Small lab furnace functionality ported.
[A] Small electrical lab furnace functionality ported.
[A] Small waste incinerator functionality ported.
[A] Fluid valves, Passive Fluid Accumulator ported.
[I] Issue: Scoped recipe constants still not working.
- v1.0.9-b1 [U] Updated to MC1.14.3, Forge 1.14.3-27.0.17/20190621-1.14.2.
[A] Added Small Mineral Smelter.
- v1.0.7-b4 [U] Updated to Forge BETA 1.14.2-26.0.32/20190608-1.14.2.
[A] Sitting on the stool ported.
[A] Ladder climbing speed boost ported.
[A] Crafting table functionality ported.
[I] Issue: Scoped recipe constants not working yet with
the current Forge version (or somehow changed).
- v1.0.8-b3 [A] Ported slabs and slab slices from 1.12.2.
[A] IE independent ("standalone") recipes ported.
- v1.0.7-b3 [A] Initial 1.14.2 port of decorative blocks.
- v1.0.8-b2 [U] Updated to Forge BETA 1.14.2-26.0.63/20190621-1.14.2,
code adapted to new mappings.
[M] Updated 1st/3rd person item model rotations/translations.
- v1.0.8-b1 [V] Feature set of 1.12 ported.
[A] CTRL-SHIFT tooltips ported.
[A] Ported stained clinker block/stairs.
[M] Updated textures.
[I] Issue: Scoped recipe constants still not working.
- v1.0.7-b5 [U] Updated to Forge BETA 1.14.2-26.0.35/20190608-1.14.2.
[A] Factory dropper functionality ported.
[A] Small lab furnace functionality ported.
[A] Small electrical lab furnace functionality ported.
[A] Small waste incinerator functionality ported.
[A] Fluid valves, Passive Fluid Accumulator ported.
[I] Issue: Scoped recipe constants still not working.
- v1.0.7-b4 [U] Updated to Forge BETA 1.14.2-26.0.32/20190608-1.14.2.
[A] Sitting on the stool ported.
[A] Ladder climbing speed boost ported.
[A] Crafting table functionality ported.
[I] Issue: Scoped recipe constants not working yet with
the current Forge version (or somehow changed).
- v1.0.7-b3 [A] Initial 1.14.2 port of decorative blocks.
----

View file

@ -33,7 +33,6 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.event.RegistryEvent;
import org.apache.commons.lang3.ArrayUtils;
import java.util.ArrayList;
import java.util.List;
@ -525,6 +524,14 @@ public class ModContent
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorTest TEST_BLOCK = (BlockDecorTest)(new BlockDecorTest(
BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_ELECTRICAL|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(0f, 32000f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "test_block"));
// -------------------------------------------------------------------------------------------------------------------
private static final Block modBlocks[] = {
TREATED_WOOD_CRAFTING_TABLE,
SMALL_LAB_FURNACE,
@ -537,6 +544,7 @@ public class ModContent
SMALL_SOLAR_PANEL,
SMALL_WASTE_INCINERATOR,
SMALL_MINERAL_SMELTER,
SMALL_MILKING_MACHINE,
STRAIGHT_CHECK_VALVE,
STRAIGHT_REDSTONE_VALVE,
STRAIGHT_REDSTONE_ANALOG_VALVE,
@ -608,7 +616,7 @@ public class ModContent
};
private static final Block devBlocks[] = {
SMALL_MILKING_MACHINE
//TEST_BLOCK
};
//--------------------------------------------------------------------------------------------------------------------
@ -690,6 +698,10 @@ public class ModContent
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_tree_cutter");
public static final TileEntityType<?> TET_TEST_BLOCK = TileEntityType.Builder
.create(BlockDecorPipeValve.BTileEntity::new, TEST_BLOCK)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_test_block");
private static final TileEntityType<?> tile_entity_types[] = {
TET_TREATED_WOOD_CRAFTING_TABLE,
@ -707,6 +719,7 @@ public class ModContent
TET_STRAIGHT_PIPE_VALVE,
TET_PASSIVE_FLUID_ACCUMULATOR,
TET_SMALL_FLUID_FUNNEL,
TET_TEST_BLOCK
};
//--------------------------------------------------------------------------------------------------------------------

View file

@ -148,7 +148,7 @@ public class BlockDecorFluidFunnel extends BlockDecor
public static final int MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE = 1024;
public static final int MAX_TRACK_RADIUS_SQ = MAX_TRACK_RADIUS*MAX_TRACK_RADIUS;
public static final int INTENSIVE_SEARCH_TRIGGER_THRESHOLD = 16;
private FluidStack tank_ = FluidStack.EMPTY.copy();
private FluidStack tank_ = FluidStack.EMPTY;
private int tick_timer_ = 0;
private int collection_timer_ = 0;
private int no_fluid_found_counter_ = 0;
@ -168,7 +168,7 @@ public class BlockDecorFluidFunnel extends BlockDecor
public void readnbt(CompoundNBT nbt)
{
tank_ = (!nbt.contains("tank")) ? (FluidStack.EMPTY.copy()) : (FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
tank_ = (!nbt.contains("tank")) ? (FluidStack.EMPTY) : (FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
}
public void writenbt(CompoundNBT nbt)
@ -200,19 +200,19 @@ public class BlockDecorFluidFunnel extends BlockDecor
@Override public FluidStack drain(FluidStack resource, FluidAction action)
{
if((resource==null) || (te.tank_.isEmpty())) return FluidStack.EMPTY.copy();
return (!(te.tank_.isFluidEqual(resource))) ? (FluidStack.EMPTY.copy()) : drain(resource.getAmount(), action);
if((resource==null) || (te.tank_.isEmpty())) return FluidStack.EMPTY;
return (!(te.tank_.isFluidEqual(resource))) ? (FluidStack.EMPTY) : drain(resource.getAmount(), action);
}
@Override public FluidStack drain(int maxDrain, FluidAction action)
{
if(te.tank_.isEmpty()) return FluidStack.EMPTY;
FluidStack res = te.tank_.copy();
if(res.isEmpty()) return res;
maxDrain = MathHelper.clamp(maxDrain ,0 , te.tank_.getAmount());
res.setAmount(maxDrain);
if(action != FluidAction.EXECUTE) return res;
te.tank_.setAmount(te.tank_.getAmount()-maxDrain);
if(te.tank_.getAmount() <= 0) te.tank_ = FluidStack.EMPTY.copy();
if(te.tank_.getAmount() <= 0) te.tank_ = FluidStack.EMPTY;
return res;
}
}

View file

@ -269,12 +269,12 @@ public class BlockDecorMilker extends BlockDecorDirectedHorizontal
@Override
public FluidStack drain(FluidStack resource, FluidAction action)
{ return (!resource.isFluidEqual(milk_fluid_)) ? (FluidStack.EMPTY.copy()) : drain(resource.getAmount(), action); }
{ return (!resource.isFluidEqual(milk_fluid_)) ? (FluidStack.EMPTY) : drain(resource.getAmount(), action); }
@Override
public FluidStack drain(int maxDrain, FluidAction action)
{
if(te.fluid_level() <= 0) return FluidStack.EMPTY.copy();
if(te.fluid_level() <= 0) return FluidStack.EMPTY;
FluidStack fs = milk_fluid_.copy();
fs.setAmount(Math.min(fs.getAmount(), te.fluid_level()));
if(action==FluidAction.EXECUTE) te.tank_level_ -= fs.getAmount();
@ -300,7 +300,7 @@ public class BlockDecorMilker extends BlockDecorDirectedHorizontal
// ITickable ------------------------------------------------------------------------------------
private void log(String s)
{} // System.out.println("Milker|" + s); may be enabled with config, for dev was println
{} // println("Milker|" + s); may be enabled with config, for dev was println
private static ItemStack milk_filled_container_item(ItemStack stack)
{ return milk_containers_.entrySet().stream().filter(e->e.getKey().isItemEqual(stack)).map(Map.Entry::getValue).findFirst().orElse(ItemStack.EMPTY); }
@ -510,7 +510,7 @@ public class BlockDecorMilker extends BlockDecorDirectedHorizontal
{
@FunctionalInterface public interface TargetPositionInValidCheck { boolean test(SingleMoveGoal goal, IWorldReader world, BlockPos pos); }
@FunctionalInterface public interface StrollEvent { void apply(SingleMoveGoal goal, IWorldReader world, Vec3d pos); }
private static void log(String s) {} // System.out.println(s);
private static void log(String s) {} // println(s);
private static final int motion_timeout = 20*20;
private boolean aborted_;

View file

@ -9,38 +9,42 @@
*/
package wile.engineersdecor.blocks;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.entity.LivingEntity;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.block.*;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.inventory.ItemStackHelper;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.*;
import net.minecraft.util.math.*;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.block.*;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.state.IntegerProperty;
import net.minecraft.util.*;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.World;
import net.minecraft.state.IntegerProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.block.BlockState;
import net.minecraft.world.IBlockReader;
import net.minecraft.fluid.Fluids;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
@ -213,6 +217,7 @@ public class BlockDecorMineralSmelter extends BlockDecorDirectedHorizontal
private static final ItemStack MAGMA_STACK = new ItemStack(Blocks.MAGMA_BLOCK);
private static final ItemStack BUCKET_STACK = new ItemStack(Items.BUCKET);
private static final ItemStack LAVA_BUCKET_STACK = new ItemStack(Items.LAVA_BUCKET);
private static final FluidStack LAVA_BUCKET_FLUID_STACK = new FluidStack(Fluids.LAVA, 1000);
private static int energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
private static int heatup_rate = DEFAULT_HEATUP_RATE;
private static int cooldown_rate = 1;
@ -485,7 +490,7 @@ public class BlockDecorMineralSmelter extends BlockDecorDirectedHorizontal
@Override
public FluidStack drain(FluidStack resource, FluidAction action)
{
if(!resource.isFluidEqual(lava) || (te.fluid_level() <= 0)) return FluidStack.EMPTY.copy();
if(!resource.isFluidEqual(lava) || (te.fluid_level() <= 0)) return FluidStack.EMPTY;
FluidStack stack = new FluidStack(lava, te.fluid_level());
if(action == FluidAction.EXECUTE) te.fluid_level_drain(te.fluid_level());
return stack;
@ -494,7 +499,7 @@ public class BlockDecorMineralSmelter extends BlockDecorDirectedHorizontal
@Override
public FluidStack drain(int maxDrain, FluidAction action)
{
if(te.fluid_level() <= 0) return FluidStack.EMPTY.copy();
if(te.fluid_level() <= 0) return FluidStack.EMPTY;
maxDrain = (action==FluidAction.EXECUTE) ? (te.fluid_level_drain(maxDrain)) : (Math.min(maxDrain, te.fluid_level()));
return new FluidStack(lava, maxDrain);
}
@ -633,7 +638,21 @@ public class BlockDecorMineralSmelter extends BlockDecorDirectedHorizontal
break;
}
}
} else if((phase()==PHASE_LAVA) && (fluid_level() >= MAX_BUCKET_EXTRACT_FLUID_LEVEL)) {
// Fluid transfer check
final IFluidHandler fh = FluidUtil.getFluidHandler(world, getPos().down(), Direction.UP).orElse(null);
if(fh != null) {
int n = fh.fill(LAVA_BUCKET_FLUID_STACK.copy(), FluidAction.SIMULATE);
if(n >= LAVA_BUCKET_FLUID_STACK.getAmount()/2) {
n = fh.fill(LAVA_BUCKET_FLUID_STACK.copy(), FluidAction.EXECUTE);
if(n > 0) {
reset_process();
world.playSound(null, pos, SoundEvents.BLOCK_LAVA_EXTINGUISH, SoundCategory.BLOCKS, 0.3f, 0.7f);
}
}
}
}
// Block state
BlockState state = world.getBlockState(pos);
if((state.getBlock() instanceof BlockDecorMineralSmelter) && (force_block_update_ || (state.get(PHASE) != new_phase))) {
state = state.with(PHASE, new_phase);

View file

@ -112,7 +112,7 @@ public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
public void read(CompoundNBT nbt)
{
super.read(nbt);
tank_ = (!nbt.contains("tank")) ? (FluidStack.EMPTY.copy()) : (FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
tank_ = (!nbt.contains("tank")) ? (FluidStack.EMPTY) : (FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
}
@Override
@ -134,8 +134,8 @@ public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
@Override public int getTankCapacity(int tank) { return max_flowrate; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return true; }
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY.copy(); }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY.copy(); }
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY; }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY; }
}
// Output flow handler ---------------------------------------------------------------------
@ -152,21 +152,21 @@ public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
@Override public FluidStack drain(FluidStack resource, FluidAction action)
{
if((resource==null) || (te.tank_.isEmpty())) return FluidStack.EMPTY.copy();
return (!(te.tank_.isFluidEqual(resource))) ? (FluidStack.EMPTY.copy()) : drain(resource.getAmount(), action);
if((resource==null) || (te.tank_.isEmpty())) return FluidStack.EMPTY;
return (!(te.tank_.isFluidEqual(resource))) ? (FluidStack.EMPTY) : drain(resource.getAmount(), action);
}
@Override public FluidStack drain(int maxDrain, FluidAction action)
{
if(!te.initialized_) FluidStack.EMPTY.copy();
if(!te.initialized_) return FluidStack.EMPTY;
if((action==FluidAction.EXECUTE) && (maxDrain > 0)) te.last_drain_request_amount_ = maxDrain;
if(te.tank_.isEmpty()) return FluidStack.EMPTY.copy();
if(te.tank_.isEmpty()) return FluidStack.EMPTY;
maxDrain = MathHelper.clamp(maxDrain ,0 , te.tank_.getAmount());
FluidStack res = te.tank_.copy();
if(action!=FluidAction.EXECUTE) return res;
res.setAmount(maxDrain);
te.tank_.setAmount(te.tank_.getAmount()-maxDrain);
if(te.tank_.getAmount() <= 0) te.tank_ = FluidStack.EMPTY.copy();
if(te.tank_.getAmount() <= 0) te.tank_ = FluidStack.EMPTY;
te.total_volume_drained_ += res.getAmount();
return res;
}
@ -232,7 +232,7 @@ public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
if(fh==null) continue;
if(tank_.isEmpty()) {
FluidStack res = fh.drain(n_requested, FluidAction.EXECUTE).copy();
if(res.getAmount()==0) continue;
if(res.isEmpty()) continue;
total_volume_filled_ += res.getAmount();
tank_ = res.copy();
has_refilled = true;
@ -240,7 +240,9 @@ public class BlockDecorPassiveFluidAccumulator extends BlockDecorDirected
if((tank_.getAmount() + n_requested) > max_flowrate) n_requested = (max_flowrate - tank_.getAmount());
FluidStack rq = tank_.copy();
rq.setAmount(n_requested);
FluidStack res = fh.drain(rq, FluidAction.EXECUTE);
FluidStack res = fh.drain(rq, FluidAction.SIMULATE);
if(!res.isFluidEqual(rq)) continue;
res = fh.drain(rq, FluidAction.EXECUTE);
if(res.isEmpty()) continue;
tank_.setAmount(tank_.getAmount()+res.getAmount());
total_volume_filled_ += res.getAmount();

View file

@ -11,24 +11,27 @@ package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.BooleanProperty;
import net.minecraft.world.IWorld;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.world.World;
import net.minecraft.world.IBlockReader;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
@ -82,12 +85,16 @@ public class BlockDecorPipeValve extends BlockDecorDirected implements IWaterLog
return state;
}
private void update_te(World world, BlockState state, BlockPos pos)
private void update_te(IWorld world, BlockState state, BlockPos pos)
{
TileEntity te = world.getTileEntity(pos);
if(te instanceof BlockDecorPipeValve.BTileEntity) ((BlockDecorPipeValve.BTileEntity)te).block_reconfigure(state.get(FACING), config);
}
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return VoxelShapes.fullCube(); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(RS_CN_N, RS_CN_S, RS_CN_E, RS_CN_W, RS_CN_U, RS_CN_D, WATERLOGGED); }
@ -103,7 +110,10 @@ public class BlockDecorPipeValve extends BlockDecorDirected implements IWaterLog
@Override
@SuppressWarnings("deprecation")
public BlockState updatePostPlacement(BlockState state, Direction facing, BlockState facingState, IWorld world, BlockPos pos, BlockPos facingPos)
{ return get_rsconnector_state(state, world, pos, null); }
{
update_te(world, state, pos);
return get_rsconnector_state(state, world, pos, null);
}
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
@ -112,19 +122,6 @@ public class BlockDecorPipeValve extends BlockDecorDirected implements IWaterLog
world.notifyNeighborsOfStateChange(pos,this);
}
@Deprecated
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos)
{
Direction fc = state.get(FACING);
if(fromPos.equals(pos.offset(fc)) || fromPos.equals(pos.offset(fc.getOpposite()))) {
update_te(world, state, pos);
} else {
BlockState connector_state = get_rsconnector_state(state, world, pos, fromPos);
if(!state.equals(connector_state)) world.setBlockState(pos, connector_state);
}
}
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@ -146,50 +143,34 @@ public class BlockDecorPipeValve extends BlockDecorDirected implements IWaterLog
{
protected static int fluid_maxflow_mb = 1000;
protected static int redstone_flow_slope_mb = 1000/15;
// private final IFluidTankProperties[] fluid_props_ = {this};
private Direction block_facing_ = Direction.NORTH;
private Direction block_facing_ = null;
private boolean filling_ = false;
private boolean getlocked_ = false;
private boolean filling_enabled_ = true;
private long block_config_ = 0;
public BTileEntity()
{ this(ModContent.TET_STRAIGHT_PIPE_VALVE); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
public void block_reconfigure(Direction facing, long block_config)
{
block_facing_ = facing;
block_config_ = block_config;
filling_enabled_ = false;
// IFluidHandler fh = forward_fluid_handler();
// if(fh!=null) {
// if(fh.getTankProperties().length==0) {
// filling_enabled_ = true; // we don't know, so in doubt try filling.
// } else {
// for(IFluidTankProperties fp:fh.getTankProperties()) {
// if((fp!=null) && (fp.canFill())) { filling_enabled_ = true; break; }
// }
// }
// }
}
private Direction block_facing()
{
if(block_facing_ == null) {
BlockState st = getWorld().getBlockState(getPos());
block_facing_ = (st.getBlock() instanceof BlockDecorPipeValve) ? st.get(FACING) : Direction.NORTH;
}
return block_facing_;
}
// TileEntity ------------------------------------------------------------------------------
@Override
public void onLoad()
{
if(!hasWorld()) return;
final BlockState state = world.getBlockState(pos);
if((!(state.getBlock() instanceof BlockDecorPipeValve))) return;
block_reconfigure(state.get(FACING), block_config_);
world.notifyNeighborsOfStateChange(pos, state.getBlock());
}
@Override
public void read(CompoundNBT nbt)
{
@ -203,7 +184,7 @@ public class BlockDecorPipeValve extends BlockDecorDirected implements IWaterLog
public CompoundNBT write(CompoundNBT nbt)
{
super.write(nbt);
nbt.putInt("facing", block_facing_.getIndex());
if(block_facing_!=null) nbt.putInt("facing", block_facing_.getIndex());
nbt.putLong("conf", block_config_);
return nbt;
}
@ -218,8 +199,8 @@ public class BlockDecorPipeValve extends BlockDecorDirected implements IWaterLog
{
if(!this.removed && (facing != null)) {
if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
if(facing == block_facing_) return fluid_handler_.cast();
if(facing == block_facing_.getOpposite()) return back_flow_handler_.cast();
if(facing == block_facing()) return back_flow_handler_.cast();
if(facing == block_facing().getOpposite()) return fluid_handler_.cast();
}
}
return super.getCapability(capability, facing);
@ -230,9 +211,9 @@ public class BlockDecorPipeValve extends BlockDecorDirected implements IWaterLog
@Nullable
private IFluidHandler forward_fluid_handler()
{
final TileEntity te = world.getTileEntity(pos.offset(block_facing_));
final TileEntity te = world.getTileEntity(pos.offset(block_facing()));
if(te == null) return null;
return te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, block_facing_.getOpposite()).orElse(null);
return te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, block_facing().getOpposite()).orElse(null);
}
// Forward flow handler --
@ -244,13 +225,15 @@ public class BlockDecorPipeValve extends BlockDecorDirected implements IWaterLog
@Override public int getTanks() { return 0; }
@Override public FluidStack getFluidInTank(int tank) { return FluidStack.EMPTY; }
@Override public int getTankCapacity(int tank) { return fluid_maxflow_mb; }
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY.copy(); }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY.copy(); }
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY; }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return true; }
@Override public int fill(FluidStack resource, FluidAction action)
{
if((te.filling_) || (!te.filling_enabled_)) return 0;
if(te.filling_) return 0;
final IFluidHandler fh = te.forward_fluid_handler();
if(fh==null) return 0;
if((te.block_config_ & CFG_REDSTONE_CONTROLLED) != 0) {
int rs = te.world.getRedstonePowerFromNeighbors(te.pos);
if(rs <= 0) return 0;
@ -258,17 +241,15 @@ public class BlockDecorPipeValve extends BlockDecorDirected implements IWaterLog
}
FluidStack res = resource.copy();
if(res.getAmount() > fluid_maxflow_mb) res.setAmount(fluid_maxflow_mb);
final IFluidHandler fh = te.forward_fluid_handler();
if(fh==null) return 0;
te.filling_ = true; // in case someone does not check the cap, but just "forwards back" what is beeing filled right now.
//if(res.amount > 50) {
//final TileEntity te = te.world.getTileEntity(te.pos.offset(te.block_facing_));
//if(te instanceof IFluidPipe) {
// // forward pressureized tag
// if(res.tag == null) res.tag = new CompoundNBT();
// res.tag.putBoolean("pressurized", true);
//}
//}
te.filling_ = true;
// IE fluid pipe not available yet
// if(res.getAmount() > 50) {
// final TileEntity fte = te.world.getTileEntity(te.pos.offset(te.block_facing()));
// if(!(fte instanceof IFluidPipe)) {
// CompoundNBT tag = res.getTag();
// if((tag != null) && (tag.contains("pressurized"))) tag.remove("pressurized"); // remove pressureized tag if no IFluidPipe
// }
// }
int n_filled = fh.fill(res, action);
te.filling_ = false;
return n_filled;
@ -284,21 +265,21 @@ public class BlockDecorPipeValve extends BlockDecorDirected implements IWaterLog
@Override public int getTankCapacity(int tank) { return 0; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return false; }
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY.copy(); }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY.copy(); }
@Override public FluidStack drain(FluidStack resource, FluidAction action) { return FluidStack.EMPTY; }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return FluidStack.EMPTY; }
}
// IFluidPipe
// IE IFluidPipe
// @Override
// public boolean hasOutputConnection(Direction side)
// { return (side == block_facing_); }
// { return (side == block_facing()); }
//
// @Override
// public boolean canOutputPressurized(boolean consumePower)
// {
// if(getlocked_ || (!filling_enabled_)) return false;
// final TileEntity te = world.getTileEntity(pos.offset(block_facing_));
// final TileEntity te = world.getTileEntity(pos.offset(block_facing()));
// if(!(te instanceof IFluidPipe)) return false;
// getlocked_ = true; // not sure if IE explicitly pre-detects loops, so let's lock recurion here, too.
// boolean r = ((IFluidPipe)te).canOutputPressurized(consumePower);

View file

@ -418,12 +418,19 @@ public class BlockDecorPlacer extends BlockDecorDirected
{ return (i<NUM_OF_SLOTS-1) ? (i+1) : 0; }
private boolean spit_out(Direction facing)
{ return spit_out(facing, false); }
private boolean spit_out(Direction facing, boolean all)
{
ItemStack stack = stacks_.get(current_slot_index_);
ItemStack drop = stack.copy();
stack.shrink(1);
stacks_.set(current_slot_index_, stack);
drop.setCount(1);
if(!all) {
stack.shrink(1);
stacks_.set(current_slot_index_, stack);
drop.setCount(1);
} else {
stacks_.set(current_slot_index_, ItemStack.EMPTY);
}
for(int i=0; i<8; ++i) {
BlockPos p = pos.offset(facing, i);
if(!world.isAirBlock(p)) continue;
@ -486,7 +493,7 @@ public class BlockDecorPlacer extends BlockDecorDirected
block = Blocks.AIR;
no_space = true;
}
// System.out.println("PLACE " + current_stack + " --> " + block + " at " + placement_pos.subtract(pos) + "( item=" + item + ")");
// println("PLACE " + current_stack + " --> " + block + " at " + placement_pos.subtract(pos) + "( item=" + item + ")");
if(block != Blocks.AIR) {
try {
BlockItemUseContext use_context = null;
@ -524,9 +531,9 @@ public class BlockDecorPlacer extends BlockDecorDirected
// The block really needs a player or other issues happened during placement.
// A hard crash should not be fired here, instead spit out the item to indicated that this
// block is not compatible.
System.out.println("Exception while trying to place " + e);
ModEngineersDecor.logger().error("Exception while trying to place " + ((block==null)?(""):(""+block)) + ", spitting out. Exception is: " + e);
world.removeBlock(placement_pos, false);
return spit_out(facing);
return spit_out(facing, true);
}
}
if((!no_space) && (!current_stack.isEmpty())) {

View file

@ -0,0 +1,312 @@
/*
* @file BlockDecorTest.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Creative mod testing block
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.detail.ModAuxiliaries;
import wile.engineersdecor.detail.ModAuxiliaries.IExperimentalFeature;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.fluid.Fluids;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.Hand;
import net.minecraft.util.Direction;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class BlockDecorTest extends BlockDecorDirected implements IExperimentalFeature
{
public BlockDecorTest(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return VoxelShapes.fullCube(); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BTileEntity(); }
@Override
public boolean canConnectRedstone(BlockState state, IBlockReader world, BlockPos pos, @Nullable Direction side)
{ return true; }
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
// @todo ... there was something like single element list or so ...
ArrayList<ItemStack> list = new ArrayList<ItemStack>();
list.add(new ItemStack(this, 1));
return list;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit)
{
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return false;
((BTileEntity)te).activated(player, hand, hit);
return true;
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, ICapabilityProvider //, IItemHandler, IEnergyStorage
{
private int tick_interval_ = 10;
private int passive_tank_capacity_ = 32000;
private FluidStack passive_tank_ = FluidStack.EMPTY;
private FluidStack passive_drain_fluidstack_ = new FluidStack(Fluids.WATER, 1000);
private int passive_drain_max_flowrate_ = 1000;
private int passive_fill_max_flowrate_ = 1000;
private int passive_num_drained_general_mb_ = 0;
private int passive_num_drained_specific_mb_ = 0;
private int passive_num_filled_specific_mb_ = 0;
private int passive_num_fh_interactions_ = 0;
private FluidStack active_fill_fluidstack_ = FluidStack.EMPTY;
private int active_num_filled_ = 0;
private int tick_timer_ = 0;
// ------------------------------------------------------------------------------------------
public BTileEntity()
{ this(ModContent.TET_TEST_BLOCK); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
// ------------------------------------------------------------------------------------------
private Direction block_facing()
{
BlockState st = getWorld().getBlockState(getPos());
return (st.getBlock() instanceof BlockDecorTest) ? st.get(FACING) : Direction.NORTH;
}
private String dump_fluid_stack(FluidStack fs)
{
String s = "";
if(fs.getFluid().getRegistryName().getNamespace() != "minecraft") s += fs.getFluid().getRegistryName().getNamespace()+":";
s += fs.getFluid().getRegistryName().getPath();
s += " x" + fs.getAmount();
return "[" + s + "]";
}
public void activated(PlayerEntity player, Hand hand, BlockRayTraceResult hit)
{
if(world.isRemote()) return;
final ItemStack held_stack = player.getHeldItem(hand);
// Empty hand -> statistics
{
if(held_stack.isEmpty()) {
String message = "";
if(passive_num_filled_specific_mb_>0 || passive_num_drained_specific_mb_>0 || passive_num_drained_general_mb_>0) {
message += "Fluid handler: filled:" + passive_num_filled_specific_mb_ + ", drained:" + (passive_num_drained_specific_mb_+ passive_num_drained_general_mb_) + ", interactions:" + passive_num_fh_interactions_ + "\n";
}
if(active_num_filled_>0) {
message += "Fluid insertion:" + active_num_filled_ + "mb, (current:" + dump_fluid_stack(active_fill_fluidstack_) + ")\n";
}
if(message.isEmpty()) {
message = "No fluid, energy, or item interactions done yet.";
}
ModAuxiliaries.playerChatMessage(player, message);
return;
}
}
// Fluid container -> set fluid to insert, increase/decrease amount.
{
final IFluidHandlerItem fhi = held_stack.getCapability(CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY).orElse(null);
if((fhi != null)) {
int ntanks = fhi.getTanks();
if(ntanks == 0) return;
int capacity = fhi.getTankCapacity(0);
FluidStack fs = fhi.drain(capacity, FluidAction.SIMULATE);
if(!fs.isEmpty()) {
if(active_fill_fluidstack_.isEmpty()) {
active_fill_fluidstack_ = fs.copy();
ModAuxiliaries.playerChatMessage(player, "Fluid insertion fluid set: " + dump_fluid_stack(active_fill_fluidstack_));
} else if(fs.isFluidEqual(active_fill_fluidstack_)) {
active_fill_fluidstack_.grow(fs.getAmount());
ModAuxiliaries.playerChatMessage(player, "Fluid insertion flowrate increased: " + dump_fluid_stack(active_fill_fluidstack_));
} else {
int amount = active_fill_fluidstack_.getAmount();
active_fill_fluidstack_ = fs.copy();
active_fill_fluidstack_.setAmount(amount);
ModAuxiliaries.playerChatMessage(player, "Fluid insertion fluid changed: " + dump_fluid_stack(active_fill_fluidstack_));
}
} else {
if(!active_fill_fluidstack_.isEmpty()) {
active_fill_fluidstack_.shrink(1000);
if(active_fill_fluidstack_.isEmpty()) active_fill_fluidstack_ = FluidStack.EMPTY;
ModAuxiliaries.playerChatMessage(player, "Fluid insertion flowrate decreased: " + dump_fluid_stack(active_fill_fluidstack_));
} else {
ModAuxiliaries.playerChatMessage(player, "Fluid insertion disabled.");
}
}
passive_drain_fluidstack_ = active_fill_fluidstack_.copy(); // currently no difference
return;
}
}
}
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{
super.read(nbt);
if(nbt.contains("passive_tank")) passive_tank_ = FluidStack.loadFluidStackFromNBT(nbt.getCompound("passive_tank"));
if(nbt.contains("passive_drain")) passive_drain_fluidstack_ = FluidStack.loadFluidStackFromNBT(nbt.getCompound("passive_drain"));
if(nbt.contains("active")) active_fill_fluidstack_ = FluidStack.loadFluidStackFromNBT(nbt.getCompound("active"));
}
@Override
public CompoundNBT write(CompoundNBT nbt)
{
super.write(nbt);
if(!passive_tank_.isEmpty()) nbt.put("passive_tank", passive_tank_.writeToNBT(new CompoundNBT()));
if(!passive_drain_fluidstack_.isEmpty()) nbt.put("passive_drain", passive_drain_fluidstack_.writeToNBT(new CompoundNBT()));
if(!active_fill_fluidstack_.isEmpty()) nbt.put("active", active_fill_fluidstack_.writeToNBT(new CompoundNBT()));
return nbt;
}
// ICapabilityProvider --------------------------------------------------------------------
private LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> (IFluidHandler)new MainFluidHandler(this));
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) {
if(facing != block_facing()) return fluid_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// IFluidHandler ---------------------------------------------------------------------------
private static class MainFluidHandler implements IFluidHandler
{
private BTileEntity te;
public MainFluidHandler(BTileEntity te)
{ this.te = te; }
@Override public int getTanks()
{ return 1; }
@Override public FluidStack getFluidInTank(int tank)
{ return FluidStack.EMPTY; }
@Override public int getTankCapacity(int tank)
{ return te.passive_tank_capacity_; }
@Override public FluidStack drain(FluidStack resource, FluidAction action)
{
++te.passive_num_fh_interactions_;
if(resource.isEmpty()) return FluidStack.EMPTY;
if(!resource.isFluidEqual(te.passive_drain_fluidstack_)) return FluidStack.EMPTY;
FluidStack st = resource.copy();
st.setAmount(MathHelper.clamp(st.getAmount(), 0, te.passive_drain_max_flowrate_));
if(st.isEmpty()) return FluidStack.EMPTY;
if(action==FluidAction.EXECUTE) te.passive_num_drained_specific_mb_ += st.getAmount();
return st;
}
@Override public FluidStack drain(int maxDrain, FluidAction action)
{
++te.passive_num_fh_interactions_;
maxDrain = MathHelper.clamp(maxDrain, 0, te.passive_drain_max_flowrate_);
if((te.passive_drain_fluidstack_.isEmpty()) || (maxDrain<=0)) return FluidStack.EMPTY;
if(action==FluidAction.EXECUTE) te.passive_num_drained_general_mb_ += maxDrain;
FluidStack st = te.passive_drain_fluidstack_.copy();
st.setAmount(maxDrain);
return st;
}
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack)
{ return true; }
@Override public int fill(FluidStack resource, FluidAction action)
{
++te.passive_num_fh_interactions_;
int amount = MathHelper.clamp(resource.getAmount(), 0, te.passive_fill_max_flowrate_);
if(action == FluidAction.EXECUTE) {
te.passive_num_filled_specific_mb_ += amount;
if(te.passive_tank_.isFluidEqual(resource)) {
int level = (int)MathHelper.clamp((long)te.passive_tank_.getAmount() + (long)amount, (long)0, (long)Integer.MAX_VALUE);
te.passive_tank_.setAmount(level);
}
}
return amount;
}
}
// ITickableTileEntity ----------------------------------------------------------------------
private void fluid_insertion()
{
if(active_fill_fluidstack_.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos.offset(block_facing()));
if(te == null) return;
final IFluidHandler fh = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, block_facing().getOpposite()).orElse(null);
if(fh == null) return;
int filled = fh.fill(active_fill_fluidstack_.copy(), FluidAction.EXECUTE);
active_num_filled_ += filled;
}
@Override
public void tick()
{
if(world.isRemote) return;
if(--tick_timer_ > 0) return;
tick_interval_ = MathHelper.clamp(tick_interval_ ,1 , 200);
tick_timer_ = tick_interval_;
fluid_insertion();
}
}
}

View file

@ -11,12 +11,16 @@ package wile.engineersdecor.blocks;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.StateContainer;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
public class BlockDecorWindow extends BlockDecorDirected implements IWaterLoggable
{
public BlockDecorWindow(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
@ -35,4 +39,24 @@ public class BlockDecorWindow extends BlockDecorDirected implements IWaterLoggab
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(WATERLOGGED); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
Direction facing = context.getPlacementHorizontalFacing();
if(Math.abs(context.getPlayer().getLookVec().y) > 0.9) {
facing = context.getNearestLookingDirection();
} else {
for(Direction f: Direction.values()) {
BlockState st = context.getWorld().getBlockState(context.getPos().offset(f));
if(st.getBlock() == this) {
facing = st.get(FACING);
break;
}
}
}
return super.getStateForPlacement(context).with(FACING, facing);
}
}

View file

@ -122,6 +122,7 @@ public class ModConfig
public final ForgeConfigSpec.BooleanValue without_fluid_funnel;
public final ForgeConfigSpec.BooleanValue without_mineral_smelter;
public final ForgeConfigSpec.BooleanValue without_milking_machine;
public final ForgeConfigSpec.BooleanValue without_tree_cutter;
public final ForgeConfigSpec.BooleanValue without_chair_sitting;
public final ForgeConfigSpec.BooleanValue without_mob_chair_sitting;
public final ForgeConfigSpec.BooleanValue without_ladder_speed_boost;
@ -301,6 +302,10 @@ public class ModConfig
.translation(ModEngineersDecor.MODID + ".config.without_milking_machine")
.comment("Disable the small milking machine.")
.define("without_milking_machine", false);
without_tree_cutter = builder
.translation(ModEngineersDecor.MODID + ".config.without_tree_cutter")
.comment("Disable the small tree cutter.")
.define("without_tree_cutter", false);
without_slabs = builder
.translation(ModEngineersDecor.MODID + ".config.without_slabs")
.comment("Disable horizontal half-block slab.")
@ -533,6 +538,7 @@ public class ModConfig
if(block instanceof BlockDecorSolarPanel) return COMMON.without_solar_panel.get();
if(block instanceof BlockDecorMineralSmelter) return COMMON.without_mineral_smelter.get();
if(block instanceof BlockDecorMilker) return COMMON.without_milking_machine.get();
if(block instanceof BlockDecorTreeCutter) return COMMON.without_tree_cutter.get();
// Type based evaluation where later filters may match, too
if(COMMON.without_slabs.get() && (block instanceof BlockDecorSlab)) return true;
if(COMMON.without_stairs.get() && (block instanceof BlockDecorStairs)) return true;

View file

@ -1,7 +1,7 @@
# @file mods.toml
# @spec TOML v0.5.0 (https://github.com/toml-lang/toml)
modLoader="javafml" # forge FML java
loaderVersion="[25,)"
modLoader="javafml"
loaderVersion="[28,)"
issueTrackerURL="https://github.com/stfwi/engineers-decor/issues/"
[[mods]]

View file

@ -0,0 +1,10 @@
{
"variants": {
"facing=north": { "model": "engineersdecor:block/generic/test_block_model" },
"facing=south": { "model": "engineersdecor:block/generic/test_block_model", "y":180 },
"facing=west": { "model": "engineersdecor:block/generic/test_block_model", "y":270 },
"facing=east": { "model": "engineersdecor:block/generic/test_block_model", "y":90 },
"facing=up": { "model": "engineersdecor:block/generic/test_block_model", "x":270 },
"facing=down": { "model": "engineersdecor:block/generic/test_block_model", "x":90 }
}
}

View file

@ -170,9 +170,9 @@
"block.engineersdecor.factory_dropper": "Factory Dropper",
"block.engineersdecor.factory_dropper.help": "§6Dropper suitable for advanced factory automation.§r Has twelve round-robin selected slots. Drop force, angle, stack size, and cool-down delay adjustable using sliders in the GUI. Three stack compare slots (below the inventory slots) with logical AND or OR can be used as internal trigger source. The internal trigger can be AND'ed or OR'ed with the external redstone signal trigger. Trigger simulation buttons for testing. Pre-opens shutter door when internal trigger conditions are met. Drops all matching stacks simultaneously. Simply click on all elements in the GUI to see how it works.",
"block.engineersdecor.factory_hopper": "Factory Hopper",
"block.engineersdecor.factory_hopper.help": "§6Hopper suitable for advanced factory automation.§r Can transfer half-stacks, max collection range 9x9.\n GUI Slider controls: Collection range (0 to 4), insertion delay (0.5s to 10s), insertion stack size (1 to 32).\\n GUI Redstone controls: Not inverted / inverted (default), pulse mode / continuous mode (default).",
"block.engineersdecor.factory_hopper.help": "§6Hopper suitable for advanced factory automation.§r Can transfer half-stacks, max collection range 9x9.\n GUI Slider controls: Collection range (0 to 4), insertion delay (0.5s to 10s), insertion stack size (1 to 32).\n GUI Redstone controls: Not inverted / inverted (default), pulse mode / continuous mode (default).",
"block.engineersdecor.factory_placer": "Factory Block Placer",
"block.engineersdecor.factory_placer.help": "§6Allows placing blocks and planting crops or trees.§r\n GUI Redstone controls: Not inverted / inverted (default), pulse mode / continuous mode (default).\\n Also supports spike planing from underneath the soil. Spits out items that it cannot place or plant.",
"block.engineersdecor.factory_placer.help": "§6Allows placing blocks and planting crops or trees.§r\n GUI Redstone controls: Not inverted / inverted (default), pulse mode / continuous mode (default).\n Also supports spike planing from underneath the soil. Spits out items that it cannot place or plant.",
"block.engineersdecor.small_block_breaker": "Small Block Breaker",
"block.engineersdecor.small_block_breaker.help": "§6Breaks blocks in front of it.§r\n Can be disabled by applying a redstone signal. The time needed to destroy a block depends on the hardness of that block. ${!block_breaker_requires_power?engineersdecor.tooltip.massive_speed_boost_with_rf_power} ${block_breaker_requires_power?engineersdecor.tooltip.requires_rf_power}",
"block.engineersdecor.small_mineral_smelter": "Small Mineral Melting Furnace",

View file

@ -7,8 +7,8 @@
"engineersdecor.tooltip.hint.extended": "§6[§9SHIFT§r 查看更多信息§6]§r",
"engineersdecor.tooltip.hint.help": "§6[§9CTRL-SHIFT§r 查看帮助§6]§r",
"engineersdecor.tooltip.slabpickup.help": "§r手持同类台阶往上/下看时单击该台阶可无需破坏快速拾起。",
"engineersdecor.tooltip.requires_rf_power": "Requires RF power.",
"engineersdecor.tooltip.massive_speed_boost_with_rf_power": "Apply RF power to magnificently increase the speed.",
"engineersdecor.tooltip.requires_rf_power": "需要RF能量。",
"engineersdecor.tooltip.massive_speed_boost_with_rf_power": "提供RF能量可显著提升速度。",
"engineersdecor.config.pattern_excludes": "模式不包括",
"engineersdecor.config.pattern_includes": "模式包括",
"engineersdecor.config.without_clinker_bricks": "不要过烧砖",
@ -59,7 +59,8 @@
"block.engineersdecor.slag_brick_block.help": "§6一种放在不同位置贴图有不同变化的灰棕色砖块。",
"block.engineersdecor.rebar_concrete": "钢筋混凝土",
"block.engineersdecor.rebar_concrete.help": "§6钢强化的混凝土。§r昂贵但像黑曜石一样防爬行者爆炸。",
"block.engineersdecor.gas_concrete": "Gas Concrete Block",
"block.engineersdecor.gas_concrete": "加气混凝土",
"block.engineersdecor.gas_concrete.help": "§6低硬度高产出的混凝土。§r容易破坏的装饰性混凝土方块。",
"block.engineersdecor.panzerglass_block": "装甲玻璃块",
"block.engineersdecor.panzerglass_block.help": "§6强化的玻璃方块。§r昂贵防爆。深灰色调有隐约可见的结构线和多种纹理外观无光泽。",
"block.engineersdecor.rebar_concrete_tile": "钢筋混凝土砖",
@ -74,7 +75,8 @@
"block.engineersdecor.rebar_concrete_slab.help": "§6钢强化的混凝土台阶。§r昂贵但像黑曜石一样防爬行者爆炸。",
"block.engineersdecor.rebar_concrete_tile_slab": "钢筋混凝土砖台阶",
"block.engineersdecor.rebar_concrete_tile_slab.help": "§6钢强化的混凝土砖台阶。§r昂贵但像黑曜石一样防爬行者爆炸。",
"block.engineersdecor.gas_concrete_slab": "Gas Concrete Slab",
"block.engineersdecor.gas_concrete_slab": "加气混凝土台阶",
"block.engineersdecor.gas_concrete_slab.help": "§6低硬度的混凝土台阶。§r容易破坏的装饰性混凝土。",
"block.engineersdecor.panzerglass_slab": "装甲玻璃台阶",
"block.engineersdecor.panzerglass_slab.help": "§6强化的玻璃台阶。§r昂贵防爆。深灰色调有隐约可见的结构线和多种纹理。",
"block.engineersdecor.treated_wood_floor": "防腐木地板",
@ -83,7 +85,8 @@
"block.engineersdecor.rebar_concrete_wall.help": "§6钢强化的混凝土墙。§r 昂贵但像黑曜石一样防爬行者爆炸。",
"block.engineersdecor.concrete_wall": "混凝土墙",
"block.engineersdecor.concrete_wall.help": "§6用坚固混凝土制造的墙。",
"block.engineersdecor.gas_concrete_wall": "Gas Concrete Wall",
"block.engineersdecor.gas_concrete_wall": "加气混凝土墙",
"block.engineersdecor.gas_concrete_wall.help": "§6低硬度的混凝土墙。§r容易破坏的装饰性混凝土。",
"block.engineersdecor.clinker_brick_wall": "过烧砖墙",
"block.engineersdecor.clinker_brick_wall.help": "§6简单的过烧砖墙。",
"block.engineersdecor.slag_brick_wall": "炉渣砖墙",
@ -104,7 +107,8 @@
"block.engineersdecor.rebar_concrete_stairs.help": "§6钢强化的混凝土楼梯。§r昂贵但像黑曜石一样防爬行者爆炸。",
"block.engineersdecor.rebar_concrete_tile_stairs": "钢筋混凝土砖楼梯",
"block.engineersdecor.rebar_concrete_tile_stairs.help": "§6钢强化的混凝土砖楼梯。§r昂贵但像黑曜石一样防爬行者爆炸。",
"block.engineersdecor.gas_concrete_stairs": "Gas Concrete Stairs",
"block.engineersdecor.gas_concrete_stairs": "加气混凝土楼梯",
"block.engineersdecor.gas_concrete_stairs.help": "§6低硬度的混凝土楼梯。§r容易破坏的装饰性混凝土。",
"block.engineersdecor.treated_wood_pole": "直防腐木杆",
"block.engineersdecor.treated_wood_pole.help": "§6直杆的一段有着继电器的直径。§r\n 在需要特殊长度电线杆的时候很有用, 也可以作为结构的柱子。",
"block.engineersdecor.treated_wood_pole_head": "直防腐木杆头/尾",
@ -135,7 +139,8 @@
"block.engineersdecor.treated_wood_side_table.help": "§6干完活后需要喝杯茶。",
"block.engineersdecor.iron_inset_light": "嵌入灯",
"block.engineersdecor.iron_inset_light.help": "§6小型荧石光源能嵌入地板、天花板或墙里。§r\n 用于照亮电力光源难以安装的地方。 亮度与火把一样。",
"block.engineersdecor.iron_floor_edge_light": "Inset Floor Edge Light",
"block.engineersdecor.iron_floor_edge_light": "嵌入地板边缘灯",
"block.engineersdecor.iron_floor_edge_light.help": "§6小型荧石光源置于地板方块边缘。§r\n 用于照亮电力光源难以安装的地方。",
"block.engineersdecor.treated_wood_window": "防腐木窗",
"block.engineersdecor.treated_wood_window.help": "§6木框三层玻璃窗。绝缘良好。§r不像玻璃板一样连接到相邻方块。",
"block.engineersdecor.treated_wood_windowsill": "防腐木窗台",
@ -160,19 +165,24 @@
"block.engineersdecor.straight_pipe_valve_redstone_analog.help": "§6一段直输液管。§r单向传递流体。 侧面不会与管道连接。会减少流速。潜行能反方向放置。 没有红石信号时断流流速与红石信号强度从1到14线性增长 15时流速上限达到最大。",
"block.engineersdecor.passive_fluid_accumulator": "被动流体累积器。",
"block.engineersdecor.passive_fluid_accumulator.help": "§6基于真空吸力的流体收集器。§r有一个输出面其他面都是输入。 当从输出面被泵抽取时,从输入面邻接储罐抽取液体。",
"block.engineersdecor.small_fluid_funnel": "Small Fluid Collection Funnel",
"block.engineersdecor.small_fluid_funnel": "小型流体收集漏斗",
"block.engineersdecor.small_fluid_funnel.help": "§6收集上方的流体。§r有一个三桶大的内部储罐。会 追溯流体到附近的源方块。流体可被流体运输系统或桶 移出。只会装满下方的储罐(重力传输)。与原版 无限水兼容。",
"block.engineersdecor.factory_dropper": "工厂掉落器",
"block.engineersdecor.factory_dropper.help": "§6适用于高级工厂自动化的掉落器。§r有十二个轮询选择的储物格。 掉落的力度、角度、一叠数量和冷却延时可在GUI调节。三个 内部比较槽带有逻辑与或逻辑或功能,可用作内部触发源。内部触发 还能和外部红石信号触发再进行逻辑与或逻辑或。触发模拟按钮仅作测试用途。 当内部触发条件满足时,预先打开卷帘门。所有符合条件的物品 会同时掉落。点击GUI的各处来了解如何运作。",
"block.engineersdecor.factory_hopper": "Factory Hopper",
"block.engineersdecor.factory_placer": "Factory Block Placer",
"block.engineersdecor.small_block_breaker": "Factory Block Breaker",
"block.engineersdecor.factory_hopper": "工厂漏斗",
"block.engineersdecor.factory_hopper.help": "§6适用于高级工厂自动化的漏斗。§r可一次传输半组物品最大收集范围9x9。\n GUI滑动条控制收集距离0到4插入延迟0.5秒到10秒插入一叠物品的大小1到32。\n GUI红石控制不反相/反相(默认),脉冲模式/持续模式(默认)。",
"block.engineersdecor.factory_placer": "工厂方块放置器",
"block.engineersdecor.factory_placer.help": "§6能够放置方块和种植作物或树。§r\n GUI红石控制不反相/反相(默认),脉冲模式/持续模式(默认)。\n 也支持从耕地下方穿透方块种植。会吐出不能放置或种植的物品。",
"block.engineersdecor.small_block_breaker": "工厂方块破坏器",
"block.engineersdecor.small_block_breaker.help": "§6破坏其正前方的方块。§r\n 通入红石信号可以停止破坏。 破坏一个方块需要的时间取决于其硬度。 ${!block_breaker_requires_power?engineersdecor.tooltip.massive_speed_boost_with_rf_power} ${block_breaker_requires_power?engineersdecor.tooltip.requires_rf_power}",
"block.engineersdecor.small_mineral_smelter": "小型矿物熔炼炉",
"block.engineersdecor.small_mineral_smelter.help": "§6高温、高绝缘电熔石炉。§r\n 把矿物块加热成岩浆块,最后变成熔岩。由于 小型化的设备大小,该过程效率不高,需要大量时间和能源 来液化一块石头。",
"block.engineersdecor.small_solar_panel": "小型太阳能板",
"block.engineersdecor.small_solar_panel.help": "§6暴露在阳光下时产生少量能量。§r\n 用于低消耗地在远程系统给低压电容器充电。 内部电荷泵电路积累并频繁输出RF。产出取决于时间 和天气。",
"block.engineersdecor.small_tree_cutter": "小型砍树机",
"block.engineersdecor.small_tree_cutter.help": "§6砍倒正前方的树。§r\n 不收集木材。通入红石信号停用。 提供RF来加快砍树速度。没有的话会很慢。",
"block.engineersdecor.small_milking_machine": "Small Milking Machine",
"block.engineersdecor.small_milking_machine": "小型挤奶机",
"block.engineersdecor.small_milking_machine.help": "§6偶尔给奶牛梳理和挤奶。§r\n 有一个内置流体储罐。不会喂食动物。使用桶获得牛奶。 从后方或下方的方块物品栏拉取或存储牛奶容器物品(偏好 从下方输入,从后方输出,但也能将装满的牛奶容器放回原来 的物品栏)支持将牛奶作为流体输出到下方的储罐和管道(只要牛奶是流体)。 小心牛栏里不要太拥挤,只有快乐的动物才会自觉地在挤奶机前散步。",
"block.engineersdecor.sign_decor": "标志板(工程师的装饰)",
"block.engineersdecor.sign_decor.help": "§6这不应该可合成或在JEI看到。用于创造模式的物品栏标签和截屏。",
"block.engineersdecor.sign_hotwire": "指示牌 \"小心电线\"",
@ -190,7 +200,8 @@
"block.engineersdecor.halfslab_rebar_concrete.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。",
"block.engineersdecor.halfslab_concrete": "混凝土切片",
"block.engineersdecor.halfslab_concrete.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。",
"block.engineersdecor.halfslab_gas_concrete": "Gas Concrete Slice",
"block.engineersdecor.halfslab_gas_concrete": "加气混凝土切片",
"block.engineersdecor.halfslab_gas_concrete.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。",
"block.engineersdecor.halfslab_treated_wood": "防腐木切片",
"block.engineersdecor.halfslab_treated_wood.help": "§6可垂直堆叠的切片。§r手持切片右/左击切片堆叠的顶端或底部来添加/移除切片。",
"block.engineersdecor.halfslab_sheetmetal_iron": "铁板金属块切片",

View file

@ -0,0 +1,39 @@
{
"parent": "block/block",
"textures": {
"top": "engineersdecor:block/furnace/small_electrical_furnace_top",
"particle": "engineersdecor:block/furnace/small_electrical_furnace_top",
"bottom": "engineersdecor:block/furnace/small_electrical_furnace_bottom",
"left": "engineersdecor:block/furnace/small_electrical_furnace_left",
"right": "engineersdecor:block/furnace/small_electrical_furnace_right",
"front": "engineersdecor:block/furnace/small_electrical_furnace_front",
"back": "engineersdecor:block/furnace/small_electrical_furnace_back"
},
"elements": [
{
"from": [0, 0, 0],
"to": [16, 16, 16],
"faces": {
"north": {"texture": "#front"},
"east": {"texture": "#right"},
"south": {"texture": "#back"},
"west": {"texture": "#left"},
"up": {"texture": "#top"},
"down": {"texture": "#bottom"}
}
}
],
"display": {
"ground": {
"translation": [0, 1.75, 0],
"scale": [0.2, 0.2, 0.2]
},
"gui": {
"rotation": [30, 225, 0],
"scale": [0.625, 0.625, 0.625]
},
"fixed": {
"scale": [0.5, 0.5, 0.5]
}
}
}

View file

@ -0,0 +1,12 @@
{
"parent": "engineersdecor:block/generic/directed_cube",
"textures": {
"top": "engineersdecor:block/furnace/small_electrical_furnace_bottom",
"particle": "engineersdecor:block/furnace/small_electrical_furnace_bottom",
"bottom": "engineersdecor:block/furnace/small_electrical_furnace_bottom",
"left": "engineersdecor:block/furnace/small_electrical_furnace_bottom",
"right": "engineersdecor:block/furnace/small_electrical_furnace_bottom",
"front": "engineersdecor:block/furnace/small_electrical_furnace_top",
"back": "engineersdecor:block/furnace/small_electrical_furnace_bottom"
}
}

View file

@ -7,8 +7,9 @@
},
"elements": [
{
"from": [6, 0.1875, 0.5],
"to": [10, 1.8125, 1],
"from": [6, 0, 0],
"to": [10, 1.8125, 0.375],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 7.5]},
"faces": {
"north": {"uv": [6, 14.1875, 10, 15.8125], "texture": "#light"},
"south": {"uv": [6, 14.1875, 10, 15.8125], "texture": "#light"},
@ -16,9 +17,9 @@
}
},
{
"from": [10, 0.1875, 0.5],
"to": [11, 1.8125, 1],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 8.125]},
"from": [10, 0, 0],
"to": [11, 1.8125, 0.375],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 7.625]},
"faces": {
"north": {"uv": [5, 14.1875, 6, 15.8125], "texture": "#side"},
"east": {"uv": [15, 14.1875, 15.5, 15.8125], "texture": "#side"},
@ -29,9 +30,9 @@
}
},
{
"from": [5, 0.1875, 0.5],
"to": [6, 1.8125, 1],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 8.125]},
"from": [5, 0, 0],
"to": [6, 1.8125, 0.375],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 7.625]},
"faces": {
"north": {"uv": [10, 14.1875, 11, 15.8125], "texture": "#side"},
"east": {"uv": [15, 14.1875, 15.5, 15.8125], "texture": "#side"},
@ -40,30 +41,6 @@
"up": {"uv": [5, 0.5, 6, 1], "texture": "#side"},
"down": {"uv": [5, 15, 6, 15.5], "texture": "#side"}
}
},
{
"from": [5, 0, 0],
"to": [11, 2, 0.5],
"faces": {
"north": {"uv": [5, 14, 11, 16], "texture": "#side"},
"east": {"uv": [15.5, 14, 16, 16], "texture": "#side"},
"south": {"uv": [5, 14, 11, 16], "texture": "#side"},
"west": {"uv": [0, 14, 0.5, 16], "texture": "#side"},
"up": {"uv": [5, 0, 11, 0.5], "texture": "#side"},
"down": {"uv": [5, 15.5, 11, 16], "texture": "#side"}
}
},
{
"from": [5, 0, 0.5],
"to": [11, 0.1875, 1],
"faces": {
"north": {"uv": [5, 15.8125, 11, 16], "texture": "#side"},
"east": {"uv": [15, 15.8125, 15.5, 16], "texture": "#side"},
"south": {"uv": [5, 15.8125, 11, 16], "texture": "#side"},
"west": {"uv": [0.5, 15.8125, 1, 16], "texture": "#side"},
"up": {"uv": [5, 0.5, 11, 1], "texture": "#side"},
"down": {"uv": [5, 15, 11, 15.5], "texture": "#side"}
}
}
],
"display": {
@ -76,7 +53,7 @@
"translation": [-3, -0.75, 1.25]
},
"ground": {
"translation": [0, 2.5, 6],
"translation": [0, 1.75, 0],
"scale": [0.7, 0.7, 0.7]
},
"gui": {

View file

@ -1 +1 @@
{ "parent": "engineersdecor:block/pipe/straight_pipe_valve_model" }
{ "parent": "engineersdecor:block/pipe/straight_pipe_valve_redstone_analog_model" }

View file

@ -0,0 +1 @@
{ "parent": "engineersdecor:block/generic/test_block_model" }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 624 B

After

Width:  |  Height:  |  Size: 605 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 B

After

Width:  |  Height:  |  Size: 591 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 513 B

Before After
Before After

View file

@ -8,8 +8,6 @@
],
"type": "minecraft:crafting_shaped",
"pattern": [
" ",
" ",
"CCC"
],
"key": {

View file

@ -0,0 +1,16 @@
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:clinker_brick_block",
"required": ["engineersdecor:clinker_brick_stained_block"]
}
],
"type": "minecraft:crafting_shapeless",
"ingredients": [
{ "item": "engineersdecor:clinker_brick_stained_block" }
],
"result": {
"item": "engineersdecor:clinker_brick_block"
}
}

View file

@ -8,8 +8,6 @@
],
"type": "minecraft:crafting_shaped",
"pattern": [
" ",
" ",
"CCC"
],
"key": {

View file

@ -0,0 +1,21 @@
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:clinker_brick_stained_block",
"required": ["engineersdecor:clinker_brick_stained_slab"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"B",
"B"
],
"key": {
"B": { "item": "engineersdecor:clinker_brick_stained_slab" }
},
"result": {
"item": "engineersdecor:clinker_brick_stained_block",
"count": 1
}
}

View file

@ -0,0 +1,23 @@
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:gas_concrete_slab",
"required": ["engineersdecor:halfslab_gas_concrete"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"SS",
"SS"
],
"key": {
"S": {
"item": "engineersdecor:halfslab_gas_concrete"
}
},
"result": {
"item": "engineersdecor:gas_concrete_slab",
"count": 1
}
}

View file

@ -8,8 +8,6 @@
],
"type": "minecraft:crafting_shaped",
"pattern": [
" ",
" ",
"CCC"
],
"key": {

View file

@ -0,0 +1,21 @@
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:gas_concrete",
"required": ["engineersdecor:gas_concrete_slab"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"B",
"B"
],
"key": {
"B": { "item": "engineersdecor:gas_concrete_slab" }
},
"result": {
"item": "engineersdecor:gas_concrete",
"count": 1
}
}

View file

@ -0,0 +1,23 @@
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:rebar_concrete_slab",
"required": ["engineersdecor:halfslab_rebar_concrete"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"SS",
"SS"
],
"key": {
"S": {
"item": "engineersdecor:halfslab_rebar_concrete"
}
},
"result": {
"item": "engineersdecor:rebar_concrete_slab",
"count": 1
}
}

View file

@ -8,8 +8,6 @@
],
"type": "minecraft:crafting_shaped",
"pattern": [
" ",
" ",
"CCC"
],
"key": {

View file

@ -0,0 +1,23 @@
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:rebar_concrete",
"required": ["engineersdecor:rebar_concrete_slab"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"C",
"C"
],
"key": {
"C": {
"item": "engineersdecor:rebar_concrete_slab"
}
},
"result": {
"item": "engineersdecor:rebar_concrete",
"count": 1
}
}

View file

@ -0,0 +1,23 @@
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:rebar_concrete_tile",
"required": ["engineersdecor:rebar_concrete_tile_slab"]
}
],
"type": "minecraft:crafting_shaped",
"pattern": [
"C",
"C"
],
"key": {
"C": {
"item": "engineersdecor:rebar_concrete_tile_slab"
}
},
"result": {
"item": "engineersdecor:rebar_concrete_tile",
"count": 1
}
}

37
1.15/.gitignore vendored Normal file
View file

@ -0,0 +1,37 @@
bin
*.launch
.settings
.metadata
.classpath
.project
out
*.ipr
*.iws
*.iml
.idea
build
.gradle
*.tmp
*.log
*.jks
eclipse
run
tests
/dist
signing.*
src/main/java/archive
src/main/resources/assets/minecraft
.vscode
/classes
/dev
/tmp
/archive
/assets-src
.gimp
*.xcf
desktop.ini
.DS_Store
Thumbs.db
forge*changelog.txt
/*.txt
mcmodsrepo

92
1.15/Makefile Normal file
View file

@ -0,0 +1,92 @@
# @file Makefile
# @author Stefan Wilhelm (wile)
# @license MIT
#
# GNU Make makefile based build relay.
# Note for reviewers/clones: This file is a auxiliary script for my setup.
# It's not needed to build the mod.
#
MOD_JAR_PREFIX=engineersdecor-
MOD_JAR=$(filter-out %-sources.jar,$(wildcard build/libs/${MOD_JAR_PREFIX}*.jar))
ifeq ($(OS),Windows_NT)
GRADLE=gradlew.bat --no-daemon
GRADLE_STOP=gradlew.bat --stop
DJS=djs
else
GRADLE=./gradlew --no-daemon
GRADLE_STOP=./gradlew --stop
DJS=djs
endif
wildcardr=$(foreach d,$(wildcard $1*),$(call wildcardr,$d/,$2) $(filter $(subst *,%,$2),$d))
#
# Targets
#
.PHONY: default mod data init clean clean-all mrproper all run install sanatize dist-check dist start-server assets
default: mod
all: clean clean-all mod | install
mod: data
@echo "[1.15] Building mod using gradle ..."
@$(GRADLE) build $(GRADLE_OPTS)
data:
@echo "[1.15] Running data generators ..."
@djs tasks.js datagen
clean:
@echo "[1.15] Cleaning ..."
@rm -rf src/generated
@rm -rf mcmodsrepo
@rm -f build/libs/*
@$(GRADLE) clean
clean-all:
@echo "[1.15] Cleaning using gradle ..."
@rm -rf mcmodsrepo
@rm -f dist/*
@rm -rf run/logs/
@rm -rf run/crash-reports/
@$(GRADLE) clean
mrproper: clean-all
@rm -f meta/*.*
@rm -rf run/
@rm -rf out/
@rm -f .project
@rm -f .classpath
init:
@echo "[1.15] Initialising eclipse workspace using gradle ..."
@$(GRADLE) eclipse
sanatize:
@echo "[1.15] Running sanatising tasks ..."
@djs tasks.js trailing-whitespaces
@djs tasks.js tabs-to-spaces
@djs tasks.js sync-languages
@djs tasks.js version-check
@djs tasks.js update-json
@git status -s .
dist-check:
@echo "[1.15] Running dist checks ..."
@djs tasks.js dist-check
dist-files: clean-all init mod
@echo "[1.15] Distribution files ..."
@mkdir -p dist
@cp build/libs/$(MOD_JAR_PREFIX)* dist/
@djs tasks.js dist
dist: sanatize dist-check dist-files
assets:
@echo "[1.15] Running asset generators ..."
@djs tasks.js create-slab-assets
@djs tasks.js create-half-slab-assets
@djs tasks.js assets

102
1.15/build.gradle Normal file
View file

@ -0,0 +1,102 @@
// @file build.gradle
// Engineer's decor mod gradle build relay (mc1.15.1)
buildscript {
repositories {
maven { url = 'https://files.minecraftforge.net/maven' }
jcenter()
mavenCentral()
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true
}
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse'
apply plugin: 'maven-publish'
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8'
//-----------------------------------------------------------------------------
version = "${version_engineersdecor}"
group = "wile.engineersdecor"
archivesBaseName = "engineersdecor-${version_minecraft}"
def signingData = { ->
def sp = new Properties()
if(file("signing.properties").exists()) file("signing.properties").withInputStream { sp.load(it) }
return sp
}()
repositories {
maven { name = "Progwml6 maven"; url = "https://dvs1.progwml6.com/files/maven/" } // JEI files
maven { name = "ModMaven"; url = "modmaven.k-4u.nl" } // JEI files, fallback
}
minecraft {
mappings channel: 'snapshot', version: "${version_fml_mappings}"
// accessTransformer = file('build/resources/main/META-INF/accesstransformer.cfg')
runs {
client {
workingDirectory project.file('run')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
mods {
engineersdecor {
source sourceSets.main
}
}
}
server {
workingDirectory project.file('run')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
mods {
engineersdecor {
source sourceSets.main
}
}
}
data {
workingDirectory project.file('run')
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
property 'forge.logging.console.level', 'debug'
args '--mod', 'engineersdecor', '--all', '--output', file('src/generated/resources/')
mods {
engineersdecor {
source sourceSets.main
}
}
}
}
}
dependencies {
minecraft "net.minecraftforge:forge:${version_forge_minecraft}"
//compileOnly fg.deobf("mezz.jei:jei-${version_jei}:api")
//runtimeOnly fg.deobf("mezz.jei:jei-${version_jei}")
}
processResources {
outputs.upToDateWhen { false } // thx to @tterrag for this hint
doLast { file("${sourceSets.main.output.resourcesDir}/.gitversion").text = 'git log "-1" "--format=%h"'.execute().in.text.trim() }
}
jar {
manifest {
attributes([
"Specification-Title": "engineersdecor",
"Specification-Vendor": "wilechaote",
"Specification-Version": "1", // We are version 1 of ourselves
"Implementation-Title": project.name,
"Implementation-Version": "${version_engineersdecor}",
"Implementation-Vendor" :"wilechaote",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
])
}
}
def reobfFile = file("$buildDir/reobfJar/output.jar")
def reobfArtifact = artifacts.add('default', reobfFile) { type 'jar'; builtBy 'reobfJar'; }
publishing {
publications { mavenJava(MavenPublication) { artifact reobfArtifact } }
repositories { maven { url "file:///${project.projectDir}/mcmodsrepo" } }
}

8
1.15/gradle.properties Normal file
View file

@ -0,0 +1,8 @@
# @file gradle.properties
org.gradle.daemon=false
org.gradle.jvmargs=-Xmx8G
version_minecraft=1.15.1
version_forge_minecraft=1.15.1-30.0.16
version_fml_mappings=20190719-1.14.3
version_jei=1.14.4:6.0.0.10
version_engineersdecor=1.0.18-b1

BIN
1.15/gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip

172
1.15/gradlew vendored Normal file
View file

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
1.15/gradlew.bat vendored Normal file
View file

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View file

@ -0,0 +1,61 @@
#!/usr/bin/djs
// run from tasks.js directory
"use strict";
(function(constants, libassets){
const me = {};
const modid = constants.mod_registry_name();
const assets_root = constants.local_assets_root();
const hexchar = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e']; // ('a'+parts) won't work so here we go
const create_item_model = function(prefix, texture) {
const model = {
parent: modid+":block/slab/generic/halfslab_inventory_model",
textures: { all: texture }
}
const path = "models/item/halfslab_"+prefix+".json";
if(!fs.writefile(path, JSON.stringify(model))) {
throw new Error("Failed to write item model file '"+ path +"'");
}
};
const create_block_models = function(prefix, texture) {
for(var parts=0; parts<15; ++parts) {
const model = {
parent: modid+":block/slab/generic/halfslab_s"+hexchar[parts]+"_model",
textures: { all:texture }
}
const path = "models/block/slab/specific/halfslab_"+prefix+"_s"+hexchar[parts]+"_model.json";
if(!fs.writefile(path, JSON.stringify(model))) {
throw new Error("Failed to write model file '"+ path +"'");
}
}
};
const create_blockstate = function(prefix) {
var variants = {};
for(var parts=0; parts<15; ++parts) {
variants[ ("parts="+parts).replace(/[\s]/g,"") ] = {
model: (modid+":block/slab/specific/halfslab_"+prefix+"_s"+hexchar[parts]+"_model").replace(/[\s]/g,"")
}
}
const path = "blockstates/halfslab_"+prefix+".json";
if(!fs.writefile(path, JSON.stringify({variants:variants},null,1))) throw new Error("Failed to write blockstate '"+path+"'");
return path;
};
me.create = function(data) {
const here = fs.cwd()
const registry_name_prefix = data.name_prefix;
const texture = data.texture;
if(!fs.chdir(assets_root)) throw new Error("Could not switch to assets root folder: '" + assets_root + "'");
try {
create_block_models(registry_name_prefix, texture);
create_item_model(registry_name_prefix, texture);
create_blockstate(registry_name_prefix, texture);
} finally {
fs.chdir(here);
}
}
Object.freeze(me);
return me;
});

View file

@ -0,0 +1,64 @@
#!/usr/bin/djs
// run from tasks.js directory
"use strict";
(function(constants, libassets){
const me = {};
const modid = constants.mod_registry_name();
const assets_root = constants.local_assets_root();
const create_item_model = function(prefix, texture_prefix) {
const model = {
parent: modid+":block/slab/generic/slab_inventory_model",
textures: { all: modid+":block/"+texture_prefix+"0" }
}
const path = "models/item/"+prefix+"_slab.json";
if(!fs.writefile(path, JSON.stringify(model))) {
throw new Error("Failed to write item model file '"+ path +"'");
}
};
const create_block_models = function(prefix, texture_prefix) {
for(var parts=0; parts<3; ++parts) {
for(var tvariant=0; tvariant<4; ++tvariant) {
const model = {
parent: modid+":block/slab/generic/slab_s"+parts+"_model",
textures: { all: modid+":block/"+texture_prefix+tvariant }
}
const path = "models/block/slab/specific/"+prefix+"_slab_s"+parts+"v"+tvariant+"_model.json";
if(!fs.writefile(path, JSON.stringify(model))) {
throw new Error("Failed to write model file '"+ path +"'");
}
}
}
};
const create_blockstate = function(prefix) {
var variants = {};
for(var parts=0; parts<3; ++parts) {
for(var tvariant=0; tvariant<4; ++tvariant) {
variants[ ("parts="+parts+",tvariant="+tvariant).replace(/[\s]/g,"") ] = {
model: (modid+":block/slab/specific/"+prefix+"_slab_s"+parts+"v"+tvariant+"_model").replace(/[\s]/g,"")
}
}
}
const path = "blockstates/"+prefix+"_slab.json";
if(!fs.writefile(path, JSON.stringify({variants:variants},null,1))) throw new Error("Failed to write blockstate '"+path+"'");
return path;
};
me.create = function(prefixes) {
const here = fs.cwd()
const registry_name_prefix = prefixes.name_prefix;
const texture_prefix = prefixes.texture_prefix;
if(!fs.chdir(assets_root)) throw new Error("Could not switch to assets root folder: '" + assets_root + "'");
try {
create_block_models(registry_name_prefix, texture_prefix);
create_item_model(registry_name_prefix, texture_prefix);
create_blockstate(registry_name_prefix, texture_prefix);
} finally {
fs.chdir(here);
}
}
Object.freeze(me);
return me;
});

11
1.15/meta/update.json Normal file
View file

@ -0,0 +1,11 @@
{
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
"1.15.1": {
"1.0.18-b1": "[U] Updated to Forge 1.15.1-30.0.16/20190719-1.14.3.\n[F] Client setup Dist annotation fixed (issue #73, thx hitsu420).\n[F] Double newline escapes in lang files fixed (\"\\n\" in a tooltip).\n[M] Updated zh_cn lang file (scikirbypoke).\n[A] Added opt-out config for the Small Tree Cutter",
"1.0.17-b2": "[A] Initial port."
},
"promos": {
"1.15.1-recommended": "",
"1.15.1-latest": "1.0.18-b1"
}
}

22
1.15/readme.md Normal file
View file

@ -0,0 +1,22 @@
## Engineer's Decor (MC1.15.1)
Mod sources for Minecraft version 1.15.1.
- Description, credits, and features: Please see the readme in the repository root.
- Compiled mod distribution channel is curseforge: https://www.curseforge.com/minecraft/mc-mods/engineers-decor/files.
----
## Version history
- v1.0.18-b1 [U] Updated to Forge 1.15.1-30.0.16/20190719-1.14.3.
[F] Client setup Dist annotation fixed (issue #73, thx hitsu420).
[F] Double newline escapes in lang files fixed ("\n" in a tooltip).
[M] Updated zh_cn lang file (scikirbypoke).
[A] Added opt-out config for the Small Tree Cutter
- v1.0.17-b2 [A] Initial port.
----

View file

@ -0,0 +1,18 @@
/*
* BluSunrize
* Copyright (c) 2017
*
* This code is licensed under "Blu's License of Common Sense"
* Details can be found in the license file in the root folder of this project
*/
package blusunrize.immersiveengineering.api.fluid;
import net.minecraft.util.Direction;
public interface IFluidPipe
{
boolean canOutputPressurized(boolean consumePower);
boolean hasOutputConnection(Direction side);
}

View file

@ -0,0 +1,903 @@
/*
* @file ModContent.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2018 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Definition and initialisation of blocks of this
* module, along with their tile entities if applicable.
*
* Note: Straight forward definition of different blocks/entities
* to make recipes, models and texture definitions easier.
*/
package wile.engineersdecor;
import wile.engineersdecor.blocks.*;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.block.material.MaterialColor;
import net.minecraft.block.Block;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.item.Item;
import net.minecraft.item.BlockItem;
import net.minecraft.entity.EntityClassification;
import net.minecraft.entity.EntityType;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.util.ResourceLocation;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.client.gui.ScreenManager;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.client.registry.RenderingRegistry;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import org.apache.commons.lang3.ArrayUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import javax.annotation.Nonnull;
@SuppressWarnings("unused")
public class ModContent
{
//--------------------------------------------------------------------------------------------------------------------
// Blocks
//--------------------------------------------------------------------------------------------------------------------
public static final BlockDecor CLINKER_BRICK_BLOCK = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_block"));
public static final BlockDecorSlab CLINKER_BRICK_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_slab"));
public static final BlockDecorStairs CLINKER_BRICK_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
CLINKER_BRICK_BLOCK.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_stairs"));
public static final BlockDecorWall CLINKER_BRICK_WALL = (BlockDecorWall)(new BlockDecorWall(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_wall"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor CLINKER_BRICK_STAINED_BLOCK = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_stained_block"));
public static final BlockDecorSlab CLINKER_BRICK_STAINED_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_stained_slab"));
public static final BlockDecorStairs CLINKER_BRICK_STAINED_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
CLINKER_BRICK_BLOCK.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "clinker_brick_stained_stairs"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor SLAG_BRICK_BLOCK = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "slag_brick_block"));
public static final BlockDecorSlab SLAG_BRICK_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "slag_brick_slab"));
public static final BlockDecorStairs SLAG_BRICK_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
SLAG_BRICK_BLOCK.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "slag_brick_stairs"));
public static final BlockDecorWall SLAG_BRICK_WALL = (BlockDecorWall)(new BlockDecorWall(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(3f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "slag_brick_wall"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor REBAR_CONCRETE_BLOCK = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete"));
public static final BlockDecorSlab REBAR_CONCRETE_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_slab"));
public static final BlockDecorStairs REBAR_CONCRETE_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
REBAR_CONCRETE_BLOCK.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_stairs"));
public static final BlockDecorWall REBAR_CONCRETE_WALL = (BlockDecorWall)(new BlockDecorWall(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_wall"));
public static final BlockDecorHalfSlab HALFSLAB_REBARCONCRETE = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_rebar_concrete"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor GAS_CONCRETE_BLOCK = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1.5f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "gas_concrete"));
public static final BlockDecorSlab GAS_CONCRETE_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1.5f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "gas_concrete_slab"));
public static final BlockDecorStairs GAS_CONCRETE_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
REBAR_CONCRETE_BLOCK.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1.5f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "gas_concrete_stairs"));
public static final BlockDecorWall GAS_CONCRETE_WALL = (BlockDecorWall)(new BlockDecorWall(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1.5f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "gas_concrete_wall"));
public static final BlockDecorHalfSlab HALFSLAB_GASCONCRETE = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1.5f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_gas_concrete"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor REBAR_CONCRETE_TILE = (BlockDecor)(new BlockDecor(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_tile"));
public static final BlockDecorSlab REBAR_CONCRETE_TILE_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_tile_slab"));
public static final BlockDecorStairs REBAR_CONCRETE_TILE_STAIRS = (BlockDecorStairs)(new BlockDecorStairs(
BlockDecor.CFG_DEFAULT,
REBAR_CONCRETE_TILE.getDefaultState(),
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(5f, 2000f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "rebar_concrete_tile_stairs"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorGlassBlock PANZERGLASS_BLOCK = (BlockDecorGlassBlock)(new BlockDecorGlassBlock(
BlockDecor.CFG_TRANSLUCENT,
Block.Properties.create(Material.GLASS, MaterialColor.AIR).hardnessAndResistance(5f, 2000f).sound(SoundType.METAL).func_226896_b_()
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "panzerglass_block"));
public static final BlockDecorSlab PANZERGLASS_SLAB = (BlockDecorSlab)(new BlockDecorSlab(
BlockDecor.CFG_TRANSLUCENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(5f, 2000f).sound(SoundType.METAL).func_226896_b_()
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "panzerglass_slab"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorLadder METAL_RUNG_LADDER = (BlockDecorLadder)(new BlockDecorLadder(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1.0f, 25f).sound(SoundType.METAL).func_226896_b_()
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "metal_rung_ladder"));
public static final BlockDecorLadder METAL_RUNG_STEPS = (BlockDecorLadder)(new BlockDecorLadder(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1.0f, 25f).sound(SoundType.METAL).func_226896_b_()
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "metal_rung_steps"));
public static final BlockDecorLadder TREATED_WOOD_LADDER = (BlockDecorLadder)(new BlockDecorLadder(
BlockDecor.CFG_DEFAULT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1.0f, 25f).sound(SoundType.WOOD).func_226896_b_()
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_ladder"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecor.WaterLoggable TREATED_WOOD_TABLE = (BlockDecor.WaterLoggable)(new BlockDecor.WaterLoggable(
BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(1,0,1, 15,15.9,15)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_table"));
public static final BlockDecorChair TREATED_WOOD_STOOL = (BlockDecorChair)(new BlockDecorChair(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(4.1,0,4.1, 11.8,8.8,11.8)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_stool"));
public static final BlockDecor.WaterLoggable TREATED_WOOD_SIDE_TABLE = (BlockDecor.WaterLoggable)(new BlockDecor.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(2,0,2, 14,15.9,14)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_side_table"));
public static final BlockDecorDirected.WaterLoggable TREATED_WOOD_WINDOWSILL = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_FACING_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(0.5,15,10.5, 15.5,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_windowsill"));
public static final BlockDecorDirected.WaterLoggable TREATED_WOOD_BROAD_WINDOWSILL = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_FACING_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(0,14.5,4, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_broad_windowsill"));
public static final BlockDecorDirected.WaterLoggable INSET_LIGHT_IRON = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_OPPOSITE_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).lightValue(15),
ModAuxiliaries.getPixeledAABB(5.2,5.2,15.7, 10.8,10.8,16.0)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "iron_inset_light"));
public static final BlockDecorDirected.WaterLoggable FLOOR_EDGE_LIGHT_IRON = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).lightValue(15),
ModAuxiliaries.getPixeledAABB(5,0,0, 11,2,1)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "iron_floor_edge_light"));
public static final BlockDecor.WaterLoggable STEEL_TABLE = (BlockDecor.WaterLoggable)(new BlockDecor.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "steel_table"));
public static final BlockDecor STEEL_FLOOR_GRATING = (BlockDecorFloorGrating)(new BlockDecorFloorGrating(
BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,14,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "steel_floor_grating"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorWindow TREATED_WOOD_WINDOW = (BlockDecorWindow)(new BlockDecorWindow(
BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.GLASS),
ModAuxiliaries.getPixeledAABB(0,0,7, 16,16,9)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_window"));
public static final BlockDecorWindow STEEL_FRAMED_WINDOW = (BlockDecorWindow)(new BlockDecorWindow(
BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.GLASS),
ModAuxiliaries.getPixeledAABB(0,0,7.5, 16,16,8.5)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "steel_framed_window"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorStraightPole TREATED_WOOD_POLE = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_IF_SAME,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_pole"));
public static final BlockDecorStraightPole TREATED_WOOD_POLE_HEAD = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_IF_SAME,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_pole_head"));
public static final BlockDecorStraightPole TREATED_WOOD_POLE_SUPPORT = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_IF_SAME,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_pole_support"));
public static final BlockDecorStraightPole THIN_STEEL_POLE = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(6,6,0, 10,10,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "thin_steel_pole"));
public static final BlockDecorStraightPole THIN_STEEL_POLE_HEAD = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_IF_SAME,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(6,6,0, 10,10,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "thin_steel_pole_head"));
public static final BlockDecorStraightPole THICK_STEEL_POLE = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(5,5,0, 11,11,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "thick_steel_pole"));
public static final BlockDecorStraightPole THICK_STEEL_POLE_HEAD = (BlockDecorStraightPole)(new BlockDecorStraightPole(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_IF_SAME,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(5,5,0, 11,11,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "thick_steel_pole_head"));
public static final BlockDecorHorizontalSupport STEEL_DOUBLE_T_SUPPORT = (BlockDecorHorizontalSupport)(new BlockDecorHorizontalSupport(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(5,11,0, 11,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "steel_double_t_support"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorDirected.WaterLoggable SIGN_MODLOGO = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1000f).sound(SoundType.WOOD).lightValue(1),
ModAuxiliaries.getPixeledAABB(0,0,15.6, 16,16,16.0)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_decor"));
public static final BlockDecorDirected.WaterLoggable SIGN_HOTWIRE = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(2,2,15.6, 14,14,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_hotwire"));
public static final BlockDecorDirected.WaterLoggable SIGN_DANGER = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(2,2,15.6, 14,14,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_danger"));
public static final BlockDecorDirected.WaterLoggable SIGN_DEFENSE = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(2,2,15.6, 14,14,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_defense"));
public static final BlockDecorDirected.WaterLoggable SIGN_FACTORY_AREA = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(2,2,15.6, 14,14,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_factoryarea"));
public static final BlockDecorDirected.WaterLoggable SIGN_EXIT = (BlockDecorDirected.WaterLoggable)(new BlockDecorDirected.WaterLoggable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_HORIZIONTAL,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 1f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(3,7,15.6, 13,13,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "sign_exit"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorCraftingTable TREATED_WOOD_CRAFTING_TABLE = (BlockDecorCraftingTable)(new BlockDecorCraftingTable(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 15f).sound(SoundType.WOOD),
ModAuxiliaries.getPixeledAABB(1,0,1, 15,15.9,15)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "treated_wood_crafting_table"));
public static final BlockDecorFurnace SMALL_LAB_FURNACE = (BlockDecorFurnace)(new BlockDecorFurnace(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(1,0,1, 15,15,16.0)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_lab_furnace"));
public static final BlockDecorFurnaceElectrical SMALL_ELECTRICAL_FURNACE = (BlockDecorFurnaceElectrical)(new BlockDecorFurnaceElectrical(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_ELECTRICAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_electrical_furnace"));
public static final BlockDecorDropper FACTORY_DROPPER = (BlockDecorDropper)(new BlockDecorDropper(
BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,15)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "factory_dropper"));
public static final BlockDecorPlacer FACTORY_PLACER = (BlockDecorPlacer)(new BlockDecorPlacer(
BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(2,2,2, 14,14,14)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "factory_placer"));
public static final BlockDecorBreaker SMALL_BLOCK_BREAKER = (BlockDecorBreaker)(new BlockDecorBreaker(
BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,12,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_block_breaker"));
public static final BlockDecorHopper FACTORY_HOPPER = (BlockDecorHopper)(new BlockDecorHopper(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "factory_hopper"));
public static final BlockDecorWasteIncinerator SMALL_WASTE_INCINERATOR = (BlockDecorWasteIncinerator)(new BlockDecorWasteIncinerator(
BlockDecor.CFG_DEFAULT|BlockDecor.CFG_ELECTRICAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_waste_incinerator"));
public static final BlockDecorMineralSmelter SMALL_MINERAL_SMELTER = (BlockDecorMineralSmelter)(new BlockDecorMineralSmelter(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_ELECTRICAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(1.1,0,1.1, 14.9,16,14.9)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_mineral_smelter"));
public static final BlockDecorSolarPanel SMALL_SOLAR_PANEL = (BlockDecorSolarPanel)(new BlockDecorSolarPanel(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_ELECTRICAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,11.5,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_solar_panel"));
public static final BlockDecorMilker SMALL_MILKING_MACHINE = (BlockDecorMilker)(new BlockDecorMilker(
BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_CUTOUT|BlockDecor.CFG_ELECTRICAL,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,13)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_milking_machine"));
public static final BlockDecorTreeCutter SMALL_TREE_CUTTER = (BlockDecorTreeCutter)(new BlockDecorTreeCutter(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HORIZIONTAL|BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,8,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_tree_cutter"));
public static final BlockDecorPipeValve STRAIGHT_CHECK_VALVE = (BlockDecorPipeValve)(new BlockDecorPipeValve(
BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(4,4,0, 12,12,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "straight_pipe_valve"));
public static final BlockDecorPipeValve STRAIGHT_REDSTONE_VALVE = (BlockDecorPipeValve)(new BlockDecorPipeValve(
BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_CUTOUT|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(4,4,0, 12,12,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "straight_pipe_valve_redstone"));
public static final BlockDecorPipeValve STRAIGHT_REDSTONE_ANALOG_VALVE = (BlockDecorPipeValve)(new BlockDecorPipeValve(
BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_CUTOUT|BlockDecor.CFG_REDSTONE_CONTROLLED|BlockDecor.CFG_ANALOG,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(4,4,0, 12,12,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "straight_pipe_valve_redstone_analog"));
public static final BlockDecorPassiveFluidAccumulator PASSIVE_FLUID_ACCUMULATOR = (BlockDecorPassiveFluidAccumulator)(new BlockDecorPassiveFluidAccumulator(
BlockDecor.CFG_FACING_PLACEMENT|BlockDecor.CFG_OPPOSITE_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "passive_fluid_accumulator"));
public static final BlockDecorFluidFunnel SMALL_FLUID_FUNNEL = (BlockDecorFluidFunnel)(new BlockDecorFluidFunnel(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL).func_226896_b_(),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "small_fluid_funnel"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorWall CONCRETE_WALL = (BlockDecorWall)(new BlockDecorWall(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(2f, 50f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "concrete_wall"));
public static final BlockDecorHalfSlab HALFSLAB_CONCRETE = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.ROCK, MaterialColor.STONE).hardnessAndResistance(1f, 10f).sound(SoundType.STONE)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_concrete"));
public static final BlockDecorHalfSlab HALFSLAB_TREATEDWOOD = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(1f, 4f).sound(SoundType.WOOD)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_treated_wood"));
public static final BlockDecorHalfSlab HALFSLAB_SHEETMETALIRON = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 10f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_sheetmetal_iron"));
public static final BlockDecorHalfSlab HALFSLAB_SHEETMETALSTEEL = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 10f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_sheetmetal_steel"));
public static final BlockDecorHalfSlab HALFSLAB_SHEETMETALCOPPER = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 10f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_sheetmetal_copper"));
public static final BlockDecorHalfSlab HALFSLAB_SHEETMETALGOLD = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 10f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_sheetmetal_gold"));
public static final BlockDecorHalfSlab HALFSLAB_SHEETMETALALUMINIUM = (BlockDecorHalfSlab)(new BlockDecorHalfSlab(
BlockDecor.CFG_CUTOUT|BlockDecor.CFG_HARD_IE_DEPENDENT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(1f, 10f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "halfslab_sheetmetal_aluminum"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorFence STEEL_MESH_FENCE = (BlockDecorFence)(new BlockDecorFence(
BlockDecor.CFG_CUTOUT,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(2f, 15f).sound(SoundType.METAL)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "steel_mesh_fence"));
// -------------------------------------------------------------------------------------------------------------------
public static final BlockDecorTest TEST_BLOCK = (BlockDecorTest)(new BlockDecorTest(
BlockDecor.CFG_LOOK_PLACEMENT|BlockDecor.CFG_FLIP_PLACEMENT_SHIFTCLICK|BlockDecor.CFG_ELECTRICAL|BlockDecor.CFG_REDSTONE_CONTROLLED,
Block.Properties.create(Material.IRON, MaterialColor.IRON).hardnessAndResistance(0f, 32000f).sound(SoundType.METAL),
ModAuxiliaries.getPixeledAABB(0,0,0, 16,16,16)
)).setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "test_block"));
// -------------------------------------------------------------------------------------------------------------------
private static final Block modBlocks[] = {
TREATED_WOOD_CRAFTING_TABLE,
SMALL_LAB_FURNACE,
SMALL_ELECTRICAL_FURNACE,
FACTORY_HOPPER,
FACTORY_DROPPER,
FACTORY_PLACER,
SMALL_BLOCK_BREAKER,
SMALL_TREE_CUTTER,
SMALL_SOLAR_PANEL,
SMALL_WASTE_INCINERATOR,
SMALL_MINERAL_SMELTER,
SMALL_MILKING_MACHINE,
STRAIGHT_CHECK_VALVE,
STRAIGHT_REDSTONE_VALVE,
STRAIGHT_REDSTONE_ANALOG_VALVE,
PASSIVE_FLUID_ACCUMULATOR,
SMALL_FLUID_FUNNEL,
CLINKER_BRICK_BLOCK,
CLINKER_BRICK_SLAB,
CLINKER_BRICK_STAIRS,
CLINKER_BRICK_WALL,
CLINKER_BRICK_STAINED_BLOCK,
CLINKER_BRICK_STAINED_SLAB,
CLINKER_BRICK_STAINED_STAIRS,
SLAG_BRICK_BLOCK,
SLAG_BRICK_SLAB,
SLAG_BRICK_STAIRS,
SLAG_BRICK_WALL,
REBAR_CONCRETE_BLOCK,
REBAR_CONCRETE_SLAB,
REBAR_CONCRETE_STAIRS,
REBAR_CONCRETE_WALL,
REBAR_CONCRETE_TILE,
REBAR_CONCRETE_TILE_SLAB,
REBAR_CONCRETE_TILE_STAIRS,
GAS_CONCRETE_BLOCK,
GAS_CONCRETE_SLAB,
GAS_CONCRETE_STAIRS,
GAS_CONCRETE_WALL,
HALFSLAB_REBARCONCRETE,
HALFSLAB_GASCONCRETE,
HALFSLAB_CONCRETE,
//HALFSLAB_TREATEDWOOD,
//HALFSLAB_SHEETMETALIRON
//HALFSLAB_SHEETMETALSTEEL,
//HALFSLAB_SHEETMETALCOPPER,
//HALFSLAB_SHEETMETALGOLD,
//HALFSLAB_SHEETMETALALUMINIUM,
CONCRETE_WALL,
PANZERGLASS_BLOCK,
PANZERGLASS_SLAB,
METAL_RUNG_LADDER,
METAL_RUNG_STEPS,
TREATED_WOOD_LADDER,
TREATED_WOOD_TABLE,
TREATED_WOOD_STOOL,
TREATED_WOOD_SIDE_TABLE,
TREATED_WOOD_WINDOWSILL,
TREATED_WOOD_BROAD_WINDOWSILL,
TREATED_WOOD_WINDOW,
STEEL_FRAMED_WINDOW,
STEEL_TABLE,
INSET_LIGHT_IRON,
FLOOR_EDGE_LIGHT_IRON,
STEEL_FLOOR_GRATING,
STEEL_MESH_FENCE,
TREATED_WOOD_POLE,
TREATED_WOOD_POLE_HEAD,
TREATED_WOOD_POLE_SUPPORT,
THIN_STEEL_POLE,
THIN_STEEL_POLE_HEAD,
THICK_STEEL_POLE,
THICK_STEEL_POLE_HEAD,
STEEL_DOUBLE_T_SUPPORT,
SIGN_HOTWIRE,
SIGN_DANGER,
SIGN_DEFENSE,
SIGN_FACTORY_AREA,
SIGN_EXIT,
SIGN_MODLOGO,
};
private static final Block devBlocks[] = {
//TEST_BLOCK
};
//--------------------------------------------------------------------------------------------------------------------
// Tile entities bound exclusively to the blocks above
//--------------------------------------------------------------------------------------------------------------------
public static final TileEntityType<?> TET_TREATED_WOOD_CRAFTING_TABLE = TileEntityType.Builder
.create(BlockDecorCraftingTable.BTileEntity::new, TREATED_WOOD_CRAFTING_TABLE)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_treated_wood_crafting_table");
public static final TileEntityType<?> TET_SMALL_LAB_FURNACE = TileEntityType.Builder
.create(BlockDecorFurnace.BTileEntity::new, SMALL_LAB_FURNACE)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_lab_furnace");
public static final TileEntityType<?> TET_SMALL_ELECTRICAL_FURNACE = TileEntityType.Builder
.create(BlockDecorFurnaceElectrical.BTileEntity::new, SMALL_ELECTRICAL_FURNACE)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_electrical_furnace");
public static final TileEntityType<?> TET_FACTORY_DROPPER = TileEntityType.Builder
.create(BlockDecorDropper.BTileEntity::new, FACTORY_DROPPER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_factory_dropper");
public static final TileEntityType<?> TET_FACTORY_PLACER = TileEntityType.Builder
.create(BlockDecorPlacer.BTileEntity::new, FACTORY_PLACER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_factory_placer");
public static final TileEntityType<?> TET_SMALL_BLOCK_BREAKER = TileEntityType.Builder
.create(BlockDecorBreaker.BTileEntity::new, SMALL_BLOCK_BREAKER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_block_breaker");
public static final TileEntityType<?> TET_FACTORY_HOPPER = TileEntityType.Builder
.create(BlockDecorHopper.BTileEntity::new, FACTORY_HOPPER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_factory_hopper");
public static final TileEntityType<?> TET_WASTE_INCINERATOR = TileEntityType.Builder
.create(BlockDecorWasteIncinerator.BTileEntity::new, SMALL_WASTE_INCINERATOR)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_waste_incinerator");
public static final TileEntityType<?> TET_STRAIGHT_PIPE_VALVE = TileEntityType.Builder
.create(BlockDecorPipeValve.BTileEntity::new, STRAIGHT_CHECK_VALVE, STRAIGHT_REDSTONE_VALVE, STRAIGHT_REDSTONE_ANALOG_VALVE)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_pipe_valve");
public static final TileEntityType<?> TET_PASSIVE_FLUID_ACCUMULATOR = TileEntityType.Builder
.create(BlockDecorPassiveFluidAccumulator.BTileEntity::new, PASSIVE_FLUID_ACCUMULATOR)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_passive_fluid_accumulator");
public static final TileEntityType<?> TET_SMALL_FLUID_FUNNEL = TileEntityType.Builder
.create(BlockDecorFluidFunnel.BTileEntity::new, SMALL_FLUID_FUNNEL)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_fluid_funnel");
public static final TileEntityType<?> TET_MINERAL_SMELTER = TileEntityType.Builder
.create(BlockDecorMineralSmelter.BTileEntity::new, SMALL_MINERAL_SMELTER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_mineral_smelter");
public static final TileEntityType<?> TET_SMALL_SOLAR_PANEL = TileEntityType.Builder
.create(BlockDecorSolarPanel.BTileEntity::new, SMALL_SOLAR_PANEL)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_solar_panel");
public static final TileEntityType<?> TET_SMALL_MILKING_MACHINE = TileEntityType.Builder
.create(BlockDecorMilker.BTileEntity::new, SMALL_MILKING_MACHINE)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_milking_machine");
public static final TileEntityType<?> TET_SMALL_TREE_CUTTER = TileEntityType.Builder
.create(BlockDecorTreeCutter.BTileEntity::new, SMALL_TREE_CUTTER)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_small_tree_cutter");
public static final TileEntityType<?> TET_TEST_BLOCK = TileEntityType.Builder
.create(BlockDecorPipeValve.BTileEntity::new, TEST_BLOCK)
.build(null)
.setRegistryName(ModEngineersDecor.MODID, "te_test_block");
private static final TileEntityType<?> tile_entity_types[] = {
TET_TREATED_WOOD_CRAFTING_TABLE,
TET_SMALL_LAB_FURNACE,
TET_SMALL_ELECTRICAL_FURNACE,
TET_FACTORY_HOPPER,
TET_FACTORY_DROPPER,
TET_FACTORY_PLACER,
TET_SMALL_BLOCK_BREAKER,
TET_SMALL_TREE_CUTTER,
TET_WASTE_INCINERATOR,
TET_MINERAL_SMELTER,
TET_SMALL_SOLAR_PANEL,
TET_SMALL_MILKING_MACHINE,
TET_STRAIGHT_PIPE_VALVE,
TET_PASSIVE_FLUID_ACCUMULATOR,
TET_SMALL_FLUID_FUNNEL,
TET_TEST_BLOCK
};
//--------------------------------------------------------------------------------------------------------------------
// Entities bound exclusively to the blocks above
//--------------------------------------------------------------------------------------------------------------------
@SuppressWarnings("unchecked")
public static final EntityType<BlockDecorChair.EntityChair> ET_CHAIR = (EntityType<BlockDecorChair.EntityChair>)(
EntityType.Builder
.create(BlockDecorChair.EntityChair::new, EntityClassification.MISC)
.immuneToFire().size(1e-3f, 1e-3f).disableSerialization()
.setShouldReceiveVelocityUpdates(false).setUpdateInterval(4)
.setCustomClientFactory(BlockDecorChair.EntityChair::customClientFactory)
.build(new ResourceLocation(ModEngineersDecor.MODID, "et_chair").toString())
.setRegistryName(new ResourceLocation(ModEngineersDecor.MODID, "et_chair"))
);
private static final EntityType<?> entity_types[] = {
ET_CHAIR
};
//--------------------------------------------------------------------------------------------------------------------
// Container registration
//--------------------------------------------------------------------------------------------------------------------
public static final ContainerType<BlockDecorCraftingTable.BContainer> CT_TREATED_WOOD_CRAFTING_TABLE;
public static final ContainerType<BlockDecorDropper.BContainer> CT_FACTORY_DROPPER;
public static final ContainerType<BlockDecorPlacer.BContainer> CT_FACTORY_PLACER;
public static final ContainerType<BlockDecorHopper.BContainer> CT_FACTORY_HOPPER;
public static final ContainerType<BlockDecorFurnace.BContainer> CT_SMALL_LAB_FURNACE;
public static final ContainerType<BlockDecorFurnaceElectrical.BContainer> CT_SMALL_ELECTRICAL_FURNACE;
public static final ContainerType<BlockDecorWasteIncinerator.BContainer> CT_WASTE_INCINERATOR;
static {
CT_TREATED_WOOD_CRAFTING_TABLE = (new ContainerType<BlockDecorCraftingTable.BContainer>(BlockDecorCraftingTable.BContainer::new));
CT_TREATED_WOOD_CRAFTING_TABLE.setRegistryName(ModEngineersDecor.MODID,"ct_treated_wood_crafting_table");
CT_FACTORY_DROPPER = (new ContainerType<BlockDecorDropper.BContainer>(BlockDecorDropper.BContainer::new));
CT_FACTORY_DROPPER.setRegistryName(ModEngineersDecor.MODID,"ct_factory_dropper");
CT_FACTORY_PLACER = (new ContainerType<BlockDecorPlacer.BContainer>(BlockDecorPlacer.BContainer::new));
CT_FACTORY_PLACER.setRegistryName(ModEngineersDecor.MODID,"ct_factory_placer");
CT_FACTORY_HOPPER = (new ContainerType<BlockDecorHopper.BContainer>(BlockDecorHopper.BContainer::new));
CT_FACTORY_HOPPER.setRegistryName(ModEngineersDecor.MODID,"ct_factory_hopper");
CT_SMALL_LAB_FURNACE = (new ContainerType<BlockDecorFurnace.BContainer>(BlockDecorFurnace.BContainer::new));
CT_SMALL_LAB_FURNACE.setRegistryName(ModEngineersDecor.MODID,"ct_small_lab_furnace");
CT_SMALL_ELECTRICAL_FURNACE = (new ContainerType<BlockDecorFurnaceElectrical.BContainer>(BlockDecorFurnaceElectrical.BContainer::new));
CT_SMALL_ELECTRICAL_FURNACE.setRegistryName(ModEngineersDecor.MODID,"ct_small_electrical_furnace");
CT_WASTE_INCINERATOR = (new ContainerType<BlockDecorWasteIncinerator.BContainer>(BlockDecorWasteIncinerator.BContainer::new));
CT_WASTE_INCINERATOR.setRegistryName(ModEngineersDecor.MODID,"ct_small_waste_incinerator");
}
// DON'T FORGET TO REGISTER THE GUI in registerContainerGuis(), no list/map format found yet for that.
private static final ContainerType<?> container_types[] = {
CT_TREATED_WOOD_CRAFTING_TABLE,
CT_FACTORY_DROPPER,
CT_FACTORY_PLACER,
CT_FACTORY_HOPPER,
CT_SMALL_LAB_FURNACE,
CT_SMALL_ELECTRICAL_FURNACE,
CT_WASTE_INCINERATOR
};
//--------------------------------------------------------------------------------------------------------------------
// Initialisation events
//--------------------------------------------------------------------------------------------------------------------
private static ArrayList<Block> registeredBlocks = new ArrayList<>();
public static ArrayList<Block> allBlocks()
{
ArrayList<Block> blocks = new ArrayList<>();
Collections.addAll(blocks, modBlocks);
Collections.addAll(blocks, devBlocks);
return blocks;
}
public static boolean isExperimentalBlock(Block block)
{ return ArrayUtils.contains(devBlocks, block); }
@Nonnull
public static List<Block> getRegisteredBlocks()
{ return Collections.unmodifiableList(registeredBlocks); }
public static final void registerBlocks(final RegistryEvent.Register<Block> event)
{
if(ModAuxiliaries.isModLoaded("immersiveengineering")) ModAuxiliaries.logInfo("Immersive Engineering also installed ...");
registeredBlocks.addAll(allBlocks());
for(Block e:registeredBlocks) event.getRegistry().register(e);
ModAuxiliaries.logInfo("Registered " + Integer.toString(registeredBlocks.size()) + " blocks.");
}
public static final void registerBlockItems(final RegistryEvent.Register<Item> event)
{
int n = 0;
for(Block e:registeredBlocks) {
ResourceLocation rl = e.getRegistryName();
if(rl == null) continue;
event.getRegistry().register(new BlockItem(e, (new BlockItem.Properties().group(ModEngineersDecor.ITEMGROUP))).setRegistryName(rl));
++n;
}
}
public static final void registerTileEntities(final RegistryEvent.Register<TileEntityType<?>> event)
{
int n_registered = 0;
for(final TileEntityType<?> e:tile_entity_types) {
event.getRegistry().register(e);
++n_registered;
}
ModAuxiliaries.logInfo("Registered " + Integer.toString(n_registered) + " tile entities.");
}
public static final void registerEntities(final RegistryEvent.Register<EntityType<?>> event)
{
int n_registered = 0;
for(final EntityType<?> e:entity_types) {
if((e==ET_CHAIR) && (!registeredBlocks.contains(TREATED_WOOD_STOOL))) continue;
event.getRegistry().register(e);
++n_registered;
}
ModAuxiliaries.logInfo("Registered " + Integer.toString(n_registered) + " entities bound to blocks.");
}
public static final void registerContainers(final RegistryEvent.Register<ContainerType<?>> event)
{
int n_registered = 0;
for(final ContainerType<?> e:container_types) {
event.getRegistry().register(e);
++n_registered;
}
ModAuxiliaries.logInfo("Registered " + Integer.toString(n_registered) + " containers bound to tile entities.");
}
@OnlyIn(Dist.CLIENT)
public static final void registerContainerGuis(final FMLClientSetupEvent event)
{
ScreenManager.registerFactory(CT_TREATED_WOOD_CRAFTING_TABLE, BlockDecorCraftingTable.BGui::new);
ScreenManager.registerFactory(CT_FACTORY_DROPPER, BlockDecorDropper.BGui::new);
ScreenManager.registerFactory(CT_FACTORY_PLACER, BlockDecorPlacer.BGui::new);
ScreenManager.registerFactory(CT_FACTORY_HOPPER, BlockDecorHopper.BGui::new);
ScreenManager.registerFactory(CT_SMALL_LAB_FURNACE, BlockDecorFurnace.BGui::new);
ScreenManager.registerFactory(CT_SMALL_ELECTRICAL_FURNACE, BlockDecorFurnaceElectrical.BGui::new);
ScreenManager.registerFactory(CT_WASTE_INCINERATOR, BlockDecorWasteIncinerator.BGui::new);
}
@OnlyIn(Dist.CLIENT)
public static final void registerTileEntityRenderers(final FMLClientSetupEvent event)
{
// @todo: re-enable
//ClientRegistry.bindTileEntityRenderer(TET_TREATED_WOOD_CRAFTING_TABLE, new wile.engineersdecor.detail.ModRenderers.TesrDecorCraftingTable());
}
@OnlyIn(Dist.CLIENT)
public static final void processContentClientSide(final FMLClientSetupEvent event)
{
// Block renderer selection
for(Block block: getRegisteredBlocks()) {
if(block instanceof IDecorBlock) {
switch(((IDecorBlock)block).getRenderTypeHint()) {
case CUTOUT:
RenderTypeLookup.setRenderLayer(block, RenderType.func_228643_e_()/*cutout*/);
break;
case CUTOUT_MIPPED:
RenderTypeLookup.setRenderLayer(block, RenderType.func_228641_d_()/*cutout_mipped*/);
break;
case TRANSLUCENT:
RenderTypeLookup.setRenderLayer(block, RenderType.func_228645_f_()/*transparent*/);
break;
case SOLID:
break;
}
}
}
// Entity renderers
RenderingRegistry.registerEntityRenderingHandler(ET_CHAIR,
manager->(new wile.engineersdecor.detail.ModRenderers.InvisibleEntityRenderer<BlockDecorChair.EntityChair>(manager))
);
}
}

View file

@ -0,0 +1,185 @@
package wile.engineersdecor;
import wile.engineersdecor.detail.ModConfig;
import wile.engineersdecor.detail.Networking;
import wile.engineersdecor.blocks.*;
import wile.engineersdecor.detail.OptionalRecipeCondition.Serializer;
import wile.engineersdecor.datagen.ModLootTables;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.item.ItemGroup;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.world.World;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraftforge.common.crafting.CraftingHelper;
import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.*;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
@Mod("engineersdecor")
public class ModEngineersDecor
{
public static final String MODID = "engineersdecor";
public static final int VERSION_DATAFIXER = 0;
private static final Logger LOGGER = LogManager.getLogger();
private static boolean config_loaded = false;
public ModEngineersDecor()
{
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onSetup);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onSendImc);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onRecvImc);
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientSetup);
ModLoadingContext.get().registerConfig(net.minecraftforge.fml.config.ModConfig.Type.COMMON, ModConfig.COMMON_CONFIG_SPEC);
ModLoadingContext.get().registerConfig(net.minecraftforge.fml.config.ModConfig.Type.CLIENT, ModConfig.CLIENT_CONFIG_SPEC);
MinecraftForge.EVENT_BUS.register(this);
}
public static final Logger logger() { return LOGGER; }
//
// Events
//
private void onSetup(final FMLCommonSetupEvent event)
{
LOGGER.info("Registering recipe condition processor ...");
CraftingHelper.register(Serializer.INSTANCE);
Networking.init();
if(config_loaded) {
try {
logger().info("Applying loaded config file.");
ModConfig.apply();
} catch(Throwable e) {
logger().error("Failed to apply config: " + e.getMessage());
}
} else {
logger().info("Cannot apply config, load event was not casted yet.");
}
}
private void onClientSetup(final FMLClientSetupEvent event)
{
ModContent.registerContainerGuis(event);
ModContent.registerTileEntityRenderers(event);
ModContent.processContentClientSide(event);
}
private void onSendImc(final InterModEnqueueEvent event)
{}
private void onRecvImc(final InterModProcessEvent event)
{}
@Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD)
public static class ForgeEvents
{
@SubscribeEvent
public static void onBlocksRegistry(final RegistryEvent.Register<Block> event)
{ ModContent.registerBlocks(event); }
@SubscribeEvent
public static void onItemRegistry(final RegistryEvent.Register<Item> event)
{ ModContent.registerBlockItems(event); }
@SubscribeEvent
public static void onTileEntityRegistry(final RegistryEvent.Register<TileEntityType<?>> event)
{ ModContent.registerTileEntities(event); }
@SubscribeEvent
public static void onRegisterEntityTypes(final RegistryEvent.Register<EntityType<?>> event)
{ ModContent.registerEntities(event); }
@SubscribeEvent
public static void onRegisterContainerTypes(final RegistryEvent.Register<ContainerType<?>> event)
{ ModContent.registerContainers(event); }
// @SubscribeEvent
public static void onServerStarting(FMLServerStartingEvent event)
{}
@SubscribeEvent
public static void onConfigLoad(net.minecraftforge.fml.config.ModConfig.Loading configEvent)
{ config_loaded = true; }
@SubscribeEvent
public static void onConfigFileChange(net.minecraftforge.fml.config.ModConfig.ConfigReloading configEvent)
{
try {
ModEngineersDecor.logger().info("Config file changed {}", configEvent.getConfig().getFileName());
ModConfig.apply();
} catch(Throwable e) {
ModEngineersDecor.logger().error("Failed to load changed config: " + e.getMessage());
}
}
@SubscribeEvent
public static void onDataGeneration(GatherDataEvent event)
{
event.getGenerator().addProvider(new ModLootTables(event.getGenerator()));
}
}
//
// Sided proxy functionality (skel)
//
public static ISidedProxy proxy = DistExecutor.runForDist(()->ClientProxy::new, ()->ServerProxy::new);
public interface ISidedProxy
{
default @Nullable PlayerEntity getPlayerClientSide() { return null; }
default @Nullable World getWorldClientSide() { return null; }
default @Nullable Minecraft mc() { return null; }
}
public static final class ClientProxy implements ISidedProxy
{
public @Nullable PlayerEntity getPlayerClientSide() { return Minecraft.getInstance().player; }
public @Nullable World getWorldClientSide() { return Minecraft.getInstance().world; }
public @Nullable Minecraft mc() { return Minecraft.getInstance(); }
}
public static final class ServerProxy implements ISidedProxy
{
public @Nullable PlayerEntity getPlayerClientSide() { return null; }
public @Nullable World getWorldClientSide() { return null; }
public @Nullable Minecraft mc() { return null; }
}
//
// Item group / creative tab
//
public static final ItemGroup ITEMGROUP = (new ItemGroup("tab" + MODID) {
@OnlyIn(Dist.CLIENT)
public ItemStack createIcon()
{ return new ItemStack(ModContent.SIGN_MODLOGO); }
});
//
// Player update event
//
@SubscribeEvent
public void onPlayerEvent(final LivingEvent.LivingUpdateEvent event)
{
if(!(event.getEntity() instanceof PlayerEntity)) return;
final PlayerEntity player = (PlayerEntity)event.getEntity();
if(player.world == null) return;
if(player.isOnLadder()) BlockDecorLadder.onPlayerUpdateEvent(player);
}
}

View file

@ -0,0 +1,233 @@
/*
* @file BlockDecorFull.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Common functionality class for decor blocks.
* Mainly needed for:
* - MC block defaults.
* - Tooltip functionality
* - Model initialisation
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.state.StateContainer;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.world.server.ServerWorld;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.IFluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.world.IWorld;
import net.minecraft.world.Explosion;
import net.minecraft.world.World;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.block.Block;
import net.minecraft.block.material.PushReaction;
import net.minecraft.block.BlockState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.util.*;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import wile.engineersdecor.detail.ModConfig;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class BlockDecor extends Block implements IDecorBlock
{
public static final long CFG_DEFAULT = 0x0000000000000000L; // no special config
public static final long CFG_CUTOUT = 0x0000000000000001L; // cutout rendering
public static final long CFG_HORIZIONTAL = 0x0000000000000002L; // horizontal block, affects bounding box calculation at construction time and placement
public static final long CFG_LOOK_PLACEMENT = 0x0000000000000004L; // placed in direction the player is looking when placing.
public static final long CFG_FACING_PLACEMENT = 0x0000000000000008L; // placed on the facing the player has clicked.
public static final long CFG_OPPOSITE_PLACEMENT = 0x0000000000000010L; // placed placed in the opposite direction of the face the player clicked.
public static final long CFG_FLIP_PLACEMENT_IF_SAME = 0x0000000000000020L; // placement direction flipped if an instance of the same class was clicked
public static final long CFG_FLIP_PLACEMENT_SHIFTCLICK = 0x0000000000000040L; // placement direction flipped if player is sneaking
public static final long CFG_TRANSLUCENT = 0x0000000000000080L; // indicates a block/pane is glass like (transparent, etc)
public static final long CFG_ELECTRICAL = 0x0000000000010000L; // Denotes if a component is mainly flux driven.
public static final long CFG_REDSTONE_CONTROLLED = 0x0000000000020000L; // Denotes if a component has somehow a redstone control input
public static final long CFG_ANALOG = 0x0000000000040000L; // Denotes if a component has analog behaviour
public static final long CFG_HARD_IE_DEPENDENT = 0x8000000000000000L; // The block is implicitly opt'ed out if IE is not installed
public static final long CFG_WATERLOGGABLE = 0x4000000000000000L; // The derived block extends IWaterLoggable
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
public final long config;
public final VoxelShape vshape;
public BlockDecor(long conf, Block.Properties properties)
{ this(conf, properties, ModAuxiliaries.getPixeledAABB(0, 0, 0, 16, 16,16 )); }
public BlockDecor(long conf, Block.Properties properties, AxisAlignedBB aabb)
{ super(properties); config = conf; vshape = VoxelShapes.create(aabb); }
public BlockDecor(long conf, Block.Properties properties, VoxelShape voxel_shape)
{ super(properties); config = conf; vshape = voxel_shape; }
///////////// --------------------------------------------------------------------------------------------------------
// 1.15 transition
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit)
{ return false; }
@Deprecated
public ActionResultType func_225533_a_(BlockState p_225533_1_, World p_225533_2_, BlockPos p_225533_3_, PlayerEntity p_225533_4_, Hand p_225533_5_, BlockRayTraceResult p_225533_6_)
{
return onBlockActivated(p_225533_1_,p_225533_2_,p_225533_3_,p_225533_4_,p_225533_5_,p_225533_6_) ? ActionResultType.SUCCESS : ActionResultType.PASS;
}
@Deprecated
public void func_225534_a_(BlockState p_225534_1_, ServerWorld p_225534_2_, BlockPos p_225534_3_, Random p_225534_4_)
{ tick(p_225534_1_,p_225534_2_,p_225534_3_,p_225534_4_); }
public void tick(BlockState state, World world, BlockPos pos, Random rnd)
{}
// 1.15 /transition
///////////// --------------------------------------------------------------------------------------------------------
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{ ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return ((config & CFG_CUTOUT)!=0) ? RenderTypeHint.CUTOUT : RenderTypeHint.SOLID; }
@Override
@SuppressWarnings("deprecation")
public VoxelShape getShape(BlockState state, IBlockReader source, BlockPos pos, ISelectionContext selectionContext)
{ return vshape; }
@Override
@SuppressWarnings("deprecation")
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return vshape; }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
BlockState state = super.getStateForPlacement(context);
if((config & CFG_WATERLOGGABLE)!=0) {
IFluidState fs = context.getWorld().getFluidState(context.getPos());
state = state.with(WATERLOGGED,fs.getFluid()==Fluids.WATER);
}
return state;
}
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public PushReaction getPushReaction(BlockState state)
{ return PushReaction.NORMAL; }
@Override
@SuppressWarnings("deprecation")
public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving)
{
if(state.hasTileEntity() && (state.getBlock() != newState.getBlock())) {
world.removeTileEntity(pos);
world.updateComparatorOutputLevel(pos, this);
}
}
public static boolean dropBlock(BlockState state, World world, BlockPos pos, @Nullable PlayerEntity player)
{
if(!(state.getBlock() instanceof IDecorBlock)) { world.removeBlock(pos, false); return true; }
if(!world.isRemote()) {
if((ModConfig.with_creative_mode_device_drops) || (player==null) || (!player.isCreative())) {
((IDecorBlock)state.getBlock()).dropList(state, world, pos, player==null).forEach(stack->world.addEntity(new ItemEntity(world, pos.getX()+0.5, pos.getY()+0.5, pos.getZ()+0.5, stack)));
}
}
if(state.getBlock().hasTileEntity(state)) world.removeTileEntity(pos);
world.removeBlock(pos, false);
return true;
}
@Override
public boolean removedByPlayer(BlockState state, World world, BlockPos pos, PlayerEntity player, boolean willHarvest, IFluidState fluid)
{ return hasDynamicDropList() ? dropBlock(state, world, pos, player) : super.removedByPlayer(state, world,pos , player, willHarvest, fluid); }
@Override
public void onExplosionDestroy(World world, BlockPos pos, Explosion explosion)
{ if(hasDynamicDropList()) dropBlock(world.getBlockState(pos), world, pos, null); }
@Override
@SuppressWarnings("deprecation")
public List<ItemStack> getDrops(BlockState state, LootContext.Builder builder)
{ return hasDynamicDropList() ? Collections.singletonList(ItemStack.EMPTY) : super.getDrops(state, builder); }
@Override
@SuppressWarnings("deprecation")
public int getOpacity(BlockState state, IBlockReader world, BlockPos pos)
{ return ((config & (CFG_CUTOUT|CFG_TRANSLUCENT))==0) ? super.getOpacity(state, world, pos) : (state.propagatesSkylightDown(world, pos)?0:1); }
@Override
public boolean propagatesSkylightDown(BlockState state, IBlockReader reader, BlockPos pos)
{
if(((config & CFG_WATERLOGGABLE)!=0) && state.get(WATERLOGGED)) return false;
return super.propagatesSkylightDown(state, reader, pos);
}
@Override
@SuppressWarnings("deprecation")
public IFluidState getFluidState(BlockState state)
{
if((config & CFG_WATERLOGGABLE)!=0) {
return state.get(WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : super.getFluidState(state);
}
return super.getFluidState(state);
}
@Override
@SuppressWarnings("deprecation")
public BlockState updatePostPlacement(BlockState state, Direction facing, BlockState facingState, IWorld world, BlockPos pos, BlockPos facingPos)
{
if((config & CFG_WATERLOGGABLE)!=0) {
if(state.get(WATERLOGGED)) world.getPendingFluidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
}
return state;
}
/**
* Water loggable version of the basic block.
*/
public static class WaterLoggable extends BlockDecor implements IWaterLoggable
{
public WaterLoggable(long config, Block.Properties properties)
{ super(config|CFG_WATERLOGGABLE, properties); }
public WaterLoggable(long config, Block.Properties properties, AxisAlignedBB aabb)
{ super(config|CFG_WATERLOGGABLE, properties, aabb); }
public WaterLoggable(long config, Block.Properties properties, VoxelShape voxel_shape)
{ super(config|CFG_WATERLOGGABLE, properties, voxel_shape); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(WATERLOGGED); }
}
}

View file

@ -0,0 +1,295 @@
/*
* @file BlockDecorBreaker.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Small Block Breaker
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.block.Blocks;
import net.minecraft.block.SoundType;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import javax.annotation.Nullable;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
public class BlockDecorBreaker extends BlockDecorDirectedHorizontal
{
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public BlockDecorBreaker(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(ACTIVE); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(ACTIVE, false); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BTileEntity(); }
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)
{
if((state.getBlock()!=this) || (!state.get(ACTIVE))) return;
final double rv = rnd.nextDouble();
if(rv > 0.8) return;
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xc=0.52, xr=rnd.nextDouble()*0.4-0.2, yr=(y-0.3+rnd.nextDouble()*0.2);
switch(state.get(HORIZONTAL_FACING)) {
case WEST: world.addParticle(ParticleTypes.SMOKE, x-xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case EAST: world.addParticle(ParticleTypes.SMOKE, x+xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case NORTH: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z-xc, 0.0, 0.0, 0.0); break;
default: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z+xc, 0.0, 0.0, 0.0); break;
}
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{
if(!(world instanceof World) || (((World) world).isRemote)) return;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).block_updated();
}
@Override
@SuppressWarnings("deprecation")
public boolean canProvidePower(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getWeakPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
@Override
@SuppressWarnings("deprecation")
public int getStrongPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, IEnergyStorage
{
public static final int IDLE_TICK_INTERVAL = 40;
public static final int TICK_INTERVAL = 5;
public static final int BOOST_FACTOR = 8;
public static final int DEFAULT_BOOST_ENERGY = 64;
public static final int DEFAULT_BREAKING_RELUCTANCE = 17;
public static final int DEFAULT_MIN_BREAKING_TIME = 15;
public static final int MAX_BREAKING_TIME = 800;
private static int boost_energy_consumption = DEFAULT_BOOST_ENERGY;
private static int breaking_reluctance = DEFAULT_BREAKING_RELUCTANCE;
private static int min_breaking_time = DEFAULT_MIN_BREAKING_TIME;
private static boolean requires_power = false;
private int tick_timer_;
private int active_timer_;
private int proc_time_elapsed_;
private int boost_energy_;
public static void on_config(int boost_energy_per_tick, int breaking_time_per_hardness, int min_breaking_time_ticks, boolean power_required)
{
boost_energy_consumption = TICK_INTERVAL * MathHelper.clamp(boost_energy_per_tick, 16, 512);
breaking_reluctance = MathHelper.clamp(breaking_time_per_hardness, 5, 50);
min_breaking_time = MathHelper.clamp(min_breaking_time_ticks, 10, 100);
requires_power = power_required;
ModEngineersDecor.logger().info("Config block breaker: Boost energy consumption:" + (boost_energy_consumption/TICK_INTERVAL) + "rf/t, reluctance=" + breaking_reluctance + "t/hrdn, break time offset=" + min_breaking_time + "t");
}
public BTileEntity()
{ super(ModContent.TET_SMALL_BLOCK_BREAKER); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
public void block_updated()
{ if(tick_timer_ > 2) tick_timer_ = 2; }
// IEnergyStorage ----------------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public boolean canExtract()
{ return false; }
@Override
public boolean canReceive()
{ return true; }
@Override
public int getMaxEnergyStored()
{ return boost_energy_consumption; }
@Override
public int getEnergyStored()
{ return boost_energy_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{ // only speedup support, no buffering, not in nbt -> no markdirty
if((boost_energy_ >= boost_energy_consumption) || (maxReceive < boost_energy_consumption)) return 0;
if(!simulate) boost_energy_ = boost_energy_consumption;
return boost_energy_consumption;
}
// Capability export ----------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability== CapabilityEnergy.ENERGY) {
return energy_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// ITickable ------------------------------------------------------------------------------------
private static HashSet<Block> blacklist = new HashSet<>();
static {
blacklist.add(Blocks.AIR);
blacklist.add(Blocks.BEDROCK);
blacklist.add(Blocks.FIRE);
blacklist.add(Blocks.END_PORTAL);
blacklist.add(Blocks.END_GATEWAY);
blacklist.add(Blocks.END_PORTAL_FRAME);
blacklist.add(Blocks.NETHER_PORTAL);
blacklist.add(Blocks.BARRIER);
}
private static boolean isBreakable(BlockState state, BlockPos pos, World world)
{
final Block block = state.getBlock();
if(blacklist.contains(block)) return false;
if(state.getMaterial().isLiquid()) return false;
if(block.isAir(state, world, pos)) return false;
float bh = state.getBlockHardness(world, pos);
if((bh<0) || (bh>55)) return false;
return true;
}
private boolean breakBlock(BlockState state, BlockPos pos, World world)
{
if(world.isRemote || (!(world instanceof ServerWorld)) || world.restoringBlockSnapshots) return false; // retry next cycle
List<ItemStack> drops = Block.getDrops(state, (ServerWorld)world, pos, world.getTileEntity(pos));
world.removeBlock(pos, false);
for(ItemStack drop:drops) spawnAsEntity(world, pos, drop);
SoundType stype = state.getBlock().getSoundType(state, world, pos, null);
if(stype != null) world.playSound(null, pos, stype.getPlaceSound(), SoundCategory.BLOCKS, stype.getVolume()*0.6f, stype.getPitch());
return true;
}
@Override
@SuppressWarnings("deprecation")
public void tick()
{
if(--tick_timer_ > 0) return;
if(world.isRemote) {
BlockState state = world.getBlockState(pos);
if(!state.get(ACTIVE)) {
tick_timer_ = TICK_INTERVAL;
} else {
tick_timer_ = 1;
// not sure if is so cool to do this each tick ... may be simplified/removed again.
SoundEvent sound = SoundEvents.BLOCK_WOOD_HIT;
BlockState target_state = world.getBlockState(pos.offset(state.get(HORIZONTAL_FACING)));
SoundType stype = target_state.getBlock().getSoundType(target_state);
if((stype == SoundType.CLOTH) || (stype == SoundType.PLANT) || (stype == SoundType.SNOW)) {
sound = SoundEvents.BLOCK_WOOL_HIT;
} else if((stype == SoundType.GROUND) || (stype == SoundType.SAND)) {
sound = SoundEvents.BLOCK_GRAVEL_HIT;
}
world.playSound(pos.getX(), pos.getY(), pos.getZ(), sound, SoundCategory.BLOCKS, 0.1f, 1.2f, false);
}
} else {
tick_timer_ = TICK_INTERVAL;
final BlockState device_state = world.getBlockState(pos);
final BlockPos target_pos = pos.offset(device_state.get(HORIZONTAL_FACING));
final BlockState target_state = world.getBlockState(target_pos);
if((world.isBlockPowered(pos)) || (!isBreakable(target_state, target_pos, world))) {
if(device_state.get(ACTIVE)) world.setBlockState(pos, device_state.with(ACTIVE, false), 1|2);
proc_time_elapsed_ = 0;
tick_timer_ = IDLE_TICK_INTERVAL;
return;
}
int time_needed = (int)(target_state.getBlockHardness(world, pos) * breaking_reluctance) + min_breaking_time;
if(boost_energy_ >= boost_energy_consumption) {
boost_energy_ = 0;
proc_time_elapsed_ += TICK_INTERVAL * (1+BOOST_FACTOR);
time_needed += min_breaking_time * (3*BOOST_FACTOR/5);
active_timer_ = 2;
} else if(!requires_power) {
proc_time_elapsed_ += TICK_INTERVAL;
active_timer_ = 1024;
} else if(active_timer_ > 0) {
--active_timer_;
}
boolean active = (active_timer_ > 0);
if(boost_energy_ >= boost_energy_consumption) {
boost_energy_ = 0;
proc_time_elapsed_ += TICK_INTERVAL * BOOST_FACTOR;
time_needed += min_breaking_time * (3*BOOST_FACTOR/5);
}
time_needed = MathHelper.clamp(time_needed, min_breaking_time, MAX_BREAKING_TIME);
if(proc_time_elapsed_ >= time_needed) {
proc_time_elapsed_ = 0;
breakBlock(target_state, target_pos, world);
active = false;
}
if(device_state.get(ACTIVE) != active) {
world.setBlockState(pos, device_state.with(ACTIVE, active), 1|2);
}
}
}
}
}

View file

@ -0,0 +1,187 @@
/*
* @file BlockDecorFull.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Full block characteristics class.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.entity.*;
import net.minecraft.entity.monster.*;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.IPacket;
import net.minecraft.util.math.*;
import net.minecraft.world.IWorldReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.*;
import net.minecraft.world.World;
import net.minecraftforge.fml.network.FMLPlayMessages;
import net.minecraftforge.fml.network.NetworkHooks;
import java.util.List;
import java.util.Random;
public class BlockDecorChair extends BlockDecorDirected.WaterLoggable
{
private static boolean sitting_enabled = true;
private static double sitting_probability = 0.1;
private static double standup_probability = 0.01;
public static void on_config(boolean without_sitting, boolean without_mob_sitting, double sitting_probability_percent, double standup_probability_percent)
{
sitting_enabled = (!without_sitting);
sitting_probability = (without_sitting||without_mob_sitting) ? 0.0 : MathHelper.clamp(sitting_probability_percent/100, 0, 0.9);
standup_probability = (without_sitting||without_mob_sitting) ? 1.0 : MathHelper.clamp(standup_probability_percent/100, 1e-6, 1e-2);
ModEngineersDecor.logger().info("Config chairs: " + sitting_enabled + ", sit: " + sitting_probability, ", stand up: " + standup_probability);
}
public BlockDecorChair(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder.tickRandomly(), unrotatedAABB); }
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(sitting_enabled && (!world.isRemote)) { EntityChair.sit(world, player, pos); }
return true;
}
@Override
@SuppressWarnings("deprecation")
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity)
{
if(sitting_enabled && (Math.random() < sitting_probability) && (entity instanceof MobEntity)) EntityChair.sit(world, (LivingEntity)entity, pos);
}
@Override
public int tickRate(IWorldReader world)
{ return 10; }
@Override
@SuppressWarnings("deprecation")
public void tick(BlockState state, World world, BlockPos pos, Random rnd)
{
if((!sitting_enabled) || (sitting_probability < 1e-6)) return;
final List<LivingEntity> entities = world.getEntitiesWithinAABB(MobEntity.class, new AxisAlignedBB(pos).grow(2,1,2).expand(0,1,0), e->true);
if(entities.isEmpty()) return;
int index = rnd.nextInt(entities.size());
if((index < 0) || (index >= entities.size())) return;
EntityChair.sit(world, entities.get(index), pos);
}
//--------------------------------------------------------------------------------------------------------------------
// Riding entity for sitting
//--------------------------------------------------------------------------------------------------------------------
public static class EntityChair extends Entity
{
public static final double x_offset = 0.5d;
public static final double y_offset = 0.4d;
public static final double z_offset = 0.5d;
private int t_sit = 0;
public BlockPos chair_pos = new BlockPos(0,0,0);
public EntityChair(EntityType<? extends Entity> entityType, World world)
{
super(entityType, world);
preventEntitySpawning=true;
setMotion(Vec3d.ZERO);
canUpdate(true);
noClip=true;
}
public EntityChair(World world)
{ this(ModContent.ET_CHAIR, world); }
public static EntityChair customClientFactory(FMLPlayMessages.SpawnEntity spkt, World world)
{ return new EntityChair(world); }
public IPacket<?> createSpawnPacket()
{ return NetworkHooks.getEntitySpawningPacket(this); }
public static boolean accepts_mob(LivingEntity entity)
{
if(!(entity instanceof net.minecraft.entity.monster.MonsterEntity)) return false;
if((entity.getType().getSize().height > 2.5) || (entity.getType().getSize().height > 2.0)) return false;
if(entity instanceof ZombieEntity) return true;
if(entity instanceof ZombieVillagerEntity) return true;
if(entity instanceof ZombiePigmanEntity) return true;
if(entity instanceof HuskEntity) return true;
if(entity instanceof StrayEntity) return true;
if(entity instanceof SkeletonEntity) return true;
if(entity instanceof WitherSkeletonEntity) return true;
return false;
}
public static void sit(World world, LivingEntity sitter, BlockPos pos)
{
if(!sitting_enabled) return;
if((world==null) || (world.isRemote) || (sitter==null) || (pos==null)) return;
if((!(sitter instanceof PlayerEntity)) && (!accepts_mob(sitter))) return;
if(!world.getEntitiesWithinAABB(EntityChair.class, new AxisAlignedBB(pos)).isEmpty()) return;
if(sitter.isBeingRidden() || (!sitter.isAlive()) || (sitter.isPassenger()) ) return;
if((!world.isAirBlock(pos.up())) || (!world.isAirBlock(pos.up(2)))) return;
boolean on_top_of_block_position = true;
boolean use_next_negative_y_position = false;
EntityChair chair = new EntityChair(world);
BlockPos chair_pos = chair.getPosition();
chair.chair_pos = pos;
chair.t_sit = 5;
chair.prevPosX = chair_pos.getX();
chair.prevPosY = chair_pos.getY();
chair.prevPosZ = chair_pos.getZ();
chair.setPosition(pos.getX()+x_offset,pos.getY()+y_offset,pos.getZ()+z_offset);
world.addEntity(chair);
sitter.startRiding(chair, true);
}
@Override
protected void registerData() {}
@Override
protected void readAdditional(CompoundNBT compound) {}
@Override
protected void writeAdditional(CompoundNBT compound) {}
@Override
public boolean canBePushed()
{ return false; }
@Override
public double getMountedYOffset()
{ return 0.0; }
@Override
public void tick()
{
if(world.isRemote) return;
super.tick();
if(--t_sit > 0) return;
Entity sitter = getPassengers().isEmpty() ? null : getPassengers().get(0);
if((sitter==null) || (!sitter.isAlive())) {
this.remove();
return;
}
boolean abort = (!sitting_enabled);
final BlockState state = world.getBlockState(chair_pos);
if((state==null) || (!(state.getBlock() instanceof BlockDecorChair))) abort = true;
if(!world.isAirBlock(chair_pos.up())) abort = true;
if((!(sitter instanceof PlayerEntity)) && (Math.random() < standup_probability)) abort = true;
if(abort) {
for(Entity e:getPassengers()) {
if(e.isAlive()) e.stopRiding();
}
this.remove();
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,114 @@
/*
* @file BlockDecorDirected.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Smaller (cutout) block with a defined facing.
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.IWaterLoggable;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.entity.EntityType;
import net.minecraft.state.StateContainer;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.DirectionProperty;
import net.minecraft.block.Block;
import net.minecraft.block.DirectionalBlock;
import net.minecraft.block.BlockState;
import net.minecraft.world.IBlockReader;
import net.minecraft.util.Direction;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
public class BlockDecorDirected extends BlockDecor
{
public static final DirectionProperty FACING = DirectionalBlock.FACING;
protected final ArrayList<VoxelShape> AABBs;
public BlockDecorDirected(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{
super(config, builder);
setDefaultState(stateContainer.getBaseState().with(FACING, Direction.UP));
final boolean is_horizontal = ((config & BlockDecor.CFG_HORIZIONTAL)!=0);
AABBs = new ArrayList<VoxelShape>(Arrays.asList(
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.DOWN, is_horizontal)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.UP, is_horizontal)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.NORTH, is_horizontal)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.SOUTH, is_horizontal)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.WEST, is_horizontal)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.EAST, is_horizontal)),
VoxelShapes.create(unrotatedAABB),
VoxelShapes.create(unrotatedAABB)
));
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return ((config & CFG_CUTOUT)!=0) ? (RenderTypeHint.CUTOUT_MIPPED) : (RenderTypeHint.SOLID); }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public VoxelShape getShape(BlockState state, IBlockReader source, BlockPos pos, ISelectionContext selectionContext)
{ return AABBs.get((state.get(FACING)).getIndex() & 0x7); }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return getShape(state, world, pos, selectionContext); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(FACING); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
Direction facing = context.getFace();
if((config & (CFG_HORIZIONTAL|CFG_LOOK_PLACEMENT)) == (CFG_HORIZIONTAL|CFG_LOOK_PLACEMENT)) {
// horizontal placement in direction the player is looking
facing = context.getPlacementHorizontalFacing();
} else if((config & (CFG_HORIZIONTAL|CFG_LOOK_PLACEMENT)) == (CFG_HORIZIONTAL)) {
// horizontal placement on a face
if(((facing==Direction.UP)||(facing==Direction.DOWN))) return null;
} else if((config & CFG_LOOK_PLACEMENT)!=0) {
// placement in direction the player is looking, with up and down
facing = context.getNearestLookingDirection();
} else {
// default: placement on the face the player clicking
}
if((config & CFG_OPPOSITE_PLACEMENT)!=0) facing = facing.getOpposite();
if(((config & CFG_FLIP_PLACEMENT_SHIFTCLICK) != 0) && (context.getPlayer().func_225608_bj_()/*isSneaking()*/)) facing = facing.getOpposite();
return super.getStateForPlacement(context).with(FACING, facing);
}
/**
* Water loggable version of directed blocks.
*/
public static class WaterLoggable extends BlockDecorDirected implements IWaterLoggable
{
public WaterLoggable(long config, Block.Properties properties, AxisAlignedBB aabb)
{ super(config|CFG_WATERLOGGABLE, properties, aabb); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(WATERLOGGED); }
}
}

View file

@ -0,0 +1,122 @@
/*
* @file BlockDecorDirectedHorizontal.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Smaller directed block with direction set narrowed
* to horizontal directions.
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.HorizontalBlock;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.entity.EntityType;
import net.minecraft.state.StateContainer;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.DirectionProperty;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.util.Direction;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import wile.engineersdecor.detail.ModAuxiliaries;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
public class BlockDecorDirectedHorizontal extends BlockDecor
{
public static final DirectionProperty HORIZONTAL_FACING = HorizontalBlock.HORIZONTAL_FACING;
protected final ArrayList<VoxelShape> AABBs;
public BlockDecorDirectedHorizontal(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{
super(config|CFG_HORIZIONTAL, builder, unrotatedAABB);
setDefaultState(stateContainer.getBaseState().with(HORIZONTAL_FACING, Direction.NORTH));
AABBs = new ArrayList<VoxelShape>(Arrays.asList(
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.DOWN, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.UP, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.NORTH, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.SOUTH, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.WEST, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.EAST, true)),
VoxelShapes.create(unrotatedAABB),
VoxelShapes.create(unrotatedAABB)
));
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return ((config & CFG_CUTOUT)!=0) ? RenderTypeHint.CUTOUT : RenderTypeHint.SOLID; }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public VoxelShape getShape(BlockState state, IBlockReader source, BlockPos pos, ISelectionContext selectionContext)
{ return AABBs.get((state.get(HORIZONTAL_FACING)).getIndex() & 0x7); }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return getShape(state, world, pos, selectionContext); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(HORIZONTAL_FACING); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
Direction facing = context.getFace();
if((config & CFG_LOOK_PLACEMENT) != 0) {
// horizontal placement in direction the player is looking
facing = context.getPlacementHorizontalFacing();
} else {
// horizontal placement on a face
facing = ((facing==Direction.UP)||(facing==Direction.DOWN)) ? (context.getPlacementHorizontalFacing()) : facing;
}
if((config & CFG_OPPOSITE_PLACEMENT)!=0) facing = facing.getOpposite();
if(((config & CFG_FLIP_PLACEMENT_SHIFTCLICK) != 0) && (context.getPlayer().func_225608_bj_()/*isSneaking()*/)) facing = facing.getOpposite();
return super.getStateForPlacement(context).with(HORIZONTAL_FACING, facing);
}
@Override
@SuppressWarnings("deprecation")
public BlockState rotate(BlockState state, Rotation rot)
{ return state.with(HORIZONTAL_FACING, rot.rotate(state.get(HORIZONTAL_FACING))); }
@Override
@SuppressWarnings("deprecation")
public BlockState mirror(BlockState state, Mirror mirrorIn)
{ return state.rotate(mirrorIn.toRotation(state.get(HORIZONTAL_FACING))); }
/**
* Water loggable version of directed blocks.
*/
public static class WaterLoggable extends BlockDecorDirectedHorizontal implements IWaterLoggable
{
public WaterLoggable(long config, Block.Properties properties, AxisAlignedBB aabb)
{ super(config|CFG_WATERLOGGABLE, properties, aabb); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(WATERLOGGED); }
}
}

View file

@ -0,0 +1,935 @@
/*
* @file BlockDecorDropper.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Dropper factory automation suitable.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.Networking;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.block.DoorBlock;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.math.*;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.world.World;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.item.*;
import net.minecraft.inventory.*;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.*;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.wrapper.SidedInvWrapper;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import com.mojang.blaze3d.systems.RenderSystem;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class BlockDecorDropper extends BlockDecorDirected
{
public static final BooleanProperty OPEN = DoorBlock.OPEN;
public BlockDecorDropper(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.SOLID; }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return VoxelShapes.fullCube(); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(OPEN); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(OPEN, false); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos)
{ return Container.calcRedstone(world.getTileEntity(pos)); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorDropper.BTileEntity(); }
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundNBT te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorDropper.BTileEntity)) return;
((BlockDecorDropper.BTileEntity)te).readnbt(te_nbt, false);
((BlockDecorDropper.BTileEntity)te).reset_rtstate();
((BlockDecorDropper.BTileEntity)te).markDirty();
}
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
final List<ItemStack> stacks = new ArrayList<ItemStack>();
if(world.isRemote) return stacks;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return stacks;
if(!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundNBT te_nbt = ((BTileEntity) te).clear_getnbt();
if(!te_nbt.isEmpty()) {
CompoundNBT nbt = new CompoundNBT();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
for(ItemStack stack: ((BTileEntity)te).stacks_) {
if(!stack.isEmpty()) stacks.add(stack);
}
((BTileEntity)te).reset_rtstate();
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorDropper.BTileEntity)) return true;
if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return true;
NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te);
return true;
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{
if(!(world instanceof World) || (((World) world).isRemote)) return;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).block_updated();
}
@Override
@SuppressWarnings("deprecation")
public boolean canProvidePower(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getWeakPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
@Override
@SuppressWarnings("deprecation")
public int getStrongPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory
{
public static final int NUM_OF_FIELDS = 16;
public static final int TICK_INTERVAL = 32;
public static final int NUM_OF_SLOTS = 15;
public static final int INPUT_SLOTS_FIRST = 0;
public static final int INPUT_SLOTS_SIZE = 12;
public static final int CTRL_SLOTS_FIRST = INPUT_SLOTS_SIZE;
public static final int CTRL_SLOTS_SIZE = 3;
public static final int SHUTTER_CLOSE_DELAY = 40;
public static final int MAX_DROP_COUNT = 32;
public static final int DROP_PERIOD_OFFSET = 10;
///
public static final int DROPLOGIC_FILTER_ANDGATE = 0x01;
public static final int DROPLOGIC_EXTERN_ANDGATE = 0x02;
public static final int DROPLOGIC_SILENT_DROP = 0x04;
public static final int DROPLOGIC_SILENT_OPEN = 0x08;
public static final int DROPLOGIC_CONTINUOUS = 0x10;
///
private int filter_matches_[] = new int[CTRL_SLOTS_SIZE];
private int open_timer_ = 0;
private int drop_timer_ = 0;
private boolean triggered_ = false;
private boolean block_power_signal_ = false;
private boolean block_power_updated_ = false;
private int drop_speed_ = 10;
private int drop_noise_ = 0;
private int drop_xdev_ = 0;
private int drop_ydev_ = 0;
private int drop_count_ = 1;
private int drop_logic_ = DROPLOGIC_EXTERN_ANDGATE;
private int drop_period_ = 0;
private int drop_slot_index_ = 0;
private int tick_timer_ = 0;
protected NonNullList<ItemStack> stacks_;
public static void on_config(int cooldown_ticks)
{
// ModEngineersDecor.logger.info("Config factory dropper:");
}
public BTileEntity()
{ this(ModContent.TET_FACTORY_DROPPER); }
public BTileEntity(TileEntityType<?> te_type)
{
super(te_type);
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
reset_rtstate();
}
public CompoundNBT clear_getnbt()
{
CompoundNBT nbt = new CompoundNBT();
writenbt(nbt, false);
for(int i=0; i<stacks_.size(); ++i) stacks_.set(i, ItemStack.EMPTY);
reset_rtstate();
triggered_ = false;
block_power_updated_ = false;
return nbt;
}
public void reset_rtstate()
{
block_power_signal_ = false;
block_power_updated_ = false;
for(int i=0; i<filter_matches_.length; ++i) filter_matches_[i] = 0;
}
public void readnbt(CompoundNBT nbt, boolean update_packet)
{
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
ItemStackHelper.loadAllItems(nbt, stacks_);
while(stacks_.size() < NUM_OF_SLOTS) stacks_.add(ItemStack.EMPTY);
block_power_signal_ = nbt.getBoolean("powered");
open_timer_ = nbt.getInt("open_timer");
drop_speed_ = nbt.getInt("drop_speed");
drop_noise_ = nbt.getInt("drop_noise");
drop_xdev_ = nbt.getInt("drop_xdev");
drop_ydev_ = nbt.getInt("drop_ydev");
drop_slot_index_ = nbt.getInt("drop_slot_index");
drop_count_ = MathHelper.clamp(nbt.getInt("drop_count"), 1, MAX_DROP_COUNT);
drop_logic_ = nbt.getInt("drop_logic");
drop_period_ = nbt.getInt("drop_period");
}
protected void writenbt(CompoundNBT nbt, boolean update_packet)
{
ItemStackHelper.saveAllItems(nbt, stacks_);
nbt.putBoolean("powered", block_power_signal_);
nbt.putInt("open_timer", open_timer_);
nbt.putInt("drop_speed", drop_speed_);
nbt.putInt("drop_noise", drop_noise_);
nbt.putInt("drop_xdev", drop_xdev_);
nbt.putInt("drop_ydev", drop_ydev_);
nbt.putInt("drop_slot_index", drop_slot_index_);
nbt.putInt("drop_count", drop_count_);
nbt.putInt("drop_logic", drop_logic_);
nbt.putInt("drop_period", drop_period_);
}
public void block_updated()
{
// RS power check, both edges
boolean powered = world.isBlockPowered(pos);
if(block_power_signal_ != powered) block_power_updated_ = true;
block_power_signal_ = powered;
tick_timer_ = 1;
}
public boolean is_input_slot(int index)
{ return (index >= INPUT_SLOTS_FIRST) && (index < (INPUT_SLOTS_FIRST+INPUT_SLOTS_SIZE)); }
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt, false); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt, false); return nbt; }
// INamable ----------------------------------------------------------------------------------------------
@Override
public ITextComponent getName()
{ final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Factory dropper"); }
@Override
public boolean hasCustomName()
{ return false; }
@Override
public ITextComponent getCustomName()
{ return getName(); }
// INamedContainerProvider ------------------------------------------------------------------------------
@Override
public ITextComponent getDisplayName()
{ return INameable.super.getDisplayName(); }
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); }
// IInventory -------------------------------------------------------------------------------------------
@Override
public int getSizeInventory()
{ return stacks_.size(); }
@Override
public boolean isEmpty()
{ for(ItemStack stack: stacks_) { if(!stack.isEmpty()) return false; } return true; }
@Override
public ItemStack getStackInSlot(int index)
{ return (index < getSizeInventory()) ? stacks_.get(index) : ItemStack.EMPTY; }
@Override
public ItemStack decrStackSize(int index, int count)
{ return ItemStackHelper.getAndSplit(stacks_, index, count); }
@Override
public ItemStack removeStackFromSlot(int index)
{ return ItemStackHelper.getAndRemove(stacks_, index); }
@Override
public void setInventorySlotContents(int index, ItemStack stack)
{
stacks_.set(index, stack);
if(stack.getCount() > getInventoryStackLimit()) stack.setCount(getInventoryStackLimit());
if(tick_timer_ > 8) tick_timer_ = 8;
markDirty();
}
@Override
public int getInventoryStackLimit()
{ return 64; }
@Override
public void markDirty()
{ super.markDirty(); }
@Override
public boolean isUsableByPlayer(PlayerEntity player)
{ return getPos().distanceSq(player.getPosition()) < 36; }
@Override
public void openInventory(PlayerEntity player)
{}
@Override
public void closeInventory(PlayerEntity player)
{ markDirty(); }
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{ return true; }
@Override
public void clear()
{ stacks_.clear(); }
// Fields -----------------------------------------------------------------------------------------------
protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS)
{
@Override
public int get(int id)
{
switch(id) {
case 0: return drop_speed_;
case 1: return drop_xdev_;
case 2: return drop_ydev_;
case 3: return drop_noise_;
case 4: return drop_count_;
case 5: return drop_logic_;
case 6: return drop_period_;
case 9: return drop_timer_;
case 10: return open_timer_;
case 11: return block_power_signal_ ? 1 : 0;
case 12: return filter_matches_[0];
case 13: return filter_matches_[1];
case 14: return filter_matches_[2];
case 15: return drop_slot_index_;
default: return 0;
}
}
@Override
public void set(int id, int value)
{
switch(id) {
case 0: drop_speed_ = MathHelper.clamp(value, 0, 100); return;
case 1: drop_xdev_ = MathHelper.clamp(value, -100, 100); return;
case 2: drop_ydev_ = MathHelper.clamp(value, -100, 100); return;
case 3: drop_noise_ = MathHelper.clamp(value, 0, 100); return;
case 4: drop_count_ = MathHelper.clamp(value, 1, MAX_DROP_COUNT); return;
case 5: drop_logic_ = value; return;
case 6: drop_period_ = MathHelper.clamp(value, 0, 100); return;
case 9: drop_timer_ = MathHelper.clamp(value, 0, 400); return;
case 10: open_timer_ = MathHelper.clamp(value, 0, 400); return;
case 11: block_power_signal_ = (value != 0); return;
case 12: filter_matches_[0] = (value & 0x3); return;
case 13: filter_matches_[1] = (value & 0x3); return;
case 14: filter_matches_[2] = (value & 0x3); return;
case 15: drop_slot_index_ = MathHelper.clamp(value, INPUT_SLOTS_FIRST, INPUT_SLOTS_FIRST+INPUT_SLOTS_SIZE-1); return;
default: return;
}
}
};
// ISidedInventory --------------------------------------------------------------------------------------
LazyOptional<? extends IItemHandler>[] item_handlers = SidedInvWrapper.create(this, Direction.UP);
private static final int[] SIDED_INV_SLOTS;
static {
SIDED_INV_SLOTS = new int[INPUT_SLOTS_SIZE];
for(int i=0; i<INPUT_SLOTS_SIZE; ++i) SIDED_INV_SLOTS[i] = i+INPUT_SLOTS_FIRST;
}
@Override
public int[] getSlotsForFace(Direction side)
{ return SIDED_INV_SLOTS; }
@Override
public boolean canInsertItem(int index, ItemStack stack, Direction direction)
{ return is_input_slot(index) && isItemValidForSlot(index, stack); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return false; }
// Capability export ------------------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return item_handlers[0].cast();
}
return super.getCapability(capability, facing);
}
// ITickable and aux methods ----------------------------------------------------------------------------
private static void drop(World world, BlockPos pos, Direction facing, ItemStack stack, int speed_percent, int xdeviation, int ydeviation, int noise_percent)
{
final double ofs = facing==Direction.DOWN ? 0.8 : 0.7;
Vec3d v0 = new Vec3d(facing.getXOffset(), facing.getYOffset(), facing.getZOffset());
final ItemEntity ei = new ItemEntity(world, (pos.getX()+0.5)+(ofs*v0.x), (pos.getY()+0.5)+(ofs*v0.y), (pos.getZ()+0.5)+(ofs*v0.z), stack);
if((xdeviation != 0) || (ydeviation != 0)) {
double vdx = 1e-2 * MathHelper.clamp(xdeviation, -100, 100);
double vdy = 1e-2 * MathHelper.clamp(ydeviation, -100, 100);
switch(facing) { // switch-case faster than coorsys fwd transform
case DOWN: v0 = v0.add( vdx, 0,-vdy); break;
case NORTH: v0 = v0.add( vdx, vdy, 0); break;
case SOUTH: v0 = v0.add(-vdx, vdy, 0); break;
case EAST: v0 = v0.add(0, vdy, vdx); break;
case WEST: v0 = v0.add(0, vdy, -vdx); break;
case UP: v0 = v0.add( vdx, 0, vdy); break;
}
}
if(noise_percent > 0) {
v0 = v0.add(
((world.rand.nextDouble()-0.5) * 1e-3 * noise_percent),
((world.rand.nextDouble()-0.5) * 1e-3 * noise_percent),
((world.rand.nextDouble()-0.5) * 1e-3 * noise_percent)
);
}
if(speed_percent < 5) speed_percent = 5;
double speed = 1e-2 * speed_percent;
if(noise_percent > 0) speed += (world.rand.nextDouble()-0.5) * 1e-4 * noise_percent;
v0 = v0.normalize().scale(speed);
ei.setMotion(v0.x, v0.y, v0.z);
ei.velocityChanged = true;
world.addEntity(ei);
}
@Nullable
BlockState update_blockstate()
{
BlockState state = world.getBlockState(pos);
if(!(state.getBlock() instanceof BlockDecorDropper)) return null;
boolean open = (open_timer_ > 0);
if(state.get(OPEN) != open) {
state = state.with(OPEN, open);
world.setBlockState(pos, state, 2|16);
if((drop_logic_ & DROPLOGIC_SILENT_OPEN) == 0) {
if(open) {
world.playSound(null, pos, SoundEvents.BLOCK_WOODEN_TRAPDOOR_OPEN, SoundCategory.BLOCKS, 0.08f, 3f);
} else {
world.playSound(null, pos, SoundEvents.BLOCK_WOODEN_TRAPDOOR_CLOSE, SoundCategory.BLOCKS, 0.08f, 3f);
}
}
}
return state;
}
private static int next_slot(int i)
{ return (i<INPUT_SLOTS_SIZE-1) ? (i+1) : INPUT_SLOTS_FIRST; }
@Override
public void tick()
{
if(world.isRemote) return;
if(--open_timer_ < 0) open_timer_ = 0;
if((drop_timer_ > 0) && ((--drop_timer_) == 0)) markDirty();
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
final boolean continuous_mode = (drop_logic_ & DROPLOGIC_CONTINUOUS)!=0;
boolean dirty = block_power_updated_;
boolean redstone_trigger = (block_power_signal_ && ((block_power_updated_) || (continuous_mode)));
boolean filter_trigger;
boolean filter_defined;
boolean trigger;
// Trigger logic
{
boolean droppable_slot_found = false;
for(int i=INPUT_SLOTS_FIRST; i<(INPUT_SLOTS_FIRST+INPUT_SLOTS_SIZE); ++i) {
if(stacks_.get(i).getCount() >= drop_count_) { droppable_slot_found = true; break; }
}
// From filters / inventory checks
{
int filter_nset = 0;
int last_filter_matches_[] = filter_matches_.clone();
boolean slot_assigned = false;
for(int ci=0; ci<CTRL_SLOTS_SIZE; ++ci) {
filter_matches_[ci] = 0;
final ItemStack cmp_stack = stacks_.get(CTRL_SLOTS_FIRST+ci);
if(cmp_stack.isEmpty()) continue;
filter_matches_[ci] = 1;
final int cmp_stack_count = cmp_stack.getCount();
int inventory_item_count = 0;
int slot = drop_slot_index_;
for(int i=INPUT_SLOTS_FIRST; i<(INPUT_SLOTS_FIRST+INPUT_SLOTS_SIZE); ++i) {
final ItemStack inp_stack = stacks_.get(slot);
if(!inp_stack.isItemEqual(cmp_stack)) { slot = next_slot(slot); continue; }
inventory_item_count += inp_stack.getCount();
if(inventory_item_count < cmp_stack_count) { slot = next_slot(slot); continue; }
filter_matches_[ci] = 2;
break;
}
}
int nmatched = 0;
for(int i=0; i<filter_matches_.length; ++i) {
if(filter_matches_[i] > 0) ++filter_nset;
if(filter_matches_[i] > 1) ++nmatched;
if(filter_matches_[i] != last_filter_matches_[i]) dirty = true;
}
filter_defined = (filter_nset > 0);
filter_trigger = ((filter_nset > 0) && (nmatched > 0));
if(((drop_logic_ & DROPLOGIC_FILTER_ANDGATE) != 0) && (nmatched != filter_nset)) filter_trigger = false;
}
// gates
{
if(filter_defined) {
trigger = ((drop_logic_ & DROPLOGIC_EXTERN_ANDGATE) != 0) ? (filter_trigger && redstone_trigger) : (filter_trigger || redstone_trigger);
} else {
trigger = redstone_trigger;
}
if(triggered_) { triggered_ = false; trigger = true; }
if(!droppable_slot_found) {
if(open_timer_> 10) open_timer_ = 10; // override if dropping is not possible at all.
} else if(trigger || filter_trigger || redstone_trigger) {
open_timer_ = SHUTTER_CLOSE_DELAY;
}
}
// edge detection for next cycle
{
boolean tr = world.isBlockPowered(pos);
block_power_updated_ = (block_power_signal_ != tr);
block_power_signal_ = tr;
if(block_power_updated_) dirty = true;
}
}
// block state update
final BlockState state = update_blockstate();
if(state == null) { block_power_signal_= false; return; }
// dispense action
if(trigger && (drop_timer_ <= 0)) {
// drop stack for non-filter triggers
ItemStack drop_stacks[] = {ItemStack.EMPTY,ItemStack.EMPTY,ItemStack.EMPTY};
if(!filter_trigger) {
for(int i=0; i<INPUT_SLOTS_SIZE; ++i) {
if(drop_slot_index_ >= INPUT_SLOTS_SIZE) drop_slot_index_ = 0;
int ic = drop_slot_index_;
drop_slot_index_ = next_slot(drop_slot_index_);
ItemStack ds = stacks_.get(ic);
if((!ds.isEmpty()) && (ds.getCount() >= drop_count_)) {
drop_stacks[0] = ds.split(drop_count_);
stacks_.set(ic, ds);
break;
}
}
} else {
for(int fi=0; fi<filter_matches_.length; ++fi) {
if(filter_matches_[fi] > 1) {
drop_stacks[fi] = stacks_.get(CTRL_SLOTS_FIRST+fi).copy();
int ntoremove = drop_stacks[fi].getCount();
for(int i=INPUT_SLOTS_SIZE-1; (i>=0) && (ntoremove>0); --i) {
ItemStack stack = stacks_.get(i);
if(!stack.isItemEqual(drop_stacks[fi])) continue;
if(stack.getCount() <= ntoremove) {
ntoremove -= stack.getCount();
stacks_.set(i, ItemStack.EMPTY);
} else {
stack.shrink(ntoremove);
ntoremove = 0;
stacks_.set(i, stack);
}
}
if(ntoremove > 0) drop_stacks[fi].shrink(ntoremove);
}
}
}
// drop action
boolean dropped = false;
for(int i = 0; i < drop_stacks.length; ++i) {
if(drop_stacks[i].isEmpty()) continue;
dirty = true;
drop(world, pos, state.get(FACING), drop_stacks[i], drop_speed_, drop_xdev_, drop_ydev_, drop_noise_);
dropped = true;
}
// cooldown
if(dropped) drop_timer_ = DROP_PERIOD_OFFSET + drop_period_ * 2; // 0.1s time base -> 100%===10s
// drop sound
if(dropped && ((drop_logic_ & DROPLOGIC_SILENT_DROP) == 0)) {
world.playSound(null, pos, SoundEvents.BLOCK_WOOD_HIT, SoundCategory.BLOCKS, 0.1f, 4f);
}
// advance to next nonempty slot.
for(int i = 0; i < INPUT_SLOTS_SIZE; ++i) {
if(!stacks_.get(drop_slot_index_).isEmpty()) break;
drop_slot_index_ = next_slot(drop_slot_index_);
}
}
if(dirty) markDirty();
if(trigger && (tick_timer_ > 10)) tick_timer_ = 10;
}
}
//--------------------------------------------------------------------------------------------------------------------
// container
//--------------------------------------------------------------------------------------------------------------------
public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer
{
private static final int PLAYER_INV_START_SLOTNO = BTileEntity.NUM_OF_SLOTS;
private final PlayerEntity player_;
private final IInventory inventory_;
private final IWorldPosCallable wpc_;
private final IIntArray fields_;
public final int field(int index) { return fields_.get(index); }
public BContainer(int cid, PlayerInventory player_inventory)
{ this(cid, player_inventory, new Inventory(BTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(BTileEntity.NUM_OF_FIELDS)); }
private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields)
{
super(ModContent.CT_FACTORY_DROPPER, cid);
fields_ = fields;
wpc_ = wpc;
player_ = player_inventory.player;
inventory_ = block_inventory;
int i=-1;
// input slots (stacks 0 to 11)
for(int y=0; y<2; ++y) {
for(int x=0; x<6; ++x) {
int xpos = 10+x*18, ypos = 6+y*17;
addSlot(new Slot(inventory_, ++i, xpos, ypos));
}
}
// filter slots (stacks 12 to 14)
addSlot(new Slot(inventory_, ++i, 19, 48));
addSlot(new Slot(inventory_, ++i, 55, 48));
addSlot(new Slot(inventory_, ++i, 91, 48));
// player slots
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 8+x*18, 144)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 86+y*18)); // player slots: 9..35
}
}
this.trackIntArray(fields_); // === Add reference holders
}
@Override
public boolean canInteractWith(PlayerEntity player)
{ return inventory_.isUsableByPlayer(player); }
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int index)
{
Slot slot = getSlot(index);
if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getStack();
ItemStack transferred = slot_stack.copy();
if((index>=0) && (index<PLAYER_INV_START_SLOTNO)) {
// Device slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
// Player slot
if(!mergeItemStack(slot_stack, 0, BTileEntity.INPUT_SLOTS_SIZE, false)) return ItemStack.EMPTY;
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
return transferred;
}
// INetworkSynchronisableContainer ---------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public void onGuiAction(CompoundNBT nbt)
{ Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); }
@OnlyIn(Dist.CLIENT)
public void onGuiAction(String key, int value)
{
CompoundNBT nbt = new CompoundNBT();
nbt.putInt(key, value);
Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt);
}
@Override
public void onServerPacketReceived(int windowId, CompoundNBT nbt)
{}
@Override
public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt)
{
if(!(inventory_ instanceof BTileEntity)) return;
BTileEntity te = (BTileEntity)inventory_;
if(nbt.contains("drop_speed")) te.drop_speed_ = MathHelper.clamp(nbt.getInt("drop_speed"), 0, 100);
if(nbt.contains("drop_xdev")) te.drop_xdev_ = MathHelper.clamp(nbt.getInt("drop_xdev"), -100, 100);
if(nbt.contains("drop_ydev")) te.drop_ydev_ = MathHelper.clamp(nbt.getInt("drop_ydev"), -100, 100);
if(nbt.contains("drop_count")) te.drop_count_ = MathHelper.clamp(nbt.getInt("drop_count"), 1, BTileEntity.MAX_DROP_COUNT);
if(nbt.contains("drop_period")) te.drop_period_ = MathHelper.clamp(nbt.getInt("drop_period"), 0, 100);
if(nbt.contains("drop_logic")) te.drop_logic_ = nbt.getInt("drop_logic");
if(nbt.contains("manual_rstrigger") && (nbt.getInt("manual_rstrigger")!=0)) { te.block_power_signal_=true; te.block_power_updated_=true; te.tick_timer_=1; }
if(nbt.contains("manual_trigger") && (nbt.getInt("manual_trigger")!=0)) { te.tick_timer_ = 1; te.triggered_ = true; }
te.markDirty();
}
}
//--------------------------------------------------------------------------------------------------------------------
// GUI
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class BGui extends ContainerScreen<BContainer>
{
protected final PlayerEntity player_;
public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title)
{ super(container, player_inventory, title); this.player_ = player_inventory.player; }
@Override
public void init()
{ super.init(); }
@Override
public void render(int mouseX, int mouseY, float partialTicks)
{
renderBackground();
super.render(mouseX, mouseY, partialTicks);
renderHoveredToolTip(mouseX, mouseY);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton)
{
BContainer container = (BContainer)getContainer();
int mx = (int)(mouseX - getGuiLeft() + .5), my = (int)(mouseY - getGuiTop() + .5);
if((!isPointInRegion(114, 1, 61, 79, mouseX, mouseY))) {
return super.mouseClicked(mouseX, mouseY, mouseButton);
} else if(isPointInRegion(130, 10, 12, 25, mouseX, mouseY)) {
int force_percent = 100 - MathHelper.clamp(((my-10)*100)/25, 0, 100);
container.onGuiAction("drop_speed", force_percent);
} else if(isPointInRegion(145, 10, 25, 25, mouseX, mouseY)) {
int xdev = MathHelper.clamp( (int)Math.round(((double)((mx-157) * 100)) / 12), -100, 100);
int ydev = MathHelper.clamp(-(int)Math.round(((double)((my- 22) * 100)) / 12), -100, 100);
if(Math.abs(xdev) < 9) xdev = 0;
if(Math.abs(ydev) < 9) ydev = 0;
CompoundNBT nbt = new CompoundNBT();
nbt.putInt("drop_xdev", xdev);
nbt.putInt("drop_ydev", ydev);
container.onGuiAction(nbt);
} else if(isPointInRegion(129, 40, 44, 10, mouseX, mouseY)) {
int ndrop = (mx-135);
if(ndrop < -1) {
ndrop = container.field(4) - 1; // -
} else if(ndrop >= 34) {
ndrop = container.field(4) + 1; // +
} else {
ndrop = MathHelper.clamp(1+ndrop, 1, BTileEntity.MAX_DROP_COUNT); // slider
}
container.onGuiAction("drop_count", ndrop);
} else if(isPointInRegion(129, 50, 44, 10, mouseX, mouseY)) {
int period = (mx-135);
if(period < -1) {
period = container.field(6) - 3; // -
} else if(period >= 34) {
period = container.field(6) + 3; // +
} else {
period = (int)(0.5 + ((100.0 * period)/34));
}
period = MathHelper.clamp(period, 0, 100);
container.onGuiAction("drop_period", period);
} else if(isPointInRegion(114, 51, 9, 9, mouseX, mouseY)) {
container.onGuiAction("manual_rstrigger", 1);
} else if(isPointInRegion(162, 66, 7, 9, mouseX, mouseY)) {
container.onGuiAction("drop_logic", container.field(5) ^ BTileEntity.DROPLOGIC_CONTINUOUS);
} else if(isPointInRegion(132, 66, 9, 9, mouseX, mouseY)) {
container.onGuiAction("drop_logic", container.field(5) ^ BTileEntity.DROPLOGIC_FILTER_ANDGATE);
} else if(isPointInRegion(148, 66, 9, 9, mouseX, mouseY)) {
container.onGuiAction("drop_logic", container.field(5) ^ BTileEntity.DROPLOGIC_EXTERN_ANDGATE);
}
return true;
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
{
RenderSystem.enableBlend();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
this.minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/factory_dropper_gui.png"));
final int x0=getGuiLeft(), y0=getGuiTop(), w=getXSize(), h=getYSize();
blit(x0, y0, 0, 0, w, h);
BContainer container = (BContainer)getContainer();
// active drop slot
{
int drop_slot_index = container.field(15);
if((drop_slot_index < 0) || (drop_slot_index >= 16)) drop_slot_index = 0;
int x = (x0+9+((drop_slot_index % 6) * 18));
int y = (y0+5+((drop_slot_index / 6) * 17));
blit(x, y, 180, 45, 18, 18);
}
// filter LEDs
{
for(int i=0; i<3; ++i) {
int xt = 180 + (6 * container.field(12+i)), yt = 38;
int x = x0 + 31 + (i * 36), y = y0 + 65;
blit(x, y, xt, yt, 6, 6);
}
}
// force adjustment
{
int hy = 2 + (((100-container.field(0)) * 21) / 100);
int x = x0+135, y = y0+12, xt = 181;
int yt = 4 + (23-hy);
blit(x, y, xt, yt, 3, hy);
}
// angle adjustment
{
int x = x0 + 157 - 3 + ((container.field(1) * 12) / 100);
int y = y0 + 22 - 3 - ((container.field(2) * 12) / 100);
blit(x, y, 180, 30, 7, 7);
}
// drop count
{
int x = x0 + 134 - 2 + (container.field(4));
int y = y0 + 45;
blit(x, y, 190, 31, 5, 5);
}
// drop period
{
int px = (int)Math.round(((33.0 * container.field(6)) / 100) + 1);
int x = x0 + 134 - 2 + MathHelper.clamp(px, 0, 33);
int y = y0 + 56;
blit(x, y, 190, 31, 5, 5);
}
// redstone input
{
if(container.field(11) != 0) {
blit(x0+114, y0+51, 189, 18, 9, 9);
}
}
// trigger logic
{
int filter_gate_offset = ((container.field(5) & BTileEntity.DROPLOGIC_FILTER_ANDGATE) != 0) ? 11 : 0;
int extern_gate_offset = ((container.field(5) & BTileEntity.DROPLOGIC_EXTERN_ANDGATE) != 0) ? 11 : 0;
int pulse_mode_offset = ((container.field(5) & BTileEntity.DROPLOGIC_CONTINUOUS ) != 0) ? 10 : 0;
blit(x0+132, y0+66, 179+filter_gate_offset, 66, 9, 9);
blit(x0+148, y0+66, 179+extern_gate_offset, 66, 9, 9);
blit(x0+162, y0+66, 200+pulse_mode_offset, 66, 9, 9);
}
// drop timer running indicator
{
if((container.field(9) > BTileEntity.DROP_PERIOD_OFFSET) && ((System.currentTimeMillis() % 1000) < 500)) {
blit(x0+149, y0+51, 201, 39, 3, 3);
}
}
RenderSystem.disableBlend();
}
}
}

View file

@ -0,0 +1,115 @@
/*
* @file BlockDecorWall.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Wall blocks.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.world.*;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.IFluidState;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.state.StateContainer;
import net.minecraft.block.*;
import net.minecraft.block.material.PushReaction;
import net.minecraft.block.BlockState;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.fluid.Fluids;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import java.util.List;
public class BlockDecorFence extends WallBlock implements IDecorBlock
{
private final VoxelShape[] shape_voxels;
private final VoxelShape[] collision_shape_voxels;
public BlockDecorFence(long config, Block.Properties builder)
{
super(builder);
this.shape_voxels = buildWallShapes(1.5f, 1.5f, 16f, 0f, 16f);
this.collision_shape_voxels = buildWallShapes(1.5f, 1.5f, 24f, 0f, 24f);
}
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{ ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); }
protected VoxelShape[] buildWallShapes(float pole_width_x, float pole_width_z, float pole_height, float side_min_y, float side_max_y)
{ return super.makeShapes(pole_width_x, pole_width_z, pole_height, side_min_y, side_max_y); }
@Override
public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return shape_voxels[this.getIndex(state)]; }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return collision_shape_voxels[this.getIndex(state)]; }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); }
private boolean attachesTo(BlockState facingState, IWorldReader world, BlockPos facingPos, Direction side)
{
final Block block = facingState.getBlock();
if((block instanceof FenceGateBlock) || (block instanceof BlockDecorFence) || (block instanceof BlockDecorWall)) return true;
final BlockState oppositeState = world.getBlockState(facingPos.offset(side, 2));
if(!(oppositeState.getBlock() instanceof BlockDecorFence)) return false;
return facingState.isNormalCube(world, facingPos) && hasSolidSide(facingState, world, facingPos, side);
}
public BlockState getStateForPlacement(BlockItemUseContext context)
{
IWorldReader world = context.getWorld();
BlockPos pos = context.getPos();
IFluidState fs = context.getWorld().getFluidState(context.getPos());
boolean n = attachesTo(world.getBlockState(pos.north()), world, pos.north(), Direction.SOUTH);
boolean e = attachesTo(world.getBlockState(pos.east()), world, pos.east(), Direction.WEST);
boolean s = attachesTo(world.getBlockState(pos.south()), world, pos.south(), Direction.NORTH);
boolean w = attachesTo(world.getBlockState(pos.west()), world, pos.west(), Direction.EAST);
boolean not_straight = (!n || !s || e || w) && (n || s || !e || !w);
return getDefaultState().with(UP, not_straight).with(NORTH, n).with(EAST, e).with(SOUTH, s).with(WEST, w).with(WATERLOGGED, fs.getFluid() == Fluids.WATER);
}
@Override
public BlockState updatePostPlacement(BlockState state, Direction side, BlockState facingState, IWorld world, BlockPos currentPos, BlockPos facingPos)
{
if(state.get(WATERLOGGED)) world.getPendingFluidTicks().scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickRate(world));
if(side == Direction.DOWN) return super.updatePostPlacement(state, side, facingState, world, currentPos, facingPos);
boolean n = (side==Direction.NORTH) ? attachesTo(facingState, world, facingPos, side) : state.get(NORTH);
boolean e = (side==Direction.EAST) ? attachesTo(facingState, world, facingPos, side) : state.get(EAST);
boolean s = (side==Direction.SOUTH) ? attachesTo(facingState, world, facingPos, side) : state.get(SOUTH);
boolean w = (side==Direction.WEST) ? attachesTo(facingState, world, facingPos, side) : state.get(WEST);
boolean not_straight = (!n || !s || e || w) && (n || s || !e || !w);
return state.with(UP, not_straight).with(NORTH, n).with(EAST, e).with(SOUTH, s).with(WEST, w);
}
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public PushReaction getPushReaction(BlockState state)
{ return PushReaction.NORMAL; }
}

View file

@ -0,0 +1,74 @@
/*
* @file BlockDecorFloorGrating.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Floor gratings.
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
public class BlockDecorFloorGrating extends BlockDecor.WaterLoggable
{
public BlockDecorFloorGrating(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config|CFG_WATERLOGGABLE, builder, unrotatedAABB); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
@Override
public boolean propagatesSkylightDown(BlockState state, IBlockReader reader, BlockPos pos)
{ return true; }
@Override
public void onLanded(IBlockReader world, Entity entity)
{
if(!(entity instanceof ItemEntity)) {
super.onLanded(world, entity);
} else {
entity.setMotion(0, -0.1,0);
entity.setPositionAndUpdate(entity.getPosition().getX(), entity.getPosition().getY()-0.3, entity.getPosition().getZ());
}
}
@Override
public void onFallenUpon(World world, BlockPos pos, Entity entity, float fallDistance)
{
if(!(entity instanceof ItemEntity)) {
super.onFallenUpon(world, pos, entity, fallDistance);
} else {
entity.setMotion(0, -0.1,0);
entity.setPositionAndUpdate(entity.getPosition().getX(), entity.getPosition().getY()-0.3, entity.getPosition().getZ());
}
}
@Override
@SuppressWarnings("deprecation")
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity)
{
if(!(entity instanceof ItemEntity)) return;
if((entity.getPosition().getY()-pos.getY()) < 0.7) return;
double vy = MathHelper.clamp(entity.getMotion().y, -1.2, -0.2);
entity.setMotion(0, vy, 0);
entity.setPositionAndUpdate(pos.getX()+0.5, entity.getPosition().getY()-0.3, pos.getZ()+0.5);
}
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context)
{ return (context.getEntity() instanceof ItemEntity) ? VoxelShapes.empty() : super.getCollisionShape(state, world, pos, context); }
}

View file

@ -0,0 +1,392 @@
/*
* @file BlockDecorFluidFunnel.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* A device that collects and stores fluid blocks above it.
* Tracks flowing fluid to their source blocks. Compatible
* with vanilla infinite water source.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import net.minecraft.block.*;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.IntegerProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.*;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.*;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
public class BlockDecorFluidFunnel extends BlockDecor
{
public static final int FILL_LEVEL_MAX = 3;
public static final IntegerProperty FILL_LEVEL = IntegerProperty.create("level", 0, FILL_LEVEL_MAX);
public BlockDecorFluidFunnel(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(FILL_LEVEL); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(FILL_LEVEL, 0); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BTileEntity(); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState state, World world, BlockPos pos)
{ return MathHelper.clamp((state.get(FILL_LEVEL)*5), 0, 15); }
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundNBT te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).readnbt(te_nbt);
((BTileEntity)te).markDirty();
world.setBlockState(pos, state.with(FILL_LEVEL, 0));
}
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
final List<ItemStack> stacks = new ArrayList<ItemStack>();
if(world.isRemote) return stacks;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return stacks;
if(!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundNBT te_nbt = new CompoundNBT();
((BTileEntity)te).writenbt(te_nbt);
if(!te_nbt.isEmpty()) {
CompoundNBT nbt = new CompoundNBT();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
stacks.add(new ItemStack(this, 1));
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return false;
return FluidUtil.interactWithFluidHandler(player, hand, world, pos, rayTraceResult.getFace());
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{ TileEntity te = world.getTileEntity(pos); if(te instanceof BTileEntity) ((BTileEntity)te).block_changed(); }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, ICapabilityProvider
{
public static final int TANK_CAPACITY = 3000;
public static final int TICK_INTERVAL = 10; // ca 500ms
public static final int COLLECTION_INTERVAL = 40; // ca 2000ms, simulates suction delay and saves CPU when not drained.
public static final int MAX_TRACK_RADIUS = 16;
public static final int MAX_TRACKING_STEPS_PER_CYCLE = 72;
public static final int MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE = 1024;
public static final int MAX_TRACK_RADIUS_SQ = MAX_TRACK_RADIUS*MAX_TRACK_RADIUS;
public static final int INTENSIVE_SEARCH_TRIGGER_THRESHOLD = 16;
private FluidStack tank_ = FluidStack.EMPTY;
private int tick_timer_ = 0;
private int collection_timer_ = 0;
private int no_fluid_found_counter_ = 0;
private int intensive_search_counter_ = 0;
private int total_pick_counter_ = 0;
private BlockPos last_pick_pos_ = BlockPos.ZERO;
private ArrayList<Vec3i> search_offsets_ = null;
public void block_changed()
{ tick_timer_ = TICK_INTERVAL; } // collect after flowing fluid has a stable state, otherwise it looks odd.
public BTileEntity()
{ this(ModContent.TET_SMALL_FLUID_FUNNEL); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
public void readnbt(CompoundNBT nbt)
{
tank_ = (!nbt.contains("tank")) ? (FluidStack.EMPTY) : (FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
}
public void writenbt(CompoundNBT nbt)
{
if(!tank_.isEmpty()) nbt.put("tank", tank_.writeToNBT(new CompoundNBT()));
}
// TileEntity -----------------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt); return nbt; }
// ICapabilityProvider / Output flow handler ----------------------------------------------------------
private static class OutputFluidHandler implements IFluidHandler
{
private final BTileEntity te;
OutputFluidHandler(BTileEntity parent) { te = parent; }
@Override public int getTanks() { return 1; }
@Override public FluidStack getFluidInTank(int tank) { return te.tank_.copy(); }
@Override public int getTankCapacity(int tank) { return TANK_CAPACITY; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return true; }
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
@Override public FluidStack drain(FluidStack resource, FluidAction action)
{
if((resource==null) || (te.tank_.isEmpty())) return FluidStack.EMPTY;
return (!(te.tank_.isFluidEqual(resource))) ? (FluidStack.EMPTY) : drain(resource.getAmount(), action);
}
@Override public FluidStack drain(int maxDrain, FluidAction action)
{
if(te.tank_.isEmpty()) return FluidStack.EMPTY;
FluidStack res = te.tank_.copy();
maxDrain = MathHelper.clamp(maxDrain ,0 , te.tank_.getAmount());
res.setAmount(maxDrain);
if(action != FluidAction.EXECUTE) return res;
te.tank_.setAmount(te.tank_.getAmount()-maxDrain);
if(te.tank_.getAmount() <= 0) te.tank_ = FluidStack.EMPTY;
return res;
}
}
private final LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> new OutputFluidHandler(this));
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) return fluid_handler_.cast();
return super.getCapability(capability, facing);
}
// ITickableTileEntity --------------------------------------------------------------------------------
private IFluidState get_fluidstate(BlockPos pos)
{
// todo: check if getFluidState() is enough
final Block collection_block = world.getBlockState(pos).getBlock();
if((!(collection_block instanceof IFluidBlock)) && (!(collection_block instanceof FlowingFluidBlock)) && (!(collection_block instanceof IWaterLoggable))) {
return Fluids.EMPTY.getDefaultState();
}
return world.getFluidState(pos);
}
private boolean try_pick(BlockPos pos, IFluidState fluidstate)
{
if(!fluidstate.isSource()) return false;
IFluidHandler hnd = FluidUtil.getFluidHandler(world, pos, null).orElse(null);
FluidStack fs;
if(hnd != null) {
fs = hnd.drain(TANK_CAPACITY, FluidAction.EXECUTE); // IFluidBlock
} else {
fs = new FluidStack(fluidstate.getFluid(), 1000);
BlockState state = world.getBlockState(pos);
if(state instanceof IBucketPickupHandler) {
((IBucketPickupHandler)state).pickupFluid(world, pos, state);
} else {
world.setBlockState(pos, Blocks.AIR.getDefaultState(), 1|2); // ok we can't leave the block, that would be an infinite source of an unknown fluid.
}
}
if((fs==null) || (fs.isEmpty())) return false; // it's marked nonnull but I don't trust every modder - including meself ...
if(tank_.isEmpty()) {
tank_ = fs.copy();
} else if(tank_.isFluidEqual(fs)) {
tank_.setAmount(MathHelper.clamp(tank_.getAmount()+fs.getAmount(), 0, TANK_CAPACITY));
} else {
return false;
}
return true;
}
private boolean can_pick(BlockPos pos, IFluidState fluidstate)
{
if(fluidstate.isSource()) return true;
IFluidHandler hnd = FluidUtil.getFluidHandler(world, pos, null).orElse(null);
if(hnd == null) return false;
FluidStack fs = hnd.drain(TANK_CAPACITY, FluidAction.SIMULATE); // don't trust that everyone returns nonnull
return ((fs!=null) && (!fs.isEmpty())) && (fluidstate.getFluid().isEquivalentTo(fs.getFluid()));
}
private void rebuild_search_offsets(boolean intensive)
{
search_offsets_ = new ArrayList<>(9);
search_offsets_.add(new Vec3i(0, 1, 0)); // up first
{
ArrayList<Vec3i> ofs = new ArrayList<Vec3i>(Arrays.asList(new Vec3i(-1, 0, 0), new Vec3i( 1, 0, 0), new Vec3i( 0, 0,-1), new Vec3i( 0, 0, 1)));
if(intensive || (total_pick_counter_ > 50)) Collections.shuffle(ofs);
search_offsets_.addAll(ofs);
}
if(intensive) {
ArrayList<Vec3i> ofs = new ArrayList<Vec3i>(Arrays.asList(new Vec3i(-1, 1, 0), new Vec3i( 1, 1, 0), new Vec3i( 0, 1,-1), new Vec3i( 0, 1, 1)));
Collections.shuffle(ofs);
search_offsets_.addAll(ofs);
}
}
private boolean try_collect(final BlockPos collection_pos)
{
IFluidState collection_fluidstate = get_fluidstate(collection_pos);
if(collection_fluidstate.isEmpty()) return false;
Fluid fluid_to_collect = collection_fluidstate.getFluid();
if((!tank_.isEmpty()) && (!tank_.getFluid().isEquivalentTo(fluid_to_collect))) return false;
if(try_pick(collection_pos, collection_fluidstate)) { last_pick_pos_ = collection_pos; return true; } // Blocks directly always first. Allows water source blocks to recover/reflow to source blocks.
if((last_pick_pos_==null) || (last_pick_pos_.distanceSq(collection_pos) > MAX_TRACK_RADIUS_SQ)) { last_pick_pos_ = collection_pos; search_offsets_ = null; }
BlockPos pos = last_pick_pos_;
HashSet<BlockPos> checked = new HashSet<>();
Stack<BlockPos> trail = new Stack<BlockPos>();
trail.add(pos);
checked.add(pos);
int steps=0;
boolean intensive = (no_fluid_found_counter_ >= INTENSIVE_SEARCH_TRIGGER_THRESHOLD);
if(intensive) { no_fluid_found_counter_ = 0; ++intensive_search_counter_; }
if(search_offsets_ == null) rebuild_search_offsets(intensive);
int max = intensive ? MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE : MAX_TRACKING_STEPS_PER_CYCLE;
while(++steps <= max) {
int num_adjacent = 0;
for(int i=0; i<search_offsets_.size(); ++i) {
BlockPos p = pos.add(search_offsets_.get(i));
if(checked.contains(p)) continue;
checked.add(p);
++steps;
IFluidState fluidstate = get_fluidstate(p);
if(fluidstate.getFluid().isEquivalentTo(fluid_to_collect)) {
++num_adjacent;
pos = p;
trail.push(pos);
if(steps < MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE/2) {
// check for same fluid above (only source blocks)
final int max_surface_search = (MAX_TRACKING_STEPS_PER_CYCLE_INTENSIVE/2)-steps;
for(int k=0; k<max_surface_search; ++k) {
IFluidState fs = get_fluidstate(pos.up());
if(!can_pick(pos.up(), fs)) break;
fluidstate = fs;
pos = pos.up();
trail.push(pos);
}
}
if(try_pick(pos, fluidstate)) {
last_pick_pos_ = pos;
no_fluid_found_counter_ = 0;
search_offsets_ = null;
// probability reset, so it's not turteling too far away, mainly for large nether lava seas, not desert lakes.
if((++total_pick_counter_ > 50) && world.rand.nextInt(10)==0) last_pick_pos_ = collection_pos;
//println("PASS " + steps + " - " + (pos.subtract(collection_pos)));
return true;
}
}
}
if(trail.isEmpty()) break; // reset search
if(num_adjacent==0) pos = trail.pop();
}
//println("FAIL=" + steps + " - " + (pos.subtract(collection_pos)));
//String s = new String(); for(BlockPos p:checked) s += "\n" + p; println(s);
if(intensive_search_counter_ > 2) world.removeBlock(pos, false);
last_pick_pos_ = collection_pos;
search_offsets_ = null; // try other search order
++no_fluid_found_counter_;
return false;
}
public void tick()
{
if((world.isRemote) || (--tick_timer_ > 0)) return;
tick_timer_ = TICK_INTERVAL;
collection_timer_ += TICK_INTERVAL;
boolean dirty = false;
// Collection
if((collection_timer_ >= COLLECTION_INTERVAL) && ((tank_==null) || (tank_.getAmount() <= (TANK_CAPACITY-1000)))) {
collection_timer_ = 0;
if(!world.isBlockPowered(pos)) { // redstone disable feature
if(last_pick_pos_==null) last_pick_pos_ = pos.up();
if(try_collect(pos.up())) dirty = true;
}
}
// Gravity fluid transfer
if((tank_.getAmount() >= 1000)) {
IFluidHandler fh = FluidUtil.getFluidHandler(world, pos.down(), Direction.UP).orElse(null);
if(fh != null) {
FluidStack fs = new FluidStack(tank_.getFluid(), 1000);
int nfilled = MathHelper.clamp(fh.fill(fs, FluidAction.EXECUTE), 0, 1000);
tank_.shrink(nfilled);
dirty = true;
}
}
// Block state
int fill_level = (tank_==null) ? 0 : (MathHelper.clamp(tank_.getAmount()/1000,0,FILL_LEVEL_MAX));
final BlockState funnel_state = world.getBlockState(pos);
if(funnel_state.get(FILL_LEVEL) != fill_level) world.setBlockState(pos, funnel_state.with(FILL_LEVEL, fill_level), 2|16);
if(dirty) markDirty();
}
}
}

View file

@ -0,0 +1,997 @@
/*
* @file BlockFurnace.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* ED Lab furnace.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.ExtItems;
import wile.engineersdecor.detail.Networking;
import net.minecraft.tileentity.*;
import net.minecraft.inventory.container.*;
import net.minecraft.item.crafting.AbstractCookingRecipe;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraft.block.RedstoneTorchBlock;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.item.ExperienceOrbEntity;
import net.minecraft.item.crafting.FurnaceRecipe;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.stats.Stats;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.world.IBlockReader;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.util.SoundEvents;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.world.World;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.item.Items;
import net.minecraft.item.*;
import net.minecraft.inventory.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.*;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.fml.hooks.BasicEventHooks;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.SidedInvWrapper;
import com.mojang.blaze3d.systems.RenderSystem;
import javax.annotation.Nullable;
import java.util.*;
public class BlockDecorFurnace extends BlockDecorDirected
{
public static final BooleanProperty LIT = RedstoneTorchBlock.LIT;
public BlockDecorFurnace(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{
super(config, builder, unrotatedAABB);
setDefaultState(stateContainer.getBaseState().with(FACING, Direction.NORTH).with(LIT, false));
}
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(LIT); }
@Override
@SuppressWarnings("deprecation")
public int getLightValue(BlockState state)
{ return state.get(LIT) ? super.getLightValue(state) : 0; }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(FACING, context.getPlacementHorizontalFacing().getOpposite()).with(LIT, false); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos)
{ return Container.calcRedstone(world.getTileEntity(pos)); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorFurnace.BTileEntity(); }
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
world.setBlockState(pos, state.with(LIT, false));
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("inventory"))) return;
CompoundNBT inventory_nbt = stack.getTag().getCompound("inventory");
if(inventory_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorFurnace.BTileEntity)) return;
final BlockDecorFurnace.BTileEntity bte = ((BlockDecorFurnace.BTileEntity)te);
bte.readnbt(inventory_nbt);
bte.markDirty();
world.setBlockState(pos, state.with(LIT, bte.burning()));
}
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion) {
final List<ItemStack> stacks = new ArrayList<ItemStack>();
if(world.isRemote) return stacks;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return stacks;
if(!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundNBT inventory_nbt = ((BTileEntity)te).reset_getnbt();
if(!inventory_nbt.isEmpty()) {
CompoundNBT nbt = new CompoundNBT();
nbt.put("inventory", inventory_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
for(ItemStack stack: ((BTileEntity)te).stacks_) stacks.add(stack);
((BTileEntity)te).reset();
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorFurnace.BTileEntity)) return true;
if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return true;
NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te);
player.addStat(Stats.INTERACT_WITH_FURNACE);
return true;
}
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)
{
if((state.getBlock()!=this) || (!state.get(LIT))) return;
final double rv = rnd.nextDouble();
if(rv > 0.5) return;
final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ();
final double xc=0.52, xr=rnd.nextDouble()*0.4-0.2, yr=(y-0.3+rnd.nextDouble()*0.2);
if(rv < 0.1d) world.playSound(x, y, z, SoundEvents.BLOCK_FURNACE_FIRE_CRACKLE, SoundCategory.BLOCKS, 0.4f, 0.5f, false);
switch(state.get(FACING)) {
case WEST: world.addParticle(ParticleTypes.SMOKE, x-xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case EAST: world.addParticle(ParticleTypes.SMOKE, x+xc, yr, z+xr, 0.0, 0.0, 0.0); break;
case NORTH: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z-xc, 0.0, 0.0, 0.0); break;
default: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z+xc, 0.0, 0.0, 0.0); break;
}
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory, IEnergyStorage
{
public static final IRecipeType<FurnaceRecipe> RECIPE_TYPE = IRecipeType.SMELTING;
public static final int NUM_OF_FIELDS = 5;
public static final int TICK_INTERVAL = 4;
public static final int FIFO_INTERVAL = 20;
public static final int STD_SMELTING_TIME = 200;
public static final int MAX_BURNTIME = 0x7fff;
public static final int DEFAULT_BOOST_ENERGY = 32;
public static final int NUM_OF_SLOTS = 11;
public static final int SMELTING_INPUT_SLOT_NO = 0;
public static final int SMELTING_FUEL_SLOT_NO = 1;
public static final int SMELTING_OUTPUT_SLOT_NO = 2;
public static final int FIFO_INPUT_0_SLOT_NO = 3;
public static final int FIFO_INPUT_1_SLOT_NO = 4;
public static final int FIFO_FUEL_0_SLOT_NO = 5;
public static final int FIFO_FUEL_1_SLOT_NO = 6;
public static final int FIFO_OUTPUT_0_SLOT_NO = 7;
public static final int FIFO_OUTPUT_1_SLOT_NO = 8;
public static final int AUX_0_SLOT_NO = 9;
public static final int AUX_1_SLOT_NO =10;
// Config ----------------------------------------------------------------------------------
private static double proc_fuel_efficiency_ = 1.0;
private static double proc_speed_ = 1.2;
private static int boost_energy_consumption = DEFAULT_BOOST_ENERGY * TICK_INTERVAL;
public static void on_config(int speed_percent, int fuel_efficiency_percent, int boost_energy_per_tick)
{
proc_speed_ = ((double)MathHelper.clamp(speed_percent, 10, 500)) / 100;
proc_fuel_efficiency_ = ((double) MathHelper.clamp(fuel_efficiency_percent, 10, 500)) / 100;
boost_energy_consumption = TICK_INTERVAL * MathHelper.clamp(boost_energy_per_tick, 16, 512);
ModEngineersDecor.logger().info("Config lab furnace speed:" + (proc_speed_*100) + "%, efficiency:" + (proc_fuel_efficiency_*100) + "%");
}
// BTileEntity -----------------------------------------------------------------------------
private int tick_timer_;
private int fifo_timer_;
private int burntime_left_;
private int fuel_burntime_;
private double proc_time_elapsed_;
private int proc_time_needed_;
private int field_is_burning_;
private int field_proc_time_elapsed_;
private int boost_energy_; // small, not saved in nbt.
private boolean heater_inserted_ = false;
protected NonNullList<ItemStack> stacks_;
protected @Nullable IRecipe current_recipe_ = null;
private final List<String> recent_recipes_ = new ArrayList<>();
public BTileEntity()
{ this(ModContent.TET_SMALL_LAB_FURNACE); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); reset(); }
public CompoundNBT reset_getnbt()
{
CompoundNBT nbt = new CompoundNBT();
writenbt(nbt);
reset();
return nbt;
}
public void reset()
{
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
proc_time_elapsed_ = 0;
proc_time_needed_ = 0;
burntime_left_ = 0;
fuel_burntime_ = 0;
fifo_timer_ = 0;
tick_timer_ = 0;
current_recipe_ = null;
}
public void readnbt(CompoundNBT nbt)
{
ItemStackHelper.loadAllItems(nbt, stacks_);
while(stacks_.size() < NUM_OF_SLOTS) stacks_.add(ItemStack.EMPTY);
burntime_left_ = nbt.getInt("BurnTime");
proc_time_elapsed_ = nbt.getInt("CookTime");
proc_time_needed_ = nbt.getInt("CookTimeTotal");
fuel_burntime_ = nbt.getInt("FuelBurnTime");
CompoundNBT rr = nbt.getCompound("Recipes");
for(int i=0; i<rr.size(); ++i) {
String recipe_id = rr.getString(Integer.toString(i));
if(recipe_id.isEmpty()) break; // no further processing, nbt data set broken.
recent_recipes_.add(recipe_id);
}
}
private void writenbt(CompoundNBT nbt)
{
nbt.putInt("BurnTime", MathHelper.clamp(burntime_left_,0 , MAX_BURNTIME));
nbt.putInt("CookTime", MathHelper.clamp((int)proc_time_elapsed_, 0, MAX_BURNTIME));
nbt.putInt("CookTimeTotal", MathHelper.clamp(proc_time_needed_, 0, MAX_BURNTIME));
nbt.putInt("FuelBurnTime", MathHelper.clamp(fuel_burntime_, 0, MAX_BURNTIME));
ItemStackHelper.saveAllItems(nbt, stacks_);
CompoundNBT rr = new CompoundNBT();
for(int i=0; i<recent_recipes_.size(); ++i) rr.putString(Integer.toString(i), recent_recipes_.get(i));
nbt.put("Recipes", rr);
}
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt); return nbt; }
// INamedContainerProvider / INameable ------------------------------------------------------
@Override
public ITextComponent getName()
{ final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Lab furnace"); }
@Override
public boolean hasCustomName()
{ return false; }
@Override
public ITextComponent getCustomName()
{ return getName(); }
// IContainerProvider ----------------------------------------------------------------------
@Override
public ITextComponent getDisplayName()
{ return INameable.super.getDisplayName(); }
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new BlockDecorFurnace.BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); }
// IInventory ------------------------------------------------------------------------------
@Override
public int getSizeInventory()
{ return stacks_.size(); }
@Override
public boolean isEmpty()
{ for(ItemStack stack: stacks_) { if(!stack.isEmpty()) return false; } return true; }
@Override
public ItemStack getStackInSlot(int index)
{ return (index < getSizeInventory()) ? stacks_.get(index) : ItemStack.EMPTY; }
@Override
public ItemStack decrStackSize(int index, int count)
{ return ItemStackHelper.getAndSplit(stacks_, index, count); }
@Override
public ItemStack removeStackFromSlot(int index)
{ return ItemStackHelper.getAndRemove(stacks_, index); }
@Override
public void setInventorySlotContents(int index, ItemStack stack)
{
ItemStack slot_stack = stacks_.get(index);
boolean already_in_slot = (!stack.isEmpty()) && (stack.isItemEqual(slot_stack)) && (ItemStack.areItemStackTagsEqual(stack, slot_stack));
stacks_.set(index, stack);
if(stack.getCount() > getInventoryStackLimit()) stack.setCount(getInventoryStackLimit());
if((index == SMELTING_INPUT_SLOT_NO) && (!already_in_slot)) {
proc_time_needed_ = getSmeltingTimeNeeded(world, stack);
proc_time_elapsed_ = 0;
markDirty();
}
}
@Override
public int getInventoryStackLimit()
{ return 64; }
@Override
public void markDirty()
{ super.markDirty(); }
@Override
public boolean isUsableByPlayer(PlayerEntity player)
{ return getPos().distanceSq(player.getPosition()) < 36; }
@Override
public void openInventory(PlayerEntity player)
{}
@Override
public void closeInventory(PlayerEntity player)
{ markDirty(); }
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{
switch(index) {
case SMELTING_OUTPUT_SLOT_NO:
case FIFO_OUTPUT_0_SLOT_NO:
case FIFO_OUTPUT_1_SLOT_NO:
return false;
case SMELTING_INPUT_SLOT_NO:
case FIFO_INPUT_0_SLOT_NO:
case FIFO_INPUT_1_SLOT_NO:
return true;
case AUX_0_SLOT_NO:
case AUX_1_SLOT_NO:
return true;
default: {
ItemStack slot_stack = stacks_.get(FIFO_FUEL_1_SLOT_NO);
return isFuel(world, stack) || FurnaceFuelSlot.isBucket(stack) && (slot_stack.getItem() != Items.BUCKET);
}
}
}
@Override
public void clear()
{ stacks_.clear(); }
// Fields -----------------------------------------------------------------------------------------------
protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS)
{
@Override
public int get(int id)
{
switch(id) {
case 0: return BTileEntity.this.burntime_left_;
case 1: return BTileEntity.this.fuel_burntime_;
case 2: return (int)BTileEntity.this.field_proc_time_elapsed_;
case 3: return BTileEntity.this.proc_time_needed_;
case 4: return BTileEntity.this.field_is_burning_;
default: return 0;
}
}
@Override
public void set(int id, int value)
{
switch(id) {
case 0: BTileEntity.this.burntime_left_ = value; break;
case 1: BTileEntity.this.fuel_burntime_ = value; break;
case 2: BTileEntity.this.field_proc_time_elapsed_ = value; break;
case 3: BTileEntity.this.proc_time_needed_ = value; break;
case 4: BTileEntity.this.field_is_burning_ = value;
}
}
};
// ISidedInventory ----------------------------------------------------------------------------
private static final int[] SLOTS_TOP = new int[] {FIFO_INPUT_1_SLOT_NO};
private static final int[] SLOTS_BOTTOM = new int[] {FIFO_OUTPUT_1_SLOT_NO};
private static final int[] SLOTS_SIDES = new int[] {FIFO_FUEL_1_SLOT_NO};
@Override
public int[] getSlotsForFace(Direction side)
{
if(side == Direction.DOWN) return SLOTS_BOTTOM;
if(side == Direction.UP) return SLOTS_TOP;
return SLOTS_SIDES;
}
@Override
public boolean canInsertItem(int index, ItemStack itemStackIn, Direction direction)
{ return isItemValidForSlot(index, itemStackIn); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{
if((direction!=Direction.DOWN) || ((index!=SMELTING_FUEL_SLOT_NO) && (index!=FIFO_FUEL_0_SLOT_NO) && (index!=FIFO_FUEL_1_SLOT_NO) )) return true;
return (stack.getItem()==Items.BUCKET);
}
// IEnergyStorage ----------------------------------------------------------------------------
@Override
public boolean canExtract()
{ return false; }
@Override
public boolean canReceive()
{ return true; }
@Override
public int getMaxEnergyStored()
{ return boost_energy_consumption; }
@Override
public int getEnergyStored()
{ return boost_energy_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{ // only speedup support, no buffering, not in nbt -> no markdirty
if((boost_energy_ >= boost_energy_consumption) || (maxReceive < boost_energy_consumption)) return 0;
if(!simulate) boost_energy_ = boost_energy_consumption;
return boost_energy_consumption;
}
// Capability export ----------------------------------------------------------------------------
LazyOptional<? extends IItemHandler>[] item_handlers = SidedInvWrapper.create(this, Direction.UP, Direction.DOWN, Direction.NORTH);
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
if(facing == Direction.UP) return item_handlers[0].cast();
if(facing == Direction.DOWN) return item_handlers[1].cast();
return item_handlers[2].cast();
} else if(capability== CapabilityEnergy.ENERGY) {
return energy_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// ITickableTileEntity -------------------------------------------------------------------------
@Override
public void tick()
{
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
final boolean was_burning = burning();
if(was_burning) burntime_left_ -= TICK_INTERVAL;
if(burntime_left_ < 0) burntime_left_ = 0;
if(world.isRemote) return;
boolean dirty = false;
if(--fifo_timer_ <= 0) {
fifo_timer_ = FIFO_INTERVAL/TICK_INTERVAL;
// note, intentionally not using bitwise OR piping.
if(transferItems(FIFO_OUTPUT_0_SLOT_NO, FIFO_OUTPUT_1_SLOT_NO, 1)) dirty = true;
if(transferItems(SMELTING_OUTPUT_SLOT_NO, FIFO_OUTPUT_0_SLOT_NO, 1)) dirty = true;
if(transferItems(FIFO_FUEL_0_SLOT_NO, SMELTING_FUEL_SLOT_NO, 1)) dirty = true;
if(transferItems(FIFO_FUEL_1_SLOT_NO, FIFO_FUEL_0_SLOT_NO, 1)) dirty = true;
if(transferItems(FIFO_INPUT_0_SLOT_NO, SMELTING_INPUT_SLOT_NO, 1)) dirty = true;
if(transferItems(FIFO_INPUT_1_SLOT_NO, FIFO_INPUT_0_SLOT_NO, 1)) dirty = true;
heater_inserted_ = (ExtItems.IE_EXTERNAL_HEATER==null) // without IE always allow electrical boost
|| (stacks_.get(AUX_0_SLOT_NO).getItem()==ExtItems.IE_EXTERNAL_HEATER)
|| (stacks_.get(AUX_1_SLOT_NO).getItem()==ExtItems.IE_EXTERNAL_HEATER);
if(!burning()) cleanupRecentRecipes();
}
ItemStack fuel = stacks_.get(SMELTING_FUEL_SLOT_NO);
if(burning() || (!fuel.isEmpty()) && (!(stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty())) {
IRecipe last_recipe = currentRecipe();
updateCurrentRecipe();
if(currentRecipe() != last_recipe) {
proc_time_elapsed_ = 0;
proc_time_needed_ = getSmeltingTimeNeeded(world, stacks_.get(SMELTING_INPUT_SLOT_NO));
}
if(!burning() && canSmeltCurrentItem()) {
burntime_left_ = (int)MathHelper.clamp((proc_fuel_efficiency_ * getFuelBurntime(world, fuel)), 0, MAX_BURNTIME);
fuel_burntime_ = (int)MathHelper.clamp(((double)burntime_left_)/((proc_speed_ > 0) ? proc_speed_ : 1), 1, MAX_BURNTIME);
if(burning()) {
dirty = true;
if(!fuel.isEmpty()) {
Item fuel_item = fuel.getItem();
fuel.shrink(1);
if(fuel.isEmpty()) stacks_.set(SMELTING_FUEL_SLOT_NO, fuel_item.getContainerItem(fuel));
}
}
}
if(burning() && canSmeltCurrentItem()) {
proc_time_elapsed_ += TICK_INTERVAL * proc_speed_;
if(heater_inserted_ && (boost_energy_ >= boost_energy_consumption)) { boost_energy_ = 0; proc_time_elapsed_ += TICK_INTERVAL; }
if(proc_time_elapsed_ >= proc_time_needed_) {
proc_time_elapsed_ = 0;
proc_time_needed_ = getSmeltingTimeNeeded(world, stacks_.get(SMELTING_INPUT_SLOT_NO));
smeltCurrentItem();
dirty = true;
}
} else {
proc_time_elapsed_ = 0;
}
} else if((!burning()) && (proc_time_elapsed_ > 0)) {
proc_time_elapsed_ = MathHelper.clamp(proc_time_elapsed_-2, 0, proc_time_needed_);
}
if(was_burning != burning()) {
dirty = true;
final BlockState state = world.getBlockState(pos);
if(state.getBlock() instanceof BlockDecorFurnace) {
world.setBlockState(pos, state.with(LIT, burning()));
}
}
if(dirty) {
markDirty();
}
field_is_burning_ = this.burning() ? 1 : 0;
field_proc_time_elapsed_ = (int)proc_time_elapsed_;
}
// Furnace -------------------------------------------------------------------------------------
@Nullable
public static final <T extends AbstractCookingRecipe> T getSmeltingResult(IRecipeType<T> recipe_type, World world, ItemStack stack)
{
if(stack.isEmpty()) return null;
Inventory inventory = new Inventory(3);
inventory.setInventorySlotContents(0, stack);
return world.getRecipeManager().getRecipe(recipe_type, inventory, world).orElse(null);
}
@Nullable
protected IRecipe currentRecipe()
{ return current_recipe_; }
public boolean burning()
{ return burntime_left_ > 0; }
public int getSmeltingTimeNeeded(World world, ItemStack stack)
{
if(stack.isEmpty()) return 0;
AbstractCookingRecipe recipe = getSmeltingResult(RECIPE_TYPE, world, stack);
if(recipe == null) return 0;
int t = recipe.getCookTime();
return (t<=0) ? STD_SMELTING_TIME : t;
}
private boolean transferItems(final int index_from, final int index_to, int count)
{
ItemStack from = stacks_.get(index_from);
if(from.isEmpty()) return false;
ItemStack to = stacks_.get(index_to);
if(from.getCount() < count) count = from.getCount();
if(count <= 0) return false;
boolean changed = true;
if(to.isEmpty()) {
stacks_.set(index_to, from.split(count));
} else if(to.getCount() >= to.getMaxStackSize()) {
changed = false;
} else if((!from.isItemEqual(to)) || (!ItemStack.areItemStackTagsEqual(from, to))) {
changed = false;
} else {
if((to.getCount()+count) >= to.getMaxStackSize()) {
from.shrink(to.getMaxStackSize()-to.getCount());
to.setCount(to.getMaxStackSize());
} else {
from.shrink(count);
to.grow(count);
}
}
if(from.isEmpty() && from!=ItemStack.EMPTY) {
stacks_.set(index_from, ItemStack.EMPTY);
changed = true;
}
return changed;
}
protected boolean canSmeltCurrentItem()
{
if((currentRecipe()==null) || (stacks_.get(SMELTING_INPUT_SLOT_NO).isEmpty())) return false;
final ItemStack recipe_result_items = getSmeltingResult(stacks_.get(SMELTING_INPUT_SLOT_NO));
if(recipe_result_items.isEmpty()) return false;
final ItemStack result_stack = stacks_.get(SMELTING_OUTPUT_SLOT_NO);
if(result_stack.isEmpty()) return true;
if(!result_stack.isItemEqual(recipe_result_items)) return false;
if(result_stack.getCount() + recipe_result_items.getCount() <= getInventoryStackLimit() && result_stack.getCount() + recipe_result_items.getCount() <= result_stack.getMaxStackSize()) return true;
return result_stack.getCount() + recipe_result_items.getCount() <= recipe_result_items.getMaxStackSize();
}
protected void smeltCurrentItem()
{
if(!canSmeltCurrentItem()) return;
final ItemStack smelting_input_stack = stacks_.get(SMELTING_INPUT_SLOT_NO);
final ItemStack recipe_result_items = getSmeltingResult(smelting_input_stack);
final ItemStack smelting_output_stack = stacks_.get(SMELTING_OUTPUT_SLOT_NO);
final ItemStack fuel_stack = stacks_.get(SMELTING_FUEL_SLOT_NO);
if(smelting_output_stack.isEmpty()) {
stacks_.set(SMELTING_OUTPUT_SLOT_NO, recipe_result_items.copy());
} else if(smelting_output_stack.getItem() == recipe_result_items.getItem()) {
smelting_output_stack.grow(recipe_result_items.getCount());
}
smelting_input_stack.shrink(1);
}
public static int getFuelBurntime(World world, ItemStack stack)
{
if(stack.isEmpty()) return 0;
int t = ForgeHooks.getBurnTime(stack);
return (t<0) ? 0 : t;
}
public static boolean isFuel(World world, ItemStack stack)
{ return getFuelBurntime(world, stack) > 0; }
public float getSmeltingExperience(ItemStack stack)
{
// This method is not often needed, so the time managing dealing with the recent
// recipes is mainly invested here.
float xp = stack.getItem().getSmeltingExperience(stack);
if(xp >= 0) return xp;
for(int i=0; i<recent_recipes_.size(); ++i) {
IRecipe r = world.getRecipeManager().getRecipe(new ResourceLocation(recent_recipes_.get(i))).orElse(null);
if((!(r instanceof AbstractCookingRecipe))) continue; // recipe not available (e.g. at the moment).
if(!(stack.isItemEqual(r.getRecipeOutput()))) continue;
xp = ((AbstractCookingRecipe)r).getExperience();
}
return (xp <= 0) ? 0 : xp;
}
public ItemStack getSmeltingResult(final ItemStack stack)
{ return (currentRecipe()==null) ? (ItemStack.EMPTY) : (currentRecipe().getRecipeOutput()); }
public static boolean canSmelt(World world, final ItemStack stack)
{ return getSmeltingResult(RECIPE_TYPE, world, stack) != null; }
protected void updateCurrentRecipe()
{ setCurrentRecipe(getSmeltingResult(RECIPE_TYPE, world, stacks_.get(SMELTING_INPUT_SLOT_NO))); }
protected void setCurrentRecipe(IRecipe<?> recipe)
{
if(recipe == null) { current_recipe_ = null; return; }
current_recipe_ = recipe;
String recipe_id = recipe.getId().toString();
if(!recent_recipes_.contains(recipe_id)) recent_recipes_.add(recipe_id);
}
private void cleanupRecentRecipes()
{
if(recent_recipes_.isEmpty()) return;
if(!stacks_.get(SMELTING_INPUT_SLOT_NO).isEmpty()) return;
if(!stacks_.get(SMELTING_OUTPUT_SLOT_NO).isEmpty()) return;
if(!stacks_.get(FIFO_OUTPUT_0_SLOT_NO).isEmpty()) return;
if(!stacks_.get(FIFO_OUTPUT_1_SLOT_NO).isEmpty()) return;
recent_recipes_.clear();
}
}
//--------------------------------------------------------------------------------------------------------------------
// container slots
//--------------------------------------------------------------------------------------------------------------------
public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer
{
// Slots --------------------------------------------------------------------------------------------
public static class BSlotInpFifo extends Slot
{
public BSlotInpFifo(IInventory inv, int index, int xpos, int ypos)
{ super(inv, index, xpos, ypos); }
}
public static class BSlotFuelFifo extends Slot
{
public BSlotFuelFifo(IInventory inv, int index, int xpos, int ypos)
{ super(inv, index, xpos, ypos); }
}
public static class BSlotOutFifo extends BSlotResult
{
public BSlotOutFifo(PlayerEntity player, IInventory inventory, int index, int xpos, int ypos)
{ super(player, inventory, index, xpos, ypos); }
}
public static class BSlotResult extends Slot
{
private final IInventory inventory_;
private final PlayerEntity player_;
private int removeCount = 0;
public BSlotResult(PlayerEntity player, IInventory inventory, int index, int xpos, int ypos)
{ super(inventory, index, xpos, ypos); inventory_ = inventory; player_ = player; }
@Override
public boolean isItemValid(ItemStack stack)
{ return false; }
@Override
public ItemStack decrStackSize(int amount)
{ removeCount += getHasStack() ? Math.min(amount, getStack().getCount()) : 0; return super.decrStackSize(amount); }
@Override
public ItemStack onTake(PlayerEntity thePlayer, ItemStack stack)
{ onCrafting(stack); super.onTake(thePlayer, stack); return stack; }
@Override
protected void onCrafting(ItemStack stack, int amount)
{ removeCount += amount; onCrafting(stack); }
@Override
protected void onCrafting(ItemStack stack)
{
stack.onCrafting(player_.world, player_, removeCount);
if((!player_.world.isRemote) && (inventory_ instanceof BTileEntity)) {
BTileEntity te = (BTileEntity)inventory_;
int xp = removeCount;
float sxp = te.getSmeltingExperience(stack);
if(sxp == 0) {
xp = 0;
} else if(sxp < 1.0) {
xp = (int)((sxp*xp) + Math.round(Math.random()+0.75));
}
while(xp > 0) {
int k = ExperienceOrbEntity.getXPSplit(xp);
xp -= k;
player_.world.addEntity((new ExperienceOrbEntity(player_.world, player_.getPosition().getX(), player_.getPosition().getY()+0.5, player_.getPosition().getZ()+0.5, k)));
}
}
removeCount = 0;
BasicEventHooks.firePlayerSmeltedEvent(player_, stack);
}
}
public static class BFuelSlot extends Slot
{
private final BContainer container_;
public BFuelSlot(IInventory inventory, int index, int xpos, int ypos, BContainer container)
{ super(inventory, index, xpos, ypos); container_=container; }
@Override
public boolean isItemValid(ItemStack stack)
{ return isBucket(stack) || (BTileEntity.isFuel(container_.world(), stack)); }
@Override
public int getItemStackLimit(ItemStack stack)
{ return isBucket(stack) ? 1 : super.getItemStackLimit(stack); }
protected static boolean isBucket(ItemStack stack)
{ return (stack.getItem()==Items.BUCKET); }
}
// Container ----------------------------------------------------------------------------------------
private static final int PLAYER_INV_START_SLOTNO = 11;
protected final PlayerEntity player_;
protected final IInventory inventory_;
protected final IWorldPosCallable wpc_;
private final IIntArray fields_;
private final IRecipeType<? extends AbstractCookingRecipe> recipe_type_;
public int field(int index) { return fields_.get(index); }
public PlayerEntity player() { return player_ ; }
public IInventory inventory() { return inventory_ ; }
public World world() { return player_.world; }
public BContainer(int cid, PlayerInventory player_inventory)
{ this(cid, player_inventory, new Inventory(BTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(BTileEntity.NUM_OF_FIELDS)); }
private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields)
{
super(ModContent.CT_SMALL_LAB_FURNACE, cid);
player_ = player_inventory.player;
inventory_ = block_inventory;
wpc_ = wpc;
fields_ = fields;
recipe_type_ = BTileEntity.RECIPE_TYPE;
addSlot(new Slot(inventory_, 0, 59, 17)); // smelting input
addSlot(new BFuelSlot(inventory_, 1, 59, 53, this)); // fuel
addSlot(new BSlotResult(player_, inventory_, 2, 101, 35)); // smelting result
addSlot(new BSlotInpFifo(inventory_, 3, 34, 17)); // input fifo 0
addSlot(new BSlotInpFifo(inventory_, 4, 16, 17)); // input fifo 1
addSlot(new BSlotFuelFifo(inventory_, 5, 34, 53)); // fuel fifo 0
addSlot(new BSlotFuelFifo(inventory_, 6, 16, 53)); // fuel fifo 1
addSlot(new BSlotOutFifo(player_inventory.player, inventory_, 7, 126, 35)); // out fifo 0
addSlot(new BSlotOutFifo(player_inventory.player, inventory_, 8, 144, 35)); // out fifo 1
addSlot(new Slot(inventory_, 9, 126, 61)); // aux slot 1
addSlot(new Slot(inventory_, 10, 144, 61)); // aux slot 2
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 8+x*18, 144)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 86+y*18)); // player slots: 9..35
}
}
this.trackIntArray(fields_); // === Add reference holders
}
@Override
public boolean canInteractWith(PlayerEntity player)
{ return inventory_.isUsableByPlayer(player); }
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int index)
{
Slot slot = getSlot(index);
if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getStack();
ItemStack transferred = slot_stack.copy();
if((index==2) || (index==7) || (index==8)) {
// Output slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, true)) return ItemStack.EMPTY;
slot.onSlotChange(slot_stack, transferred);
} else if((index==0) || (index==3) || (index==4)) {
// Input slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index==1) || (index==5) || (index==6)) {
// Fuel slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index==9) || (index==10)) {
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
// Player inventory
if(BTileEntity.canSmelt(world(), slot_stack)) {
if(
(!mergeItemStack(slot_stack, 0, 1, false)) && // smelting input
(!mergeItemStack(slot_stack, 3, 4, false)) && // fifo0
(!mergeItemStack(slot_stack, 4, 5, false)) // fifo1
) return ItemStack.EMPTY;
} else if(BTileEntity.isFuel(player_.world, slot_stack)) {
if(
(!mergeItemStack(slot_stack, 1, 2, false)) && // fuel input
(!mergeItemStack(slot_stack, 5, 6, false)) && // fuel fifo0
(!mergeItemStack(slot_stack, 6, 7, false)) // fuel fifo1
) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index < PLAYER_INV_START_SLOTNO+27)) {
// player inventory --> player hotbar
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO+27, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO+27) && (index < PLAYER_INV_START_SLOTNO+36) && (!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+27, false))) {
// player hotbar --> player inventory
return ItemStack.EMPTY;
}
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
//if(!player.world.isRemote) detectAndSendChanges();
return transferred;
}
// INetworkSynchronisableContainer ---------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public void onGuiAction(CompoundNBT nbt)
{ Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); }
@OnlyIn(Dist.CLIENT)
public void onGuiAction(String key, int value)
{
CompoundNBT nbt = new CompoundNBT();
nbt.putInt(key, value);
Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt);
}
@Override
public void onServerPacketReceived(int windowId, CompoundNBT nbt)
{}
@Override
public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt)
{}
}
//--------------------------------------------------------------------------------------------------------------------
// GUI
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class BGui extends ContainerScreen<BContainer>
{
protected final PlayerEntity player_;
public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title)
{ super(container, player_inventory, title); this.player_ = player_inventory.player; }
@Override
public void init()
{ super.init(); }
@Override
public void render(int mouseX, int mouseY, float partialTicks)
{
renderBackground();
super.render(mouseX, mouseY, partialTicks);
renderHoveredToolTip(mouseX, mouseY);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
{
RenderSystem.enableBlend();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
this.minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/small_lab_furnace_gui.png"));
final int x0=guiLeft, y0=this.guiTop, w=xSize, h=ySize;
blit(x0, y0, 0, 0, w, h);
if(getContainer().field(4) != 0) {
final int k = flame_px(13);
blit(x0+59, y0+36+12-k, 176, 12-k, 14, k+1);
}
blit(x0+79, y0+36, 176, 15, 1+progress_px(17), 15);
RenderSystem.disableBlend();
}
private int progress_px(int pixels)
{ final int tc=getContainer().field(2), T=getContainer().field(3); return ((T>0) && (tc>0)) ? (tc * pixels / T) : (0); }
private int flame_px(int pixels)
{ int ibt = getContainer().field(1); return ((getContainer().field(0) * pixels) / ((ibt>0) ? (ibt) : (BTileEntity.STD_SMELTING_TIME))); }
}
}

View file

@ -0,0 +1,779 @@
/*
* @file BlockDecorFurnaceElectrical.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* ED small electrical pass-through furnace.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.Networking;
import net.minecraft.inventory.container.*;
import net.minecraft.item.crafting.AbstractCookingRecipe;
import net.minecraft.item.crafting.FurnaceRecipe;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.block.Block;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.IBlockReader;
import net.minecraft.block.BlockState;
import net.minecraft.world.World;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.LivingEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.item.Items;
import net.minecraft.item.*;
import net.minecraft.inventory.*;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.*;
import net.minecraft.stats.Stats;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import com.mojang.blaze3d.systems.RenderSystem;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Random;
public class BlockDecorFurnaceElectrical extends BlockDecorFurnace
{
public BlockDecorFurnaceElectrical(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorFurnaceElectrical.BTileEntity(); }
@Override
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorFurnaceElectrical.BTileEntity)) return true;
if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return true;
NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te);
player.addStat(Stats.INTERACT_WITH_FURNACE);
return true;
}
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
world.setBlockState(pos, state.with(LIT, false));
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("inventory"))) return;
CompoundNBT inventory_nbt = stack.getTag().getCompound("inventory");
if(inventory_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BlockDecorFurnaceElectrical.BTileEntity)) return;
BTileEntity bte = (BlockDecorFurnaceElectrical.BTileEntity)te;
bte.readnbt(inventory_nbt);
bte.markDirty();
world.setBlockState(pos, state.with(LIT, bte.burning()));
}
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)
{}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends BlockDecorFurnace.BTileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory, IEnergyStorage
{
public static final IRecipeType<FurnaceRecipe> RECIPE_TYPE = IRecipeType.SMELTING;
public static final int NUM_OF_FIELDS = 7;
public static final int TICK_INTERVAL = 4;
public static final int FIFO_INTERVAL = 20;
public static final int HEAT_CAPACITY = 200;
public static final int HEAT_INCREMENT = 20;
public static final int MAX_ENERGY_TRANSFER = 256;
public static final int MAX_ENERGY_BUFFER = 32000;
public static final int MAX_SPEED_SETTING = 2;
public static final int NUM_OF_SLOTS = 7;
public static final int SMELTING_INPUT_SLOT_NO = 0;
public static final int SMELTING_AUX_SLOT_NO = 1;
public static final int SMELTING_OUTPUT_SLOT_NO = 2;
public static final int FIFO_INPUT_0_SLOT_NO = 3;
public static final int FIFO_INPUT_1_SLOT_NO = 4;
public static final int FIFO_OUTPUT_0_SLOT_NO = 5;
public static final int FIFO_OUTPUT_1_SLOT_NO = 6;
public static final int DEFAULT_SPEED_PERCENT = 200;
public static final int DEFAULT_ENERGY_CONSUMPTION = 16;
public static final int DEFAULT_SCALED_ENERGY_CONSUMPTION = DEFAULT_ENERGY_CONSUMPTION * HEAT_INCREMENT * DEFAULT_SPEED_PERCENT / 100;
// Config ----------------------------------------------------------------------------------
private static boolean with_automatic_inventory_pulling_ = false;
private static int energy_consumption_ = DEFAULT_SCALED_ENERGY_CONSUMPTION;
private static int transfer_energy_consumption_ = DEFAULT_SCALED_ENERGY_CONSUMPTION / 8;
private static int proc_speed_percent_ = DEFAULT_SPEED_PERCENT;
public static void on_config(int speed_percent, int standard_energy_per_tick, boolean with_automatic_inventory_pulling)
{
proc_speed_percent_ = MathHelper.clamp(speed_percent, 10, 500);
energy_consumption_ = MathHelper.clamp(standard_energy_per_tick, 10, 256) * HEAT_INCREMENT * proc_speed_percent_ / 100;
transfer_energy_consumption_ = MathHelper.clamp(energy_consumption_ / 8, 8, HEAT_INCREMENT);
with_automatic_inventory_pulling_ = with_automatic_inventory_pulling;
ModEngineersDecor.logger().info("Config electrical furnace speed:" + proc_speed_percent_ + ", power consumption:" + energy_consumption_);
}
// BTileEntity -----------------------------------------------------------------------------
private int burntime_left_;
private int proc_time_elapsed_;
private int proc_time_needed_;
private int energy_stored_;
private int field_max_energy_stored_;
private int field_isburning_;
private int speed_;
private int tick_timer_;
private int fifo_timer_;
public BTileEntity()
{ this(ModContent.TET_SMALL_ELECTRICAL_FURNACE); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
public void reset()
{
super.reset();
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
burntime_left_ = 0;
proc_time_elapsed_ = 0;
proc_time_needed_ = 0;
fifo_timer_ = 0;
tick_timer_ = 0;
energy_stored_ = 0;
speed_ = 0;
field_max_energy_stored_ = getMaxEnergyStored();
field_isburning_ = 0;
}
public void readnbt(CompoundNBT nbt)
{
ItemStackHelper.loadAllItems(nbt, this.stacks_);
while(this.stacks_.size() < NUM_OF_SLOTS) this.stacks_.add(ItemStack.EMPTY);
burntime_left_ = nbt.getInt("BurnTime");
proc_time_elapsed_ = nbt.getInt("CookTime");
proc_time_needed_ = nbt.getInt("CookTimeTotal");
energy_stored_ = nbt.getInt("Energy");
speed_ = nbt.getInt("SpeedSetting");
}
protected void writenbt(CompoundNBT nbt)
{
nbt.putInt("BurnTime", MathHelper.clamp(burntime_left_, 0, HEAT_CAPACITY));
nbt.putInt("CookTime", MathHelper.clamp(proc_time_elapsed_, 0, MAX_BURNTIME));
nbt.putInt("CookTimeTotal", MathHelper.clamp(proc_time_needed_, 0, MAX_BURNTIME));
nbt.putInt("Energy", MathHelper.clamp(energy_stored_, 0, MAX_ENERGY_BUFFER));
nbt.putInt("SpeedSetting", MathHelper.clamp(speed_, -1, MAX_SPEED_SETTING));
ItemStackHelper.saveAllItems(nbt, stacks_);
}
// INameable -------------------------------------------------------------------------------
@Override
public ITextComponent getName()
{ final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Small electrical furnace"); }
// IContainerProvider ----------------------------------------------------------------------
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new BlockDecorFurnaceElectrical.BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); }
// IInventory ------------------------------------------------------------------------------
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{
switch(index) {
case SMELTING_INPUT_SLOT_NO:
case FIFO_INPUT_0_SLOT_NO:
case FIFO_INPUT_1_SLOT_NO:
return true;
default:
return false;
}
}
@Override
public ItemStack getStackInSlot(int index)
{ return ((index < 0) || (index >= SIDED_INV_SLOTS.length)) ? ItemStack.EMPTY : stacks_.get(SIDED_INV_SLOTS[index]); }
// Fields -----------------------------------------------------------------------------------------------
protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS)
{
@Override
public int get(int id)
{
switch(id) {
case 0: return BTileEntity.this.burntime_left_;
case 1: return BTileEntity.this.energy_stored_;
case 2: return BTileEntity.this.proc_time_elapsed_;
case 3: return BTileEntity.this.proc_time_needed_;
case 4: return BTileEntity.this.speed_;
case 5: return BTileEntity.this.field_max_energy_stored_;
case 6: return BTileEntity.this.field_isburning_;
default: return 0;
}
}
@Override
public void set(int id, int value)
{
switch(id) {
case 0: BTileEntity.this.burntime_left_ = value; break;
case 1: BTileEntity.this.energy_stored_ = value; break;
case 2: BTileEntity.this.proc_time_elapsed_ = value; break;
case 3: BTileEntity.this.proc_time_needed_ = value; break;
case 4: BTileEntity.this.speed_ = value; break;
case 5: BTileEntity.this.field_max_energy_stored_ = value; break;
case 6: BTileEntity.this.field_isburning_ = value; break;
}
}
};
// ISidedInventory ----------------------------------------------------------------------------
private static final int[] SIDED_INV_SLOTS = new int[] {
SMELTING_INPUT_SLOT_NO, SMELTING_AUX_SLOT_NO, SMELTING_OUTPUT_SLOT_NO,
FIFO_INPUT_0_SLOT_NO, FIFO_INPUT_1_SLOT_NO, FIFO_OUTPUT_0_SLOT_NO, FIFO_OUTPUT_1_SLOT_NO
};
@Override
public int[] getSlotsForFace(Direction side)
{ return SIDED_INV_SLOTS; }
@Override
public boolean canInsertItem(int index, ItemStack itemStackIn, Direction direction)
{ return isItemValidForSlot(index, itemStackIn); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return ((index!=SMELTING_INPUT_SLOT_NO) && (index!=FIFO_INPUT_0_SLOT_NO) && (index!=FIFO_INPUT_1_SLOT_NO)) || (stack.getItem()==Items.BUCKET); }
// IEnergyStorage ----------------------------------------------------------------------------
@Override
public boolean canExtract()
{ return false; }
@Override
public boolean canReceive()
{ return true; }
@Override
public int getMaxEnergyStored()
{ return MAX_ENERGY_BUFFER; }
@Override
public int getEnergyStored()
{ return energy_stored_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{
if(energy_stored_ >= MAX_ENERGY_BUFFER) return 0;
int n = Math.min(maxReceive, (MAX_ENERGY_BUFFER - energy_stored_));
if(n > MAX_ENERGY_TRANSFER) n = MAX_ENERGY_TRANSFER;
if(!simulate) {energy_stored_ += n; markDirty(); }
return n;
}
// IItemHandler --------------------------------------------------------------------------------
protected static class BItemHandler implements IItemHandler
{
private BTileEntity te;
BItemHandler(BTileEntity te)
{ this.te = te; }
@Override
public int getSlots()
{ return SIDED_INV_SLOTS.length; }
@Override
@Nonnull
public ItemStack getStackInSlot(int index)
{ return te.getStackInSlot(index); }
@Override
public int getSlotLimit(int index)
{ return te.getInventoryStackLimit(); }
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack)
{ return true; }
@Override
@Nonnull
public ItemStack insertItem(int index, @Nonnull ItemStack stack, boolean simulate)
{
if(stack.isEmpty()) return ItemStack.EMPTY;
if((index < 0) || (index >= SIDED_INV_SLOTS.length)) return ItemStack.EMPTY;
int slotno = SIDED_INV_SLOTS[index];
ItemStack slotstack = getStackInSlot(slotno);
if(!slotstack.isEmpty()) {
if(slotstack.getCount() >= Math.min(slotstack.getMaxStackSize(), getSlotLimit(index))) return stack;
if(!ItemHandlerHelper.canItemStacksStack(stack, slotstack)) return stack;
if(!te.canInsertItem(slotno, stack, Direction.UP) || (!te.isItemValidForSlot(slotno, stack))) return stack;
int n = Math.min(stack.getMaxStackSize(), getSlotLimit(index)) - slotstack.getCount();
if(stack.getCount() <= n) {
if(!simulate) {
ItemStack copy = stack.copy();
copy.grow(slotstack.getCount());
te.setInventorySlotContents(slotno, copy);
}
return ItemStack.EMPTY;
} else {
stack = stack.copy();
if(!simulate) {
ItemStack copy = stack.split(n);
copy.grow(slotstack.getCount());
te.setInventorySlotContents(slotno, copy);
return stack;
} else {
stack.shrink(n);
return stack;
}
}
} else {
if(!te.canInsertItem(slotno, stack, Direction.UP) || (!te.isItemValidForSlot(slotno, stack))) return stack;
int n = Math.min(stack.getMaxStackSize(), getSlotLimit(index));
if(n < stack.getCount()) {
stack = stack.copy();
if(!simulate) {
te.setInventorySlotContents(slotno, stack.split(n));
return stack;
} else {
stack.shrink(n);
return stack;
}
} else {
if(!simulate) te.setInventorySlotContents(slotno, stack);
return ItemStack.EMPTY;
}
}
}
@Override
@Nonnull
public ItemStack extractItem(int index, int amount, boolean simulate)
{
if(amount == 0) return ItemStack.EMPTY;
if((index < 0) || (index >= SIDED_INV_SLOTS.length)) return ItemStack.EMPTY;
int slotno = SIDED_INV_SLOTS[index];
ItemStack stackInSlot = getStackInSlot(slotno);
if(stackInSlot.isEmpty()) return ItemStack.EMPTY;
if(!te.canExtractItem(slotno, stackInSlot, Direction.DOWN)) return ItemStack.EMPTY;
if(simulate) {
if(stackInSlot.getCount() < amount) return stackInSlot.copy();
ItemStack ostack = stackInSlot.copy();
ostack.setCount(amount);
return ostack;
} else {
ItemStack ostack = te.decrStackSize(slotno, Math.min(stackInSlot.getCount(), amount));
te.markDirty();
return ostack;
}
}
}
// Capability export ----------------------------------------------------------------------------
protected LazyOptional<IItemHandler> item_handler_ = LazyOptional.of(() -> new BItemHandler(this));
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return item_handler_.cast();
if(capability== CapabilityEnergy.ENERGY) return energy_handler_.cast();
}
return super.getCapability(capability, facing);
}
// ITickableTileEntity -------------------------------------------------------------------------
@Override
public void tick()
{
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
final boolean was_burning = burning();
if(was_burning) burntime_left_ -= TICK_INTERVAL;
if(burntime_left_ < 0) burntime_left_ = 0;
if(world.isRemote) return;
boolean update_blockstate = (was_burning != burning());
boolean dirty = update_blockstate;
boolean shift_in = false;
boolean shift_out = false;
if(--fifo_timer_ <= 0) {
fifo_timer_ = FIFO_INTERVAL/TICK_INTERVAL;
if(transferItems(FIFO_OUTPUT_0_SLOT_NO, FIFO_OUTPUT_1_SLOT_NO, 64)) { dirty = true; } else { shift_out = true; }
if(transferItems(SMELTING_OUTPUT_SLOT_NO, FIFO_OUTPUT_0_SLOT_NO, 64)) dirty = true;
if(transferItems(FIFO_INPUT_0_SLOT_NO, SMELTING_INPUT_SLOT_NO, 64)) dirty = true;
if(transferItems(FIFO_INPUT_1_SLOT_NO, FIFO_INPUT_0_SLOT_NO, 64)) { dirty = true; } else { shift_in = true; }
}
if((!(stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty()) && (energy_stored_ >= energy_consumption_)) {
IRecipe last_recipe = currentRecipe();
updateCurrentRecipe();
if(currentRecipe() != last_recipe) {
proc_time_elapsed_ = 0;
proc_time_needed_ = getSmeltingTimeNeeded(world, stacks_.get(SMELTING_INPUT_SLOT_NO));
}
final boolean can_smelt = canSmeltCurrentItem();
if((!can_smelt) && (getSmeltingResult(stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty())) {
// bypass
if(transferItems(SMELTING_INPUT_SLOT_NO, SMELTING_OUTPUT_SLOT_NO, 1)) dirty = true;
} else {
// smelt
if(!burning() && can_smelt) {
if(heat_up()) { dirty = true; update_blockstate = true; }
}
if(burning() && can_smelt) {
if(heat_up()) dirty = true;
proc_time_elapsed_ += (TICK_INTERVAL * proc_speed_percent_/100);
if(proc_time_elapsed_ >= proc_time_needed_) {
proc_time_elapsed_ = 0;
proc_time_needed_ = getSmeltingTimeNeeded(world, stacks_.get(SMELTING_INPUT_SLOT_NO));
smeltCurrentItem();
dirty = true;
shift_out = true;
}
} else {
proc_time_elapsed_ = 0;
}
}
} else if(proc_time_elapsed_ > 0) {
proc_time_elapsed_ -= ((stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty() ? 20 : 1);
if(proc_time_elapsed_ < 0) { proc_time_elapsed_ = 0; shift_out = true; update_blockstate = true; }
}
if(update_blockstate) {
dirty = true;
sync_blockstate();
}
if(adjacent_inventory_shift(shift_in, shift_out)) dirty = true;
if(dirty) markDirty();
field_max_energy_stored_ = getMaxEnergyStored();
field_isburning_ = burning() ? 1 : 0;
//if(this.energy_stored_ < this.getMaxEnergyStored() / 5) this.energy_stored_ = this.getMaxEnergyStored();
}
// Furnace --------------------------------------------------------------------------------------
protected void updateCurrentRecipe() //// Change this for other recipe registry (e.g. craft tweaker modified).
{ setCurrentRecipe(getSmeltingResult(RECIPE_TYPE, world, stacks_.get(SMELTING_INPUT_SLOT_NO))); }
public boolean burning()
{ return burntime_left_ > 0; }
private boolean transferItems(final int index_from, final int index_to, int count)
{
ItemStack from = stacks_.get(index_from);
if(from.isEmpty()) return false;
ItemStack to = stacks_.get(index_to);
if(from.getCount() < count) count = from.getCount();
if(count <= 0) return false;
boolean changed = true;
if(to.isEmpty()) {
stacks_.set(index_to, from.split(count));
} else if(to.getCount() >= to.getMaxStackSize()) {
changed = false;
} else if((!from.isItemEqual(to)) || (!ItemStack.areItemStackTagsEqual(from, to))) {
changed = false;
} else {
if((to.getCount()+count) >= to.getMaxStackSize()) {
from.shrink(to.getMaxStackSize()-to.getCount());
to.setCount(to.getMaxStackSize());
} else {
from.shrink(count);
to.grow(count);
}
}
if(from.isEmpty() && from!=ItemStack.EMPTY) {
stacks_.set(index_from, ItemStack.EMPTY);
changed = true;
}
return changed;
}
private boolean adjacent_inventory_shift(boolean inp, boolean out)
{
boolean dirty = false;
if(energy_stored_ < transfer_energy_consumption_) return false;
final BlockState state = world.getBlockState(pos);
if(!(state.getBlock() instanceof BlockDecorFurnaceElectrical)) return false;
final Direction out_facing = state.get(FACING);
if(out && (!stacks_.get(FIFO_OUTPUT_1_SLOT_NO).isEmpty())) {
TileEntity te = world.getTileEntity(pos.offset(out_facing));
if(te!=null) {
IItemHandler hnd = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, out_facing).orElse(null);
if(hnd != null) {
ItemStack remaining = ItemHandlerHelper.insertItemStacked(hnd, stacks_.get(FIFO_OUTPUT_1_SLOT_NO).copy(), false);
stacks_.set(FIFO_OUTPUT_1_SLOT_NO, remaining);
energy_stored_ -= transfer_energy_consumption_;
dirty = true;
}
}
}
if(with_automatic_inventory_pulling_) {
final Direction inp_facing = state.get(FACING).getOpposite();
if(inp && (stacks_.get(FIFO_INPUT_1_SLOT_NO).isEmpty())) {
TileEntity te = world.getTileEntity(pos.offset(inp_facing));
if(te!=null) {
IItemHandler hnd = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, inp_facing).orElse(null);
if(hnd != null) {
for(int i=0; i< hnd.getSlots(); ++i) {
ItemStack adj_stack = hnd.getStackInSlot(i);
if(!adj_stack.isEmpty()) {
ItemStack my_stack = adj_stack.copy();
if(my_stack.getCount() > getInventoryStackLimit()) my_stack.setCount(getInventoryStackLimit());
adj_stack.shrink(my_stack.getCount());
stacks_.set(FIFO_INPUT_1_SLOT_NO, my_stack);
energy_stored_ -= transfer_energy_consumption_;
dirty = true;
break;
}
}
}
}
}
}
return dirty;
}
// returns TE dirty
private boolean heat_up()
{
if(energy_stored_ < (energy_consumption_)) return false;
if(burntime_left_ >= (HEAT_CAPACITY-HEAT_INCREMENT)) return false;
energy_stored_ -= energy_consumption_;
burntime_left_ += HEAT_INCREMENT;
this.markDirty();
return true;
}
private void sync_blockstate()
{
final BlockState state = world.getBlockState(pos);
if((state.getBlock() instanceof BlockDecorFurnaceElectrical) && (state.get(LIT) != burning())) {
world.setBlockState(pos, state.with(LIT, burning()), 2);
}
}
}
//--------------------------------------------------------------------------------------------------------------------
// container
//--------------------------------------------------------------------------------------------------------------------
public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer
{
private static final int PLAYER_INV_START_SLOTNO = 7;
protected final PlayerEntity player_;
protected final IInventory inventory_;
protected final IWorldPosCallable wpc_;
private final IIntArray fields_;
private final IRecipeType<? extends AbstractCookingRecipe> recipe_type_;
public int field(int index) { return fields_.get(index); }
public PlayerEntity player() { return player_ ; }
public IInventory inventory() { return inventory_ ; }
public World world() { return player_.world; }
public BContainer(int cid, PlayerInventory player_inventory)
{ this(cid, player_inventory, new Inventory(BTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(BTileEntity.NUM_OF_FIELDS)); }
private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields)
{
super(ModContent.CT_SMALL_ELECTRICAL_FURNACE, cid);
player_ = player_inventory.player;
inventory_ = block_inventory;
wpc_ = wpc;
fields_ = fields;
recipe_type_ = BTileEntity.RECIPE_TYPE;
addSlot(new Slot(inventory_, 0, 59, 28)); // smelting input
addSlot(new Slot(inventory_, 1, 16, 52)); // aux
addSlot(new BlockDecorFurnace.BContainer.BSlotResult(player_, inventory_, 2, 101, 28)); // smelting result
addSlot(new BlockDecorFurnace.BContainer.BSlotInpFifo(inventory_, 3, 34, 28)); // input fifo 0
addSlot(new BlockDecorFurnace.BContainer.BSlotInpFifo(inventory_, 4, 16, 28)); // input fifo 1
addSlot(new BlockDecorFurnace.BContainer.BSlotOutFifo(player_, inventory_, 5, 126, 28)); // out fifo 0
addSlot(new BlockDecorFurnace.BContainer.BSlotOutFifo(player_, inventory_, 6, 144, 28)); // out fifo 1
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 8+x*18, 144)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 86+y*18)); // player slots: 9..35
}
}
this.trackIntArray(fields_); // === Add reference holders
}
@Override
public boolean canInteractWith(PlayerEntity player)
{ return inventory_.isUsableByPlayer(player); }
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int index)
{
Slot slot = getSlot(index);
if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getStack();
ItemStack transferred = slot_stack.copy();
if((index==2) || (index==5) || (index==6)) {
// Output slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, true)) return ItemStack.EMPTY;
slot.onSlotChange(slot_stack, transferred);
} else if((index==0) || (index==3) || (index==4)) {
// Input slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if(index==1) {
// Bypass slot
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
// Player inventory
if(BTileEntity.canSmelt(world(), slot_stack)) {
if(
(!mergeItemStack(slot_stack, 0, 1, false)) && // smelting input
(!mergeItemStack(slot_stack, 3, 4, false)) && // fifo0
(!mergeItemStack(slot_stack, 4, 5, false)) // fifo1
) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index < PLAYER_INV_START_SLOTNO+27)) {
// player inventory --> player hotbar
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO+27, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO+27) && (index < PLAYER_INV_START_SLOTNO+36) && (!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+27, false))) {
// player hotbar --> player inventory
return ItemStack.EMPTY;
}
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
return transferred;
}
// INetworkSynchronisableContainer ---------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public void onGuiAction(CompoundNBT nbt)
{ Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); }
@OnlyIn(Dist.CLIENT)
public void onGuiAction(String key, int value)
{ CompoundNBT nbt=new CompoundNBT(); nbt.putInt(key, value); Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); }
@Override
public void onServerPacketReceived(int windowId, CompoundNBT nbt)
{}
@Override
public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt)
{}
}
//--------------------------------------------------------------------------------------------------------------------
// GUI
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class BGui extends ContainerScreen<BContainer>
{
protected final PlayerEntity player_;
public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title)
{ super(container, player_inventory, title); this.player_ = player_inventory.player; }
@Override
public void init()
{ super.init(); }
@Override
public void render(int mouseX, int mouseY, float partialTicks)
{
renderBackground();
super.render(mouseX, mouseY, partialTicks);
renderHoveredToolTip(mouseX, mouseY);
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
{
RenderSystem.enableBlend();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/small_electrical_furnace_gui.png"));
final int x0=(width-xSize)/2, y0=(height-ySize)/2, w=xSize, h=ySize;
blit(x0, y0, 0, 0, w, h);
if(getContainer().field(6)!=0) {
final int hi = 13;
final int k = heat_px(hi);
blit(x0+61, y0+53+hi-k, 177, hi-k, 13, k);
}
blit(x0+79, y0+30, 176, 15, 1+progress_px(17), 15);
int we = energy_px(32, 8);
if(we>0) blit(x0+88, y0+53, 185, 30, we, 13);
RenderSystem.disableBlend();
}
private int progress_px(int pixels)
{ final int tc=getContainer().field(2), T=getContainer().field(3); return ((T>0) && (tc>0)) ? (tc * pixels / T) : (0); }
private int heat_px(int pixels)
{
int k = ((getContainer().field(0) * (pixels+1)) / (BlockDecorFurnaceElectrical.BTileEntity.HEAT_CAPACITY));
return (k < pixels) ? k : pixels;
}
private int energy_px(int maxwidth, int quantization)
{
int emax = getContainer().field(5);
int k = ((maxwidth * getContainer().field(1) * 9) / 8) /((emax>0?emax:1)+1);
k = (k >= maxwidth-2) ? maxwidth : k;
if(quantization > 0) k = ((k+(quantization/2))/quantization) * quantization;
return k;
}
}
}

View file

@ -0,0 +1,52 @@
/*
* @file BlockDecorFull.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Full block characteristics class. Explicitly overrides some
* `Block` methods to return faster due to exclusive block properties.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.world.IBlockReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.StainedGlassBlock;
import net.minecraft.item.DyeColor;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Direction;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import java.util.List;
public class BlockDecorGlassBlock extends StainedGlassBlock implements IDecorBlock
{
public BlockDecorGlassBlock(long config, Block.Properties properties)
{ super(DyeColor.BLACK, properties); }
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{ ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.TRANSLUCENT; }
@Override
@OnlyIn(Dist.CLIENT)
@SuppressWarnings("deprecation")
public boolean isSideInvisible(BlockState state, BlockState adjacentBlockState, Direction side)
{ return (adjacentBlockState.getBlock()==this) ? true : super.isSideInvisible(state, adjacentBlockState, side); }
@Override
public boolean canSpawnInBlock()
{ return false; }
}

View file

@ -0,0 +1,195 @@
/*
* @file BlockDecorHalfSlab.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Half slab ("slab slices") characteristics class. Actually
* it's now a quater slab, but who cares.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.block.*;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.state.IntegerProperty;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.World;
import net.minecraft.entity.EntityType;
import net.minecraft.state.StateContainer;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.block.BlockState;
import net.minecraft.world.IBlockReader;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import wile.engineersdecor.detail.ModConfig;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BlockDecorHalfSlab extends BlockDecor implements IWaterLoggable
{
public static final IntegerProperty PARTS = IntegerProperty.create("parts", 0, 14);
protected static final VoxelShape AABBs[] = {
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 2./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 4./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 6./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 8./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 10./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 12./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 14./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 0./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 2./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 4./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 6./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 8./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 10./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 12./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0, 14./16, 0, 1, 16./16, 1)),
VoxelShapes.create(new AxisAlignedBB(0,0,0,1,1,1)) // <- with 4bit fill
};
protected static final int num_slabs_contained_in_parts_[] = { 1,2,3,4,5,6,7,8,7,6,5,4,3,2,1 ,0x1 }; // <- with 4bit fill
public BlockDecorHalfSlab(long config, Block.Properties builder)
{ super(config|CFG_WATERLOGGABLE, builder); }
protected boolean is_cube(BlockState state)
{ return state.get(PARTS) == 0x07; }
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{
if(!ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true)) return;
if(!ModConfig.without_direct_slab_pickup) ModAuxiliaries.Tooltip.addInformation("engineersdecor.tooltip.slabpickup", "engineersdecor.tooltip.slabpickup", tooltip, flag, true);
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return (((config & CFG_TRANSLUCENT)!=0) ? (RenderTypeHint.TRANSLUCENT) : (RenderTypeHint.CUTOUT)); }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public VoxelShape getShape(BlockState state, IBlockReader source, BlockPos pos, ISelectionContext selectionContext)
{ return AABBs[state.get(PARTS) & 0xf]; }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return getShape(state, world, pos, selectionContext); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(PARTS, WATERLOGGED); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{
final Direction facing = context.getFace();
double y = context.getHitVec().getY();
return super.getStateForPlacement(context).with(PARTS, ((facing==Direction.UP) || ((facing!=Direction.DOWN) && (y < 0.6))) ? 0 : 14);
}
@Override
@SuppressWarnings("deprecation")
public BlockState rotate(BlockState state, Rotation rot)
{ return state; }
@Override
@SuppressWarnings("deprecation")
public BlockState mirror(BlockState state, Mirror mirrorIn)
{ return state; }
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{ return new ArrayList<ItemStack>(Collections.singletonList(new ItemStack(this.asItem(), num_slabs_contained_in_parts_[state.get(PARTS) & 0xf]))); }
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
Direction face = rayTraceResult.getFace();
final ItemStack stack = player.getHeldItem(hand);
if(stack.isEmpty() || (Block.getBlockFromItem(stack.getItem()) != this)) return false;
if((face != Direction.UP) && (face != Direction.DOWN)) return false;
int parts = state.get(PARTS);
if((face != Direction.UP) && (parts > 7)) {
world.setBlockState(pos, state.with(PARTS, parts-1), 3);
} else if((face != Direction.DOWN) && (parts < 7)) {
world.setBlockState(pos, state.with(PARTS, parts+1), 3);
} else {
return (parts != 7);
}
if(world.isRemote) return true;
if(!player.isCreative()) {
stack.shrink(1);
if(player.inventory != null) player.inventory.markDirty();
}
SoundType st = this.getSoundType(state, world, pos, null);
world.playSound(null, pos, st.getPlaceSound(), SoundCategory.BLOCKS, (st.getVolume()+1f)/2.5f, 0.9f*st.getPitch());
return true;
}
@Override
@SuppressWarnings("deprecation")
public void onBlockClicked(BlockState state, World world, BlockPos pos, PlayerEntity player)
{
if((world.isRemote) || (ModConfig.without_direct_slab_pickup)) return;
final ItemStack stack = player.getHeldItemMainhand();
if(stack.isEmpty() || (Block.getBlockFromItem(stack.getItem()) != this)) return;
if(stack.getCount() >= stack.getMaxStackSize()) return;
Vec3d lv = player.getLookVec();
Direction facing = Direction.getFacingFromVector((float)lv.x, (float)lv.y, (float)lv.z);
if((facing != Direction.UP) && (facing != Direction.DOWN)) return;
if(state.getBlock() != this) return;
int parts = state.get(PARTS);
if((facing == Direction.DOWN) && (parts <= 7)) {
if(parts > 0) {
world.setBlockState(pos, state.with(PARTS, parts-1), 3);
} else {
world.removeBlock(pos, false);
}
} else if((facing == Direction.UP) && (parts >= 7)) {
if(parts < 14) {
world.setBlockState(pos, state.with(PARTS, parts + 1), 3);
} else {
world.removeBlock(pos, false);
}
} else {
return;
}
if(!player.isCreative()) {
stack.grow(1);
if(player.inventory != null) player.inventory.markDirty(); // @todo: check if inventory can actually be null
}
SoundType st = this.getSoundType(state, world, pos, null);
world.playSound(player, pos, st.getPlaceSound(), SoundCategory.BLOCKS, (st.getVolume()+1f)/2.5f, 0.9f*st.getPitch());
}
}

View file

@ -0,0 +1,877 @@
/*
* @file BlockDecorHopper.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Hopper, factory automation suitable.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.Networking;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.HopperBlock;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.tileentity.HopperTileEntity;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.*;
import net.minecraft.inventory.*;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot;
import net.minecraft.util.*;
import net.minecraft.util.math.*;
import net.minecraft.util.text.*;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.wrapper.SidedInvWrapper;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import com.mojang.blaze3d.systems.RenderSystem;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
public class BlockDecorHopper extends BlockDecorDirected
{
public BlockDecorHopper(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos)
{ return Container.calcRedstone(world.getTileEntity(pos)); }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BlockDecorHopper.BTileEntity(); }
@Override
public void onBlockPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack)
{
if(world.isRemote) return;
if((!stack.hasTag()) || (!stack.getTag().contains("tedata"))) return;
CompoundNBT te_nbt = stack.getTag().getCompound("tedata");
if(te_nbt.isEmpty()) return;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).readnbt(te_nbt, false);
((BTileEntity)te).reset_rtstate();
((BTileEntity)te).markDirty();
}
@Override
public boolean hasDynamicDropList()
{ return true; }
@Override
public List<ItemStack> dropList(BlockState state, World world, BlockPos pos, boolean explosion)
{
final List<ItemStack> stacks = new ArrayList<ItemStack>();
if(world.isRemote) return stacks;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return stacks;
if(!explosion) {
ItemStack stack = new ItemStack(this, 1);
CompoundNBT te_nbt = ((BTileEntity)te).clear_getnbt();
if(!te_nbt.isEmpty()) {
CompoundNBT nbt = new CompoundNBT();
nbt.put("tedata", te_nbt);
stack.setTag(nbt);
}
stacks.add(stack);
} else {
for(ItemStack stack: ((BTileEntity)te).stacks_) {
if(!stack.isEmpty()) stacks.add(stack);
}
((BTileEntity)te).reset_rtstate();
}
return stacks;
}
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult)
{
if(world.isRemote) return true;
final TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return true;
if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return true;
NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te);
return true;
}
@Override
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused)
{
if(!(world instanceof World) || (((World) world).isRemote)) return;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).block_updated();
}
@Override
public void onFallenUpon(World world, BlockPos pos, Entity entity, float fallDistance)
{
super.onFallenUpon(world, pos, entity, fallDistance);
if(!(entity instanceof ItemEntity)) return;
TileEntity te = world.getTileEntity(pos);
if(!(te instanceof BTileEntity)) return;
((BTileEntity)te).collection_timer_ = 0;
}
@Override
@SuppressWarnings("deprecation")
public boolean canProvidePower(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getWeakPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
@Override
@SuppressWarnings("deprecation")
public int getStrongPower(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side)
{ return 0; }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory
{
public static final int NUM_OF_FIELDS = 7;
public static final int TICK_INTERVAL = 10;
public static final int COLLECTION_INTERVAL = 50;
public static final int NUM_OF_SLOTS = 18;
public static final int MAX_TRANSFER_COUNT = 32;
public static final int MAX_COLLECTION_RANGE = 4;
public static final int PERIOD_OFFSET = 10;
///
public static final int LOGIC_INVERTED = 0x01;
public static final int LOGIC_CONTINUOUS = 0x02;
///
private boolean block_power_signal_ = false;
private boolean block_power_updated_ = false;
private int collection_timer_ = 0;
private int delay_timer_ = 0;
private int transfer_count_ = 1;
private int logic_ = LOGIC_INVERTED|LOGIC_CONTINUOUS;
private int transfer_period_ = 0;
private int collection_range_ = 0;
private int current_slot_index_ = 0;
private int tick_timer_ = 0;
protected NonNullList<ItemStack> stacks_;
public static void on_config(int cooldown_ticks)
{
// ModEngineersDecor.logger.info("Config factory hopper:");
}
public BTileEntity()
{
this(ModContent.TET_FACTORY_HOPPER);
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
reset_rtstate();
}
public BTileEntity(TileEntityType<?> te_type)
{
super(te_type);
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
reset_rtstate();
}
public void reset_rtstate()
{
block_power_signal_ = false;
block_power_updated_ = false;
}
public CompoundNBT clear_getnbt()
{
CompoundNBT nbt = new CompoundNBT();
block_power_signal_ = false;
writenbt(nbt, false);
for(int i=0; i<stacks_.size(); ++i) stacks_.set(i, ItemStack.EMPTY);
reset_rtstate();
block_power_updated_ = false;
return nbt;
}
public void readnbt(CompoundNBT nbt, boolean update_packet)
{
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
ItemStackHelper.loadAllItems(nbt, stacks_);
while(stacks_.size() < NUM_OF_SLOTS) stacks_.add(ItemStack.EMPTY);
block_power_signal_ = nbt.getBoolean("powered");
current_slot_index_ = nbt.getInt("act_slot_index");
transfer_count_ = MathHelper.clamp(nbt.getInt("xsize"), 1, MAX_TRANSFER_COUNT);
logic_ = nbt.getInt("logic");
transfer_period_ = nbt.getInt("period");
collection_range_ = nbt.getInt("range");
}
protected void writenbt(CompoundNBT nbt, boolean update_packet)
{
ItemStackHelper.saveAllItems(nbt, stacks_);
nbt.putBoolean("powered", block_power_signal_);
nbt.putInt("act_slot_index", current_slot_index_);
nbt.putInt("xsize", transfer_count_);
nbt.putInt("logic", logic_);
nbt.putInt("period", transfer_period_);
nbt.putInt("range", collection_range_);
}
public void block_updated()
{
// RS power check, both edges
boolean powered = world.isBlockPowered(pos);
if(block_power_signal_ != powered) block_power_updated_ = true;
block_power_signal_ = powered;
tick_timer_ = 1;
}
public boolean is_input_slot(int index)
{ return (index >= 0) && (index < NUM_OF_SLOTS); }
// TileEntity --------------------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt, false); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt, false); return nbt; }
// INamable ----------------------------------------------------------------------------------------------
@Override
public ITextComponent getName()
{ final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getTranslationKey() : "Factory Hopper"); }
@Override
public boolean hasCustomName()
{ return false; }
@Override
public ITextComponent getCustomName()
{ return getName(); }
// INamedContainerProvider ------------------------------------------------------------------------------
@Override
public ITextComponent getDisplayName()
{ return INameable.super.getDisplayName(); }
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new BContainer(id, inventory, this, IWorldPosCallable.of(world, pos), fields); }
// IInventory --------------------------------------------------------------------------------------------
@Override
public int getSizeInventory()
{ return stacks_.size(); }
@Override
public boolean isEmpty()
{ for(ItemStack stack: stacks_) { if(!stack.isEmpty()) return false; } return true; }
@Override
public ItemStack getStackInSlot(int index)
{ return (index < stacks_.size()) ? stacks_.get(index) : ItemStack.EMPTY; }
@Override
public ItemStack decrStackSize(int index, int count)
{ return ItemStackHelper.getAndSplit(stacks_, index, count); }
@Override
public ItemStack removeStackFromSlot(int index)
{ return ItemStackHelper.getAndRemove(stacks_, index); }
@Override
public void setInventorySlotContents(int index, ItemStack stack)
{
stacks_.set(index, stack);
if(stack.getCount() > getInventoryStackLimit()) stack.setCount(getInventoryStackLimit());
if(tick_timer_ > 8) tick_timer_ = 8;
markDirty();
}
@Override
public int getInventoryStackLimit()
{ return 64; }
@Override
public void markDirty()
{ super.markDirty(); }
@Override
public boolean isUsableByPlayer(PlayerEntity player)
{ return getPos().distanceSq(player.getPosition()) < 36; }
@Override
public void openInventory(PlayerEntity player)
{}
@Override
public void closeInventory(PlayerEntity player)
{ markDirty(); }
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{ return true; }
@Override
public void clear()
{ stacks_.clear(); }
// Fields -----------------------------------------------------------------------------------------------
protected final IIntArray fields = new IntArray(BTileEntity.NUM_OF_FIELDS)
{
@Override
public int get(int id)
{
switch(id) {
case 0: return collection_range_;
case 1: return transfer_count_;
case 2: return logic_;
case 3: return transfer_period_;
case 4: return delay_timer_;
case 5: return block_power_signal_ ? 1 : 0;
case 6: return current_slot_index_;
default: return 0;
}
}
@Override
public void set(int id, int value)
{
switch(id) {
case 0: collection_range_ = MathHelper.clamp(value,0, MAX_COLLECTION_RANGE); return;
case 1: transfer_count_ = MathHelper.clamp(value,1, MAX_TRANSFER_COUNT); return;
case 2: logic_ = value; return;
case 3: transfer_period_ = MathHelper.clamp(value,0, 100); return;
case 4: delay_timer_ = MathHelper.clamp(value,0, 400); return;
case 5: block_power_signal_ = (value != 0); return;
case 6: current_slot_index_ = MathHelper.clamp(value, 0, NUM_OF_SLOTS-1); return;
default: return;
}
}
};
// ISidedInventory --------------------------------------------------------------------------------------
LazyOptional<? extends IItemHandler>[] item_handlers = SidedInvWrapper.create(this, Direction.UP);
private static final int[] SIDED_INV_SLOTS;
static {
SIDED_INV_SLOTS = new int[NUM_OF_SLOTS];
for(int i=0; i<NUM_OF_SLOTS; ++i) SIDED_INV_SLOTS[i] = i;
}
@Override
public int[] getSlotsForFace(Direction side)
{ return SIDED_INV_SLOTS; }
@Override
public boolean canInsertItem(int index, ItemStack stack, Direction direction)
{ return is_input_slot(index) && isItemValidForSlot(index, stack); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return (direction != Direction.UP); }
// Capability export ------------------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return item_handlers[0].cast();
}
return super.getCapability(capability, facing);
}
// ITickable and aux methods ---------------------------------------------------------------------
private static int next_slot(int i)
{ return (i<NUM_OF_SLOTS-1) ? (i+1) : 0; }
private int try_insert_into_hopper(final ItemStack stack)
{
final int max_to_insert = stack.getCount();
int n_to_insert = max_to_insert;
int first_empty_slot = -1;
for(int i=0; i<stacks_.size(); ++i) {
final ItemStack slotstack = stacks_.get(i);
if((first_empty_slot < 0) && slotstack.isEmpty()) { first_empty_slot=i; continue; }
if(!stack.isItemEqual(slotstack)) continue;
int nspace = slotstack.getMaxStackSize() - slotstack.getCount();
if(nspace <= 0) {
continue;
} else if(nspace >= n_to_insert) {
slotstack.grow(n_to_insert);
n_to_insert = 0;
break;
} else {
slotstack.grow(nspace);
n_to_insert -= nspace;
}
}
if((n_to_insert > 0) && (first_empty_slot >= 0)) {
ItemStack new_stack = stack.copy();
new_stack.setCount(n_to_insert);
stacks_.set(first_empty_slot, new_stack);
n_to_insert = 0;
}
return max_to_insert - n_to_insert;
}
private boolean try_insert(Direction facing)
{
ItemStack current_stack = ItemStack.EMPTY;
for(int i=0; i<NUM_OF_SLOTS; ++i) {
if(current_slot_index_ >= NUM_OF_SLOTS) current_slot_index_ = 0;
current_stack = stacks_.get(current_slot_index_);
if(!current_stack.isEmpty()) break;
current_slot_index_ = next_slot(current_slot_index_);
}
if(current_stack.isEmpty()) {
current_slot_index_ = 0;
return false;
}
final TileEntity te = world.getTileEntity(pos.offset(facing));
if(te == null) { delay_timer_ = TICK_INTERVAL+2; return false; } // no reason to recalculate this all the time if there is nothere to insert.
final IItemHandler ih = te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite()).orElse(null);
if(ih == null) { delay_timer_ = TICK_INTERVAL+2; return false; }
if(te instanceof HopperTileEntity) {
Direction f = world.getBlockState(pos.offset(facing)).get(HopperBlock.FACING);
if(f==facing.getOpposite()) return false; // no back transfer
} else if(te instanceof BTileEntity) {
Direction f = world.getBlockState(pos.offset(facing)).get(FACING);
if(f==facing.getOpposite()) return false;
}
ItemStack insert_stack = current_stack.copy();
if(insert_stack.getCount() > transfer_count_) insert_stack.setCount(transfer_count_);
final int initial_insert_stack_size = insert_stack.getCount();
int first_empty_slot_index = -1;
if((ih == null) || ih.getSlots() <= 0) return false;
for(int i=0; i<ih.getSlots(); ++i) {
if(!ih.isItemValid(i, insert_stack)) continue;
final ItemStack target_stack = ih.getStackInSlot(i);
if((first_empty_slot_index < 0) && target_stack.isEmpty()) first_empty_slot_index = i;
if(!target_stack.isItemEqual(insert_stack)) continue;
insert_stack = ih.insertItem(i, insert_stack.copy(), false);
if(insert_stack.isEmpty()) break;
}
if((first_empty_slot_index >= 0) && (!insert_stack.isEmpty())) {
insert_stack = ih.insertItem(first_empty_slot_index, insert_stack.copy(), false);
}
final int num_inserted = initial_insert_stack_size-insert_stack.getCount();
if(num_inserted > 0) {
current_stack.shrink(num_inserted);
stacks_.set(current_slot_index_, current_stack);
}
if(!insert_stack.isEmpty()) current_slot_index_ = next_slot(current_slot_index_);
return (num_inserted > 0);
}
private boolean try_item_handler_extract(final IItemHandler ih)
{
final int end = ih.getSlots();
int n_to_extract = transfer_count_;
for(int i=0; i<end; ++i) {
if(ih.getStackInSlot(i).isEmpty()) continue;
ItemStack stack = ih.extractItem(i, n_to_extract, true);
if(stack.isEmpty()) continue;
int n_accepted = try_insert_into_hopper(stack);
if(n_accepted > 0) {
ItemStack test = ih.extractItem(i, n_accepted, false);
n_to_extract -= n_accepted;
if(n_to_extract <= 0) break;
}
}
return (n_to_extract < transfer_count_);
}
private boolean try_inventory_extract(final IInventory inv)
{
final int end = inv.getSizeInventory();
int n_to_extract = transfer_count_;
for(int i=0; i<end; ++i) {
ItemStack stack = inv.getStackInSlot(i).copy();
if(stack.isEmpty()) continue;
int n_accepted = try_insert_into_hopper(stack);
if(n_accepted > 0) {
stack.shrink(n_accepted);
n_to_extract -= n_accepted;
if(stack.isEmpty()) stack = ItemStack.EMPTY;
inv.setInventorySlotContents(i, stack);
if(n_to_extract <= 0) break;
}
}
if(n_to_extract < transfer_count_) {
inv.markDirty();
return true;
} else {
return false;
}
}
private boolean try_collect(Direction facing)
{
AxisAlignedBB collection_volume;
Vec3d rpos;
if(facing==Direction.UP) {
rpos = new Vec3d(0.5+pos.getX(),1.5+pos.getY(),0.5+pos.getZ());
collection_volume = (new AxisAlignedBB(pos.up())).grow(0.1+collection_range_, 0.6, 0.1+collection_range_);
} else {
rpos = new Vec3d(0.5+pos.getX(),-1.5+pos.getY(),0.5+pos.getZ());
collection_volume = (new AxisAlignedBB(pos.down(2))).grow(0.1+collection_range_, 1, 0.1+collection_range_);
}
final List<ItemEntity> items = world.getEntitiesWithinAABB(ItemEntity.class, collection_volume);
if(items.size() <= 0) return false;
final int max_to_collect = 3;
int n_collected = 0;
for(ItemEntity ie:items) {
boolean is_direct_collection_tange = ie.getDistanceSq(rpos)<0.7;
if(!is_direct_collection_tange && (ie.cannotPickup() || (!ie.onGround))) continue;
ItemStack stack = ie.getItem();
int n_accepted = try_insert_into_hopper(stack);
if(n_accepted <= 0) continue;
if(n_accepted == stack.getCount()) {
ie.remove();
} else {
stack.shrink(n_accepted);
}
if((!is_direct_collection_tange) && (++n_collected >= max_to_collect)) break;
}
return (n_collected > 0);
}
@Override
public void tick()
{
// Tick cycle pre-conditions
if(world.isRemote) return;
if((delay_timer_ > 0) && ((--delay_timer_) == 0)) markDirty();
if(--tick_timer_ > 0) return;
tick_timer_ = TICK_INTERVAL;
// Cycle init
boolean dirty = block_power_updated_;
final boolean rssignal = ((logic_ & LOGIC_INVERTED)!=0)==(!block_power_signal_);
final boolean pulse_mode = ((logic_ & LOGIC_CONTINUOUS)==0);
boolean trigger = (rssignal && ((block_power_updated_) || (!pulse_mode)));
final BlockState state = world.getBlockState(pos);
if(state == null) { block_power_signal_= false; return; }
final Direction hopper_facing = state.get(FACING);
// Trigger edge detection for next cycle
{
boolean tr = world.isBlockPowered(pos);
block_power_updated_ = (block_power_signal_ != tr);
block_power_signal_ = tr;
if(block_power_updated_) dirty = true;
}
// Collection
if(rssignal || pulse_mode) {
Direction hopper_input_facing = (hopper_facing==Direction.UP) ? Direction.DOWN : Direction.UP;
TileEntity te = world.getTileEntity(pos.offset(hopper_input_facing));
final IItemHandler ih = (te==null) ? (null) : (te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, hopper_input_facing.getOpposite()).orElse(null));
if((ih != null) || (te instanceof ISidedInventory)) {
// IItemHandler pulling
if((ih != null)) {
if(try_item_handler_extract(ih)) dirty = true;
} else {
if(try_inventory_extract((IInventory)te)) dirty = true;
}
} else if((collection_timer_ -= TICK_INTERVAL) <= 0) {
// Ranged collection
collection_timer_ = COLLECTION_INTERVAL;
if(try_collect(hopper_input_facing)) dirty = true;
}
}
// Insertion
if(trigger && (delay_timer_ <= 0)) {
delay_timer_ = PERIOD_OFFSET + transfer_period_ * 2;
if(try_insert(hopper_facing)) dirty = true;
}
if(dirty) markDirty();
if(trigger && (tick_timer_ > TICK_INTERVAL)) tick_timer_ = TICK_INTERVAL;
}
}
//--------------------------------------------------------------------------------------------------------------------
// container
//--------------------------------------------------------------------------------------------------------------------
public static class BContainer extends Container implements Networking.INetworkSynchronisableContainer
{
private static final int PLAYER_INV_START_SLOTNO = BTileEntity.NUM_OF_SLOTS;
private final PlayerEntity player_;
private final IInventory inventory_;
private final IWorldPosCallable wpc_;
private final IIntArray fields_;
public final int field(int index) { return fields_.get(index); }
public BContainer(int cid, PlayerInventory player_inventory)
{ this(cid, player_inventory, new Inventory(BTileEntity.NUM_OF_SLOTS), IWorldPosCallable.DUMMY, new IntArray(BTileEntity.NUM_OF_FIELDS)); }
private BContainer(int cid, PlayerInventory player_inventory, IInventory block_inventory, IWorldPosCallable wpc, IIntArray fields)
{
super(ModContent.CT_FACTORY_HOPPER, cid);
fields_ = fields;
wpc_ = wpc;
player_ = player_inventory.player;
inventory_ = block_inventory;
int i=-1;
// input slots (stacks 0 to 17)
for(int y=0; y<3; ++y) {
for(int x=0; x<6; ++x) {
int xpos = 11+x*18, ypos = 9+y*17;
addSlot(new Slot(inventory_, ++i, xpos, ypos));
}
}
// player slots
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x, 8+x*18, 129)); // player slots: 0..8
}
for(int y=0; y<3; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(player_inventory, x+y*9+9, 8+x*18, 71+y*18)); // player slots: 9..35
}
}
this.trackIntArray(fields_); // === Add reference holders
}
@Override
public boolean canInteractWith(PlayerEntity player)
{ return inventory_.isUsableByPlayer(player); }
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int index)
{
Slot slot = getSlot(index);
if((slot==null) || (!slot.getHasStack())) return ItemStack.EMPTY;
ItemStack slot_stack = slot.getStack();
ItemStack transferred = slot_stack.copy();
if((index>=0) && (index<PLAYER_INV_START_SLOTNO)) {
// Device slots
if(!mergeItemStack(slot_stack, PLAYER_INV_START_SLOTNO, PLAYER_INV_START_SLOTNO+36, false)) return ItemStack.EMPTY;
} else if((index >= PLAYER_INV_START_SLOTNO) && (index <= PLAYER_INV_START_SLOTNO+36)) {
// Player slot
if(!mergeItemStack(slot_stack, 0, BTileEntity.NUM_OF_SLOTS, false)) return ItemStack.EMPTY;
} else {
// invalid slot
return ItemStack.EMPTY;
}
if(slot_stack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if(slot_stack.getCount() == transferred.getCount()) return ItemStack.EMPTY;
slot.onTake(player, slot_stack);
return transferred;
}
// INetworkSynchronisableContainer ---------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public void onGuiAction(CompoundNBT nbt)
{ Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt); }
@OnlyIn(Dist.CLIENT)
public void onGuiAction(String key, int value)
{
CompoundNBT nbt = new CompoundNBT();
nbt.putInt(key, value);
Networking.PacketContainerSyncClientToServer.sendToServer(windowId, nbt);
}
@Override
public void onServerPacketReceived(int windowId, CompoundNBT nbt)
{}
@Override
public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt)
{
if(!(inventory_ instanceof BTileEntity)) return;
BTileEntity te = (BTileEntity)inventory_;
if(nbt.contains("xsize")) te.transfer_count_ = MathHelper.clamp(nbt.getInt("xsize"), 1, BTileEntity.MAX_TRANSFER_COUNT);
if(nbt.contains("period")) te.transfer_period_ = MathHelper.clamp(nbt.getInt("period"), 0, 100);
if(nbt.contains("range")) te.collection_range_ = MathHelper.clamp(nbt.getInt("range"), 0, BTileEntity.MAX_COLLECTION_RANGE);
if(nbt.contains("logic")) te.logic_ = nbt.getInt("logic");
if(nbt.contains("manual_trigger") && (nbt.getInt("manual_trigger")!=0)) { te.block_power_signal_=true; te.block_power_updated_=true; te.tick_timer_=1; }
te.markDirty();
}
}
//--------------------------------------------------------------------------------------------------------------------
// GUI
//--------------------------------------------------------------------------------------------------------------------
@OnlyIn(Dist.CLIENT)
public static class BGui extends ContainerScreen<BContainer>
{
protected final PlayerEntity player_;
public BGui(BContainer container, PlayerInventory player_inventory, ITextComponent title)
{ super(container, player_inventory, title); this.player_ = player_inventory.player; }
@Override
public void init()
{ super.init(); }
@Override
public void render(int mouseX, int mouseY, float partialTicks)
{
renderBackground();
super.render(mouseX, mouseY, partialTicks);
renderHoveredToolTip(mouseX, mouseY);
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int mouseButton)
{
BContainer container = (BContainer)getContainer();
int mx = (int)(mouseX - getGuiLeft() + .5), my = (int)(mouseY - getGuiTop() + .5);
if((!isPointInRegion(126, 1, 49, 60, mouseX, mouseY))) {
return super.mouseClicked(mouseX, mouseY, mouseButton);
} else if(isPointInRegion(128, 9, 44, 10, mouseX, mouseY)) {
int range = (mx-133);
if(range < -1) {
range = container.field(0) - 1; // -
} else if(range >= 34) {
range = container.field(0) + 1; // +
} else {
range = (int)(0.5 + ((((double)BTileEntity.MAX_COLLECTION_RANGE) * range)/34)); // slider
range = MathHelper.clamp(range, 0, BTileEntity.MAX_COLLECTION_RANGE);
}
container.onGuiAction("range", range);
} else if(isPointInRegion(128, 21, 44, 10, mouseX, mouseY)) {
int period = (mx-133);
if(period < -1) {
period = container.field(3) - 3; // -
} else if(period >= 35) {
period = container.field(3) + 3; // +
} else {
period = (int)(0.5 + ((100.0 * period)/34));
}
period = MathHelper.clamp(period, 0, 100);
container.onGuiAction("period", period);
} else if(isPointInRegion(128, 34, 44, 10, mouseX, mouseY)) {
int ndrop = (mx-134);
if(ndrop < -1) {
ndrop = container.field(1) - 1; // -
} else if(ndrop >= 34) {
ndrop = container.field(1) + 1; // +
} else {
ndrop = MathHelper.clamp(1+ndrop, 1, BTileEntity.MAX_TRANSFER_COUNT); // slider
}
container.onGuiAction("xsize", ndrop);
} else if(isPointInRegion(133, 49, 9, 9, mouseX, mouseY)) {
container.onGuiAction("manual_trigger", 1);
} else if(isPointInRegion(145, 49, 9, 9, mouseX, mouseY)) {
container.onGuiAction("logic", container.field(2) ^ BTileEntity.LOGIC_INVERTED);
} else if(isPointInRegion(159, 49, 7, 9, mouseX, mouseY)) {
container.onGuiAction("logic", container.field(2) ^ BTileEntity.LOGIC_CONTINUOUS);
}
return true;
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
{
RenderSystem.enableBlend();
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
this.minecraft.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/factory_hopper_gui.png"));
final int x0=getGuiLeft(), y0=getGuiTop(), w=getXSize(), h=getYSize();
blit(x0, y0, 0, 0, w, h);
BContainer container = (BContainer)getContainer();
// active slot
{
int slot_index = container.field(6);
if((slot_index < 0) || (slot_index >= BTileEntity.NUM_OF_SLOTS)) slot_index = 0;
int x = (x0+10+((slot_index % 6) * 18));
int y = (y0+8+((slot_index / 6) * 17));
blit(x, y, 200, 8, 18, 18);
}
// collection range
{
int lut[] = { 133, 141, 149, 157, 166 };
int px = lut[MathHelper.clamp(container.field(0), 0, BTileEntity.MAX_COLLECTION_RANGE)];
int x = x0 + px - 2;
int y = y0 + 14;
blit(x, y, 179, 40, 5, 5);
}
// transfer period
{
int px = (int)Math.round(((33.5 * container.field(3)) / 100) + 1);
int x = x0 + 132 - 2 + MathHelper.clamp(px, 0, 34);
int y = y0 + 27;
blit(x, y, 179, 40, 5, 5);
}
// transfer count
{
int x = x0 + 133 - 2 + (container.field(1));
int y = y0 + 40;
blit(x, y, 179, 40, 5, 5);
}
// redstone input
{
if(container.field(5) != 0) {
blit(x0+133, y0+49, 217, 49, 9, 9);
}
}
// trigger logic
{
int inverter_offset = ((container.field(2) & BTileEntity.LOGIC_INVERTED) != 0) ? 11 : 0;
blit(x0+145, y0+49, 177+inverter_offset, 49, 9, 9);
int pulse_mode_offset = ((container.field(2) & BTileEntity.LOGIC_CONTINUOUS ) != 0) ? 9 : 0;
blit(x0+159, y0+49, 199+pulse_mode_offset, 49, 9, 9);
}
// delay timer running indicator
{
if((container.field(4) > BTileEntity.PERIOD_OFFSET) && ((System.currentTimeMillis() % 1000) < 500)) {
blit(x0+148, y0+22, 187, 22, 3, 3);
}
}
RenderSystem.disableBlend();
}
}
}

View file

@ -0,0 +1,133 @@
/*
* @file BlockDecorHorizontalSupport.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Horizontal ceiling support. Symmetric x axis, fixed in
* xz plane, therefore boolean placement state.
*/
package wile.engineersdecor.blocks;
import net.minecraft.block.IWaterLoggable;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.block.Block;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.IntegerProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.util.*;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
public class BlockDecorHorizontalSupport extends BlockDecor implements IWaterLoggable
{
public static final BooleanProperty EASTWEST = BooleanProperty.create("eastwest");
public static final BooleanProperty LEFTBEAM = BooleanProperty.create("leftbeam");
public static final BooleanProperty RIGHTBEAM = BooleanProperty.create("rightbeam");
public static final IntegerProperty DOWNCONNECT = IntegerProperty.create("downconnect", 0, 2);
protected final ArrayList<VoxelShape> AABBs;
public BlockDecorHorizontalSupport(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{
super(config|CFG_HORIZIONTAL|CFG_WATERLOGGABLE, builder);
AABBs = new ArrayList<VoxelShape>(Arrays.asList(
// Effective bounding box
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB.grow(2.0/16, 0, 0), Direction.NORTH, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB.grow(2.0/16, 0, 0), Direction.WEST, true)),
// Displayed bounding box
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.NORTH, true)),
VoxelShapes.create(ModAuxiliaries.getRotatedAABB(unrotatedAABB, Direction.WEST, true))
));
}
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
public VoxelShape getShape(BlockState state, IBlockReader source, BlockPos pos, ISelectionContext selectionContext)
{ return AABBs.get(state.get(EASTWEST) ? 0x1 : 0x0); }
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext selectionContext)
{ return getShape(state, world, pos, selectionContext); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(EASTWEST, RIGHTBEAM, LEFTBEAM, DOWNCONNECT, WATERLOGGED); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return temp_block_update_until_better(super.getStateForPlacement(context).with(EASTWEST, context.getPlacementHorizontalFacing().getAxis()==Direction.Axis.X), context.getWorld(), context.getPos()); }
private BlockState temp_block_update_until_better(BlockState state, IWorld world, BlockPos pos)
{
boolean ew = state.get(EASTWEST);
final BlockState rstate = world.getBlockState((!ew) ? (pos.east()) : (pos.south()) );
final BlockState lstate = world.getBlockState((!ew) ? (pos.west()) : (pos.north()) );
final BlockState dstate = world.getBlockState(pos.down());
int down_connector = 0;
if((dstate.getBlock() instanceof BlockDecorStraightPole)) {
final Direction dfacing = dstate.get(BlockDecorStraightPole.FACING);
final BlockDecorStraightPole pole = (BlockDecorStraightPole)dstate.getBlock();
if((dfacing.getAxis() == Direction.Axis.Y)) {
if((pole== ModContent.THICK_STEEL_POLE) || ((pole==ModContent.THICK_STEEL_POLE_HEAD) && (dfacing==Direction.UP))) {
down_connector = 2;
} else if((pole==ModContent.THIN_STEEL_POLE) || ((pole==ModContent.THIN_STEEL_POLE_HEAD) && (dfacing==Direction.UP))) {
down_connector = 1;
}
}
}
return state.with(RIGHTBEAM, (rstate.getBlock()==this) && (rstate.get(EASTWEST) != ew))
.with(LEFTBEAM , (lstate.getBlock()==this) && (lstate.get(EASTWEST) != ew))
.with(DOWNCONNECT , down_connector);
}
@Override
@SuppressWarnings("deprecation")
public BlockState updatePostPlacement(BlockState state, Direction facing, BlockState facingState, IWorld world, BlockPos pos, BlockPos facingPos)
{ return temp_block_update_until_better(state, world, pos); }
@Deprecated
@SuppressWarnings("deprecation")
public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos)
{ world.setBlockState(pos, temp_block_update_until_better(state, world, pos)); }
@Override
@SuppressWarnings("deprecation")
public BlockState rotate(BlockState state, Rotation rot)
{ return (rot==Rotation.CLOCKWISE_180) ? state : state.with(EASTWEST, !state.get(EASTWEST)); }
@Override
@SuppressWarnings("deprecation")
public BlockState mirror(BlockState state, Mirror mirrorIn)
{ return state; }
}

View file

@ -0,0 +1,102 @@
/*
* @file BlockDecorLadder.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Ladder block. The implementation is based on the vanilla
* net.minecraft.block.BlockLadder. Minor changes to enable
* later configuration (for block list based construction
* time configuration), does not drop when the block behind
* is broken, etc.
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.detail.ModAuxiliaries;
import net.minecraft.fluid.IFluidState;
import net.minecraft.world.Explosion;
import net.minecraft.world.World;
import net.minecraft.entity.EntityType;
import net.minecraft.util.math.Vec3d;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.block.BlockState;
import net.minecraft.block.*;
import net.minecraft.block.material.PushReaction;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.IBlockReader;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import java.util.List;
public class BlockDecorLadder extends LadderBlock implements IDecorBlock
{
protected static final AxisAlignedBB EDLADDER_UNROTATED_AABB = ModAuxiliaries.getPixeledAABB(3, 0, 0, 13, 16, 3);
protected static final VoxelShape EDLADDER_SOUTH_AABB = VoxelShapes.create(ModAuxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.SOUTH, false));
protected static final VoxelShape EDLADDER_EAST_AABB = VoxelShapes.create(ModAuxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.EAST, false));
protected static final VoxelShape EDLADDER_WEST_AABB = VoxelShapes.create(ModAuxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.WEST, false));
protected static final VoxelShape EDLADDER_NORTH_AABB = VoxelShapes.create(ModAuxiliaries.getRotatedAABB(EDLADDER_UNROTATED_AABB, Direction.NORTH, false));
private static boolean without_speed_boost_ = false;
public static void on_config(boolean without_speed_boost)
{ without_speed_boost_ = without_speed_boost; }
public BlockDecorLadder(long config, Block.Properties builder)
{ super(builder); }
@Override
public RenderTypeHint getRenderTypeHint()
{ return RenderTypeHint.CUTOUT; }
@Override
@OnlyIn(Dist.CLIENT)
public void addInformation(ItemStack stack, @Nullable IBlockReader world, List<ITextComponent> tooltip, ITooltipFlag flag)
{ ModAuxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true); }
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos)
{
switch ((Direction)state.get(FACING)) {
case NORTH: return EDLADDER_NORTH_AABB;
case SOUTH: return EDLADDER_SOUTH_AABB;
case WEST: return EDLADDER_WEST_AABB;
default: return EDLADDER_EAST_AABB;
}
}
@Override
public boolean canSpawnInBlock()
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canEntitySpawn(BlockState state, IBlockReader world, BlockPos pos, EntityType<?> entityType)
{ return false; }
@Override
@SuppressWarnings("deprecation")
public PushReaction getPushReaction(BlockState state)
{ return PushReaction.NORMAL; }
// Player update event, forwarded from the main mod instance.
public static void onPlayerUpdateEvent(final PlayerEntity player)
{
if((without_speed_boost_) || (player.onGround) || (!player.isOnLadder()) || (player.func_225608_bj_()/*isSneaking()*/) || (player.isSpectator())) return;
double lvy = player.getLookVec().y;
if(Math.abs(lvy) < 0.94) return;
final BlockPos pos = player.getPosition();
final BlockState state = player.world.getBlockState(pos);
if(!(state.getBlock() instanceof BlockDecorLadder)) return;
player.fallDistance = 0;
player.setMotionMultiplier(state, new Vec3d(0.2, (lvy>0)?(3):(6), 0.2));
}
}

View file

@ -0,0 +1,627 @@
/*
* @file BlockDecorMilker.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2019 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Frequently attracts and milks nearby cows
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.detail.ExtItems;
import wile.engineersdecor.detail.ItemHandling;
import net.minecraft.world.World;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.IBlockReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.entity.CreatureEntity;
import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.passive.CowEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.*;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.*;
import net.minecraft.util.math.*;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.wrapper.PlayerMainInvWrapper;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.Map.Entry;
public class BlockDecorMilker extends BlockDecorDirectedHorizontal
{
public static final BooleanProperty FILLED = BooleanProperty.create("filled");
public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
public BlockDecorMilker(long config, Block.Properties builder, final AxisAlignedBB unrotatedAABB)
{ super(config, builder, unrotatedAABB); }
@Override
protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder)
{ super.fillStateContainer(builder); builder.add(ACTIVE); builder.add(FILLED); }
@Override
@Nullable
public BlockState getStateForPlacement(BlockItemUseContext context)
{ return super.getStateForPlacement(context).with(FILLED, false).with(ACTIVE, false); }
@Override
@SuppressWarnings("deprecation")
public boolean hasComparatorInputOverride(BlockState state)
{ return true; }
@Override
@SuppressWarnings("deprecation")
public int getComparatorInputOverride(BlockState state, World world, BlockPos pos)
{
BTileEntity te = getTe(world, pos);
return (te==null) ? 0 : MathHelper.clamp((16 * te.fluid_level())/BTileEntity.TANK_CAPACITY, 0, 15);
}
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@Override
@Nullable
public TileEntity createTileEntity(BlockState state, IBlockReader world)
{ return new BTileEntity(); }
@Override
@SuppressWarnings("deprecation")
public boolean onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit)
{
if(world.isRemote) return true;
BTileEntity te = getTe(world, pos);
if(te==null) return true;
final ItemStack in_stack = player.getHeldItem(hand);
final ItemStack out_stack = BTileEntity.milk_filled_container_item(in_stack);
if(out_stack.isEmpty() && (te.fluid_handler()!=null)) return FluidUtil.interactWithFluidHandler(player, hand, te.fluid_handler());
boolean drained = false;
IItemHandler player_inventory = new PlayerMainInvWrapper(player.inventory);
if(te.fluid_level() >= BTileEntity.BUCKET_SIZE) {
final ItemStack insert_stack = out_stack.copy();
ItemStack remainder = ItemHandlerHelper.insertItemStacked(player_inventory, insert_stack, false);
if(remainder.getCount() < insert_stack.getCount()) {
te.drain(BTileEntity.BUCKET_SIZE);
in_stack.shrink(1);
drained = true;
if(remainder.getCount() > 0) {
final ItemEntity ei = new ItemEntity(world, player.getPosition().getX(), player.getPosition().getY()+0.5, player.getPosition().getZ(), remainder);
ei.setPickupDelay(40);
ei.setMotion(0,0,0);
world.addEntity(ei);
}
}
}
if(drained) {
world.playSound(null, pos, SoundEvents.ITEM_BUCKET_FILL, SoundCategory.BLOCKS, 0.8f, 1f);
}
return true;
}
@Nullable
private BTileEntity getTe(World world, BlockPos pos)
{ final TileEntity te=world.getTileEntity(pos); return (!(te instanceof BTileEntity)) ? (null) : ((BTileEntity)te); }
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BTileEntity extends TileEntity implements ITickableTileEntity, IEnergyStorage, ICapabilityProvider
{
public static final int BUCKET_SIZE = 1000;
public static final int TICK_INTERVAL = 80;
public static final int PROCESSING_TICK_INTERVAL = 20;
public static final int TANK_CAPACITY = BUCKET_SIZE * 12;
public static final int MAX_MILKING_TANK_LEVEL = TANK_CAPACITY-500;
public static final int FILLED_INDICATION_THRESHOLD = BUCKET_SIZE;
public static final int MAX_ENERGY_BUFFER = 16000;
public static final int MAX_ENERGY_TRANSFER = 512;
public static final int DEFAULT_ENERGY_CONSUMPTION = 0;
private static final Direction FLUID_TRANSFER_DIRECTRIONS[] = {Direction.DOWN,Direction.EAST,Direction.SOUTH,Direction.WEST,Direction.NORTH};
private enum MilkingState { IDLE, PICKED, COMING, POSITIONING, MILKING, LEAVING, WAITING }
private static FluidStack milk_fluid_ = new FluidStack(Fluids.WATER, 0);
private static HashMap<ItemStack, ItemStack> milk_containers_ = new HashMap<>();
private static int energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
private int tick_timer_;
private int energy_stored_;
private int tank_level_ = 0;
private UUID tracked_cow_ = null;
private MilkingState state_ = MilkingState.IDLE;
private int state_timeout_ = 0;
private int state_timer_ = 0;
private BlockPos tracked_cow_original_position_ = null;
public static void on_config(int energy_consumption_per_tick)
{
energy_consumption = MathHelper.clamp(energy_consumption_per_tick, 0, 128);
{
Fluid milk = null; // FluidRe.getFluid("milk");
if(milk != null) milk_fluid_ = new FluidStack(milk, BUCKET_SIZE);
}
{
milk_containers_.put(new ItemStack(Items.BUCKET), new ItemStack(Items.MILK_BUCKET));
if(ExtItems.BOTTLED_MILK_BOTTLE_DRINKLABLE!=null) milk_containers_.put(new ItemStack(Items.GLASS_BOTTLE), new ItemStack(ExtItems.BOTTLED_MILK_BOTTLE_DRINKLABLE));
}
ModEngineersDecor.logger().info(
"Config milker energy consumption:" + energy_consumption + "rf/t"
+ ((milk_fluid_==null)?"":" [milk fluid available]")
+ ((ExtItems.BOTTLED_MILK_BOTTLE_DRINKLABLE==null)?"":" [bottledmilk mod available]")
);
}
public BTileEntity()
{ this(ModContent.TET_SMALL_MILKING_MACHINE); }
public BTileEntity(TileEntityType<?> te_type)
{ super(te_type); reset(); }
public void reset()
{
tank_level_ = 0;
energy_stored_ = 0;
tick_timer_ = 0;
tracked_cow_ = null;
state_ = MilkingState.IDLE;
state_timeout_ = 0;
}
public CompoundNBT destroy_getnbt()
{
final UUID cowuid = tracked_cow_;
CompoundNBT nbt = new CompoundNBT();
writenbt(nbt, false); reset();
if(cowuid == null) return nbt;
world.getEntitiesWithinAABB(CowEntity.class, new AxisAlignedBB(pos).grow(16, 16, 16), e->e.getUniqueID().equals(cowuid)).forEach(e->e.setNoAI(false));
return nbt;
}
public void readnbt(CompoundNBT nbt, boolean update_packet)
{
tank_level_ = nbt.getInt("tank");
energy_stored_ = nbt.getInt("energy");
}
protected void writenbt(CompoundNBT nbt, boolean update_packet)
{
if(tank_level_ > 0) nbt.putInt("tank", tank_level_);
if(energy_stored_ > 0) nbt.putInt("energy", energy_stored_ );
}
private IFluidHandler fluid_handler()
{ return fluid_handler_.orElse(null); }
private int fluid_level()
{ return MathHelper.clamp(tank_level_, 0, TANK_CAPACITY); }
private void drain(int amount)
{ tank_level_ = MathHelper.clamp(tank_level_-BUCKET_SIZE, 0, TANK_CAPACITY); markDirty(); }
// TileEntity ------------------------------------------------------------------------------
@Override
public void read(CompoundNBT nbt)
{ super.read(nbt); readnbt(nbt, false); }
@Override
public CompoundNBT write(CompoundNBT nbt)
{ super.write(nbt); writenbt(nbt, false); return nbt; }
// IEnergyStorage ----------------------------------------------------------------------------
protected LazyOptional<IEnergyStorage> energy_handler_ = LazyOptional.of(() -> (IEnergyStorage)this);
@Override public boolean canExtract() { return false; }
@Override public boolean canReceive() { return true; }
@Override public int getMaxEnergyStored() { return MAX_ENERGY_BUFFER; }
@Override public int getEnergyStored() { return energy_stored_; }
@Override public int extractEnergy(int maxExtract, boolean simulate) { return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{
if(energy_stored_ >= MAX_ENERGY_BUFFER) return 0;
int n = Math.min(maxReceive, (MAX_ENERGY_BUFFER - energy_stored_));
if(n > MAX_ENERGY_TRANSFER) n = MAX_ENERGY_TRANSFER;
if(!simulate) {energy_stored_ += n; markDirty(); }
return n;
}
// IFluidHandler / IFluidTankProperties ---------------------------------------------------------------------
private LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> (IFluidHandler)new BFluidHandler(this));
private static class BFluidHandler implements IFluidHandler
{
private final BTileEntity te;
BFluidHandler(BTileEntity te) { this.te = te; }
@Override public int getTanks() { return 1; }
@Override public FluidStack getFluidInTank(int tank) { return new FluidStack(milk_fluid_, te.fluid_level()); }
@Override public int getTankCapacity(int tank) { return TANK_CAPACITY; }
@Override public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return false; }
@Override public int fill(FluidStack resource, FluidAction action) { return 0; }
@Override
public FluidStack drain(FluidStack resource, FluidAction action)
{ return (!resource.isFluidEqual(milk_fluid_)) ? (FluidStack.EMPTY) : drain(resource.getAmount(), action); }
@Override
public FluidStack drain(int maxDrain, FluidAction action)
{
if(te.fluid_level() <= 0) return FluidStack.EMPTY;
FluidStack fs = milk_fluid_.copy();
fs.setAmount(Math.min(fs.getAmount(), te.fluid_level()));
if(action==FluidAction.EXECUTE) te.tank_level_ -= fs.getAmount();
return fs;
}
}
// ICapabilityProvider ---------------------------------------------------------------------------
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(!this.removed && (facing != null)) {
if((capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) && (!milk_fluid_.isEmpty())) {
return fluid_handler_.cast();
} else if((capability == CapabilityEnergy.ENERGY) && (energy_consumption>0)) {
return energy_handler_.cast();
}
}
return super.getCapability(capability, facing);
}
// ITickable ------------------------------------------------------------------------------------
private void log(String s)
{} // println("Milker|" + s); may be enabled with config, for dev was println
private static ItemStack milk_filled_container_item(ItemStack stack)
{ return milk_containers_.entrySet().stream().filter(e->e.getKey().isItemEqual(stack)).map(Map.Entry::getValue).findFirst().orElse(ItemStack.EMPTY); }
private void fill_adjacent_inventory_item_containers(Direction block_facing)
{
// Check inventory existence, back to down is preferred, otherwise sort back into same inventory.
IItemHandler src = ItemHandling.itemhandler(world, pos.offset(block_facing), block_facing.getOpposite());
IItemHandler dst = ItemHandling.itemhandler(world, pos.down(), Direction.UP);
if(src==null) { src = dst; } else if(dst==null) { dst = src; }
if((src==null) || (dst==null)) return;
while((tank_level_ >= BUCKET_SIZE)) {
boolean inserted = false;
for(Entry<ItemStack,ItemStack> e:milk_containers_.entrySet()) {
if(ItemHandling.extract(src, e.getKey(), 1, true).isEmpty()) continue;
if(!ItemHandling.insert(dst, e.getValue().copy(), false).isEmpty()) continue;
ItemHandling.extract(src, e.getKey(), 1, false);
tank_level_ -= BUCKET_SIZE;
inserted = true;
}
if(!inserted) break;
}
}
private void release_cow(CowEntity cow)
{
log("release cow");
if(cow != null) {
cow.setNoAI(false);
SingleMoveGoal.abortFor(cow);
}
tracked_cow_ = null;
state_ = MilkingState.IDLE;
tick_timer_ = TICK_INTERVAL;
}
private boolean milking_process()
{
if((tracked_cow_ == null) && (fluid_level() >= MAX_MILKING_TANK_LEVEL)) return false; // nothing to do
final Direction facing = world.getBlockState(getPos()).get(HORIZONTAL_FACING).getOpposite();
final Vec3d target_pos = new Vec3d(getPos().offset(facing)).add(0.5,0,0.5);
CowEntity cow = null;
{
AxisAlignedBB aabb = new AxisAlignedBB(pos.offset(facing, 3)).grow(4, 2, 4);
final List<CowEntity> cows = world.getEntitiesWithinAABB(CowEntity.class, aabb,
e->( ((tracked_cow_==null) && ((!e.isChild()) && (!e.isInLove()) && (!e.isBeingRidden()))) || (e.getUniqueID().equals(tracked_cow_)) )
);
if(cows.size() == 1) {
cow = cows.get(0); // tracked or only one
} else if(cows.size() > 1) {
cow = cows.get(world.rand.nextInt(cows.size()-1)); // pick one
}
}
if((state_ != MilkingState.IDLE) && ((state_timeout_ -= PROCESSING_TICK_INTERVAL) <= 0)) { release_cow(cow); log("Cow motion timeout"); cow = null; }
if((cow == null) || (!cow.isAlive())) { release_cow(cow); cow = null; }
if(tracked_cow_ == null) state_ = MilkingState.IDLE;
if(cow == null) { log("Init: No cow"); return false; } // retry next cycle
tick_timer_ = PROCESSING_TICK_INTERVAL;
state_timer_ -= PROCESSING_TICK_INTERVAL;
if(state_timer_ > 0) return false;
switch(state_) { // Let's do this the old school FSA sequencing way ...
case IDLE: {
final List<LivingEntity> blocking_entities = world.getEntitiesWithinAABB(LivingEntity.class, new AxisAlignedBB(pos.offset(facing)).grow(0.5, 0.5, 0.5));
if(blocking_entities.size() > 0) {
tick_timer_ = TICK_INTERVAL;
log("Idle: Position blocked");
if(blocking_entities.get(0) instanceof CowEntity) {
CowEntity blocker = (CowEntity)blocking_entities.get(0);
BlockPos p = getPos().offset(facing,2);
log("Idle: Shove off");
blocker.setNoAI(false);
SingleMoveGoal.startFor(blocker, p, 2, 1.0, (goal, world, pos)->(pos.distanceSq(goal.getCreature().getPosition())>49));
}
return false;
}
if(cow.getLeashed() || cow.isChild() || cow.isInLove() || (!cow.onGround) || cow.isBeingRidden() || cow.isSprinting()) return false;
tracked_cow_ = cow.getUniqueID();
state_ = MilkingState.PICKED;
state_timeout_ = 200;
tracked_cow_original_position_ = cow.getPosition();
log("Idle: Picked cow " + tracked_cow_);
return false;
}
case PICKED: {
SingleMoveGoal.startFor(
cow, target_pos, 2, 1.0,
(goal, world, pos)->{
if(pos.distanceSq(goal.getCreature().getPosition())>100) return true;
for(int i=0; i<4; ++i) {
if(world.getBlockState(pos.offset(Direction.byHorizontalIndex(i))).getBlock() instanceof BlockDecorMilker) return false;
}
return true;
},
(goal, world, pos)->{
log("move: position reached");
goal.getCreature().setLocationAndAngles(goal.getTargetPosition().getX(), goal.getTargetPosition().getY(), goal.getTargetPosition().getZ(), facing.getHorizontalAngle(), 0);
},
(goal, world, pos)->{
log("move: aborted");
}
);
state_ = MilkingState.COMING;
state_timeout_ = 400; // 15s should be enough
log("Picked: coming to " + target_pos);
return false;
}
case COMING: {
if(target_pos.squareDistanceTo(cow.getPositionVec()) <= 1) {
log("Coming: position reached");
state_ = MilkingState.POSITIONING;
state_timeout_ = 100; // 5s
} else if((!SingleMoveGoal.isActiveFor(cow))) {
release_cow(cow);
log("Coming: aborted");
} else {
state_timeout_ -= 100;
}
return false;
}
case POSITIONING: {
log("Positioning: start milking");
cow.setNoAI(true);
cow.setLocationAndAngles(target_pos.getX(), target_pos.getY(), target_pos.getZ(), facing.getHorizontalAngle(), 0);
world.playSound(null, pos, SoundEvents.ENTITY_COW_MILK, SoundCategory.BLOCKS, 0.5f, 1f);
state_timeout_ = 600;
state_ = MilkingState.MILKING;
state_timer_ = 30;
return false;
}
case MILKING: {
tank_level_ = MathHelper.clamp(tank_level_+BUCKET_SIZE, 0, TANK_CAPACITY);
state_timeout_ = 600;
state_ = MilkingState.LEAVING;
state_timer_ = 20;
cow.setNoAI(false);
cow.getNavigator().clearPath();
log("Milking: done, leave");
return true;
}
case LEAVING: {
BlockPos p = (tracked_cow_original_position_ != null) ? (tracked_cow_original_position_) : getPos().offset(facing,2).offset(facing.rotateYCCW());
SingleMoveGoal.startFor(cow, p, 2, 1.0, (goal, world, pos)->(pos.distanceSq(goal.getCreature().getPosition())>100));
state_timeout_ = 600;
state_timer_ = 500;
tick_timer_ = TICK_INTERVAL;
state_ = MilkingState.WAITING;
log("Leaving: process done");
return true;
}
case WAITING: {
// wait for the timeout to kick in until starting with the next.
tick_timer_ = TICK_INTERVAL;
log("Waiting: ...");
return true;
}
default: {
release_cow(cow);
}
}
return (tracked_cow_ != null);
}
@Override
public void tick()
{
if((world.isRemote) || ((--tick_timer_ > 0))) return;
tick_timer_ = TICK_INTERVAL;
boolean dirty = false;
final BlockState block_state = world.getBlockState(pos);
if(!world.isBlockPowered(pos) || (state_ != MilkingState.IDLE)) {
if(energy_consumption > 0) {
if(energy_stored_ <= 0) return;
energy_stored_ = MathHelper.clamp(energy_stored_-energy_consumption, 0, MAX_ENERGY_BUFFER);
}
// Track and milk cows
if(milking_process()) dirty = true;
// Fluid transfer
if((milk_fluid_.getAmount() > 0) && (fluid_level() >= BUCKET_SIZE)) {
log("Fluid transfer");
for(Direction facing: FLUID_TRANSFER_DIRECTRIONS) {
IFluidHandler fh = FluidUtil.getFluidHandler(world, pos.offset(facing), facing.getOpposite()).orElse(null);
if(fh == null) continue;
FluidStack fs = milk_fluid_.copy();
fs.setAmount(BUCKET_SIZE);
int nfilled = MathHelper.clamp(fh.fill(fs, FluidAction.EXECUTE), 0, BUCKET_SIZE);
if(nfilled <= 0) continue;
tank_level_ -= nfilled;
if(tank_level_ < 0) tank_level_ = 0;
dirty = true;
break;
}
}
// Adjacent inventory update, only done just after milking to prevent waste of server cpu.
if(dirty && (fluid_level() >= BUCKET_SIZE)) {
log("Try item transfer");
fill_adjacent_inventory_item_containers(block_state.get(HORIZONTAL_FACING));
}
}
// State update
BlockState new_state = block_state.with(FILLED, fluid_level()>=FILLED_INDICATION_THRESHOLD).with(ACTIVE, state_==MilkingState.MILKING);
if(block_state != new_state) world.setBlockState(pos, new_state,1|2|16);
if(dirty) markDirty();
}
}
public static class SingleMoveGoal extends net.minecraft.entity.ai.goal.MoveToBlockGoal
{
@FunctionalInterface public interface TargetPositionInValidCheck { boolean test(SingleMoveGoal goal, IWorldReader world, BlockPos pos); }
@FunctionalInterface public interface StrollEvent { void apply(SingleMoveGoal goal, IWorldReader world, Vec3d pos); }
private static void log(String s) {} // println(s);
private static final int motion_timeout = 20*20;
private boolean aborted_;
private boolean in_position_;
private boolean was_aborted_;
private Vec3d target_pos_;
private TargetPositionInValidCheck abort_condition_;
private StrollEvent on_target_position_reached_;
private StrollEvent on_aborted_;
public SingleMoveGoal(CreatureEntity creature, Vec3d pos, double speed, TargetPositionInValidCheck abort_condition, @Nullable StrollEvent on_position_reached, @Nullable StrollEvent on_aborted)
{
super(creature, speed, 32, 32);
abort_condition_ = abort_condition;
on_target_position_reached_ = on_position_reached;
on_aborted_ = on_aborted;
destinationBlock = new BlockPos(pos.getX(), pos.getY(), pos.getZ());
timeoutCounter = 0;
runDelay = 0;
aborted_ = false;
was_aborted_ = false;
target_pos_ = pos;
}
public static void startFor(CreatureEntity entity, BlockPos target_pos, int priority, double speed, TargetPositionInValidCheck abort_condition)
{ startFor(entity, new Vec3d(target_pos.getX(),target_pos.getY(),target_pos.getZ()), priority, speed, abort_condition, null, null); }
public static void startFor(CreatureEntity entity, Vec3d target_pos, int priority, double speed, TargetPositionInValidCheck abort_condition, @Nullable StrollEvent on_position_reached, @Nullable StrollEvent on_aborted)
{ entity.goalSelector.addGoal(priority, new SingleMoveGoal(entity, target_pos, speed, abort_condition, on_position_reached, on_aborted)); }
public static boolean isActiveFor(CreatureEntity entity)
{ return (entity != null) && (entity.goalSelector.getRunningGoals().anyMatch(g->(g.getGoal()) instanceof SingleMoveGoal)); }
public static void abortFor(CreatureEntity entity)
{ entity.goalSelector.getRunningGoals().filter(g->(g.getGoal()) instanceof SingleMoveGoal).forEach(g->((SingleMoveGoal)g.getGoal()).abort()); }
public Vec3d getTargetPosition()
{ return target_pos_; }
public CreatureEntity getCreature()
{ return creature; }
public void abort()
{ aborted_ = true; }
@Override
public void resetTask()
{ runDelay = 0; timeoutCounter = 0; }
@Override
public double getTargetDistanceSq()
{ return 1.2; }
@Override
public boolean shouldMove()
{ return (timeoutCounter & 0x7) == 0; }
@Override
public boolean shouldExecute()
{
if(!shouldMoveTo(creature.world, destinationBlock)) {
aborted_ = true;
return false;
} else if(aborted_) {
// shouldExecute is the point where in GoalSelector.tick() the goal is not in flagGoals and can be removed.
creature.goalSelector.getRunningGoals().filter(g->(g.getGoal()) instanceof SingleMoveGoal).forEach(g->creature.goalSelector.removeGoal(g));
creature.goalSelector.removeGoal(this);
if((!was_aborted_) && (on_aborted_!=null)) on_aborted_.apply(this, creature.world, target_pos_);
was_aborted_ = true;
return false;
} else if(--runDelay > 0) {
return false;
} else {
runDelay = 10;
return true;
}
}
@Override
public void startExecuting()
{
log("startExecuting()");
timeoutCounter = 0;
if(!creature.getNavigator().tryMoveToXYZ(target_pos_.getX(), target_pos_.getY(), target_pos_.getZ(), this.movementSpeed)) abort();
}
public boolean shouldContinueExecuting()
{
if((aborted_) || (creature.getNavigator().noPath()) || (timeoutCounter > motion_timeout) || (!shouldMoveTo(creature.world, destinationBlock))) {
abort();
return false;
}
return true;
}
@Override
protected boolean shouldMoveTo(IWorldReader world, BlockPos pos)
{ if(!abort_condition_.test(this, world, pos)) { return true; } abort(); return false; }
@Override
public void tick()
{
BlockPos testpos = new BlockPos(target_pos_.getX(), creature.getPositionVec().getY(), target_pos_.getZ());
if(!testpos.withinDistance(creature.getPositionVec(), getTargetDistanceSq())) {
if((++timeoutCounter > motion_timeout)) { abort(); return; }
if(shouldMove() && (!creature.getNavigator().tryMoveToXYZ(target_pos_.getX(), target_pos_.getY(), target_pos_.getZ(), movementSpeed))) abort();
} else {
in_position_ = true;
abort();
if(on_target_position_reached_ != null) on_target_position_reached_.apply(this, creature.world, target_pos_);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show more