Clinker Brick alternative brick-swapped recipe added. Treated Wood Ladder with TW block H recipe. Furnace XP handling simplified. Crafting Table inventory sync forced for open containers, slot sync seems not to be enough. Prevented strong redstone power propagation for device blocks. Labeled Crate item Storage librarized. Fluid Funnel librarized. Inventories item handlers implemented. RF handling library. Furnace uses lib battery. Furnace item handlers librarized. Labeled Crate Tooltip refined. Crafting Table quick move when grid is placed. Forcing tooltip RE replacement escape to circumvent mixin cross-compat problems (issue #151).

This commit is contained in:
stfwi 2020-12-27 10:14:50 +01:00
parent d4d685693b
commit 98529fd961
33 changed files with 1096 additions and 1241 deletions

View file

@ -4,5 +4,5 @@ org.gradle.jvmargs=-Xmx8G
version_minecraft=1.16.4
version_forge_minecraft=1.16.4-35.1.10
version_fml_mappings=20201028-1.16.3
version_jei=1.16.4:7.6.0.58
version_engineersdecor=1.1.6-b1
version_jei=1.16.4:7.6.1.63
version_engineersdecor=1.1.6-b2

View file

@ -1,6 +1,7 @@
{
"homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/",
"1.16.4": {
"1.1.6-b2": "[M] Alternative Clinker Brick recipe (swapped Bricks/Nether Bricks) added.\n[M] Furnace XP handling simplified (simply stores/releases XP for each smelting process).\n[M] Mod devices do not propagate strong Redstone power to adjacent blocks.\n[M] Minor \"librarizing\" changes under the hood.",
"1.1.6-b1": "[F] Fixed Metal Crafting Table Hopper access (issue #147, ty umerrr).\n[F] Fixed Dark Shingle Roof Chimney placement restriction (issue #149, thx WenXin20).\n[F] Door tags added for Wood Door and Metal Sliding Door (issue #150, thx WenXin20).\n[A] Electrical Furnace automatically chokes speed and power consumption when the internally stored power is below 20%.",
"1.1.5": "[R] Release build v1.1.5.\n[F] Fixed Crafting Table JEI storage slot count.\n[F] Fixed Factory Hopper removed item collection dupe bug (issue #146, thx FatheredPuma81).\n[F] Increased device GUI access ranges beyond the player block selection range.\n[A] Window placement handling improved.\n[M] Steel/Wood Pole and Double-T support placement improved (issue #139, thx Biviho).\n[M] Metal Sliding Door bottom/top shape when opened added.",
"1.1.4": "[R] Release build v1.1.4.\n[F] Solar Panel balancing threshold tuned.\n[F] Fixed Catwalk default state (issue #140, thx hvdklauw).\n[M] Updated lang ru_ru file (PR#137, Smollet777).\n[M] Factory Dropper: Added Ignore-External-Redstone mode.",
@ -22,6 +23,6 @@
},
"promos": {
"1.16.4-recommended": "1.1.5",
"1.16.4-latest": "1.1.6-b1"
"1.16.4-latest": "1.1.6-b2"
}
}

View file

@ -11,6 +11,11 @@ Mod sources for Minecraft version 1.16.x.
## Version history
- v1.1.6-b2 [M] Alternative Clinker Brick recipe (swapped Bricks/Nether Bricks) added.
[M] Furnace XP handling simplified (simply stores/releases XP for each smelting process).
[M] Mod devices do not propagate strong Redstone power to adjacent blocks.
[M] Minor "librarizing" changes under the hood.
- v1.1.6-b1 [F] Fixed Metal Crafting Table Hopper access (issue #147, ty umerrr).
[F] Fixed Dark Shingle Roof Chimney placement restriction (issue #149, thx WenXin20).
[F] Door tags added for Wood Door and Metal Sliding Door (issue #150, thx WenXin20).

View file

@ -151,9 +151,9 @@ public class ModConfig
public final ForgeConfigSpec.IntValue block_breaker_reluctance;
public final ForgeConfigSpec.IntValue block_breaker_min_breaking_time;
public final ForgeConfigSpec.BooleanValue block_breaker_requires_power;
public final ForgeConfigSpec.IntValue tree_cuttter_energy_consumption;
public final ForgeConfigSpec.IntValue tree_cuttter_cutting_time_needed;
public final ForgeConfigSpec.BooleanValue tree_cuttter_requires_power;
public final ForgeConfigSpec.IntValue tree_cutter_energy_consumption;
public final ForgeConfigSpec.IntValue tree_cutter_cutting_time_needed;
public final ForgeConfigSpec.BooleanValue tree_cutter_requires_power;
public final ForgeConfigSpec.IntValue milking_machine_energy_consumption;
public final ForgeConfigSpec.IntValue milking_machine_milking_delay;
@ -459,21 +459,21 @@ public class ModConfig
.translation(MODID + ".config.block_breaker_requires_power")
.comment("Defines if the Small Block Breaker does not work without RF power.")
.define("block_breaker_requires_power", false);
tree_cuttter_energy_consumption = builder
.translation(MODID + ".config.tree_cuttter_energy_consumption")
tree_cutter_energy_consumption = builder
.translation(MODID + ".config.tree_cutter_energy_consumption")
.comment("Defines how much RF power the Small Tree Cutter requires to magnificently increase the processing speed. " +
"The config value can be changed on-the-fly for tuning.")
.defineInRange("tree_cuttter_energy_consumption", EdTreeCutter.TreeCutterTileEntity.DEFAULT_BOOST_ENERGY, 4, 1024);
tree_cuttter_cutting_time_needed = builder
.translation(MODID + ".config.tree_cuttter_cutting_time_needed")
.defineInRange("tree_cutter_energy_consumption", EdTreeCutter.TreeCutterTileEntity.DEFAULT_BOOST_ENERGY, 4, 1024);
tree_cutter_cutting_time_needed = builder
.translation(MODID + ".config.tree_cutter_cutting_time_needed")
.comment("Defines how much time the Small Tree Cutter needs to cut a tree without RF power. " +
"The value is in seconds. With energy it is 6 times faster. " +
"The config value can be changed on-the-fly for tuning.")
.defineInRange("tree_cuttter_cutting_time_needed", EdTreeCutter.TreeCutterTileEntity.DEFAULT_CUTTING_TIME_NEEDED, 10, 240);
tree_cuttter_requires_power = builder
.translation(MODID + ".config.tree_cuttter_requires_power")
.defineInRange("tree_cutter_cutting_time_needed", EdTreeCutter.TreeCutterTileEntity.DEFAULT_CUTTING_TIME_NEEDED, 10, 240);
tree_cutter_requires_power = builder
.translation(MODID + ".config.tree_cutter_requires_power")
.comment("Defines if the Small Tree Cutter does not work without RF power.")
.define("tree_cuttter_requires_power", false);
.define("tree_cutter_requires_power", false);
milking_machine_energy_consumption = builder
.translation(MODID + ".config.milking_machine_energy_consumption")
.comment("Defines how much time the Small Milking Machine needs work. " +
@ -671,7 +671,7 @@ public class ModConfig
EdElectricalFurnace.ElectricalFurnaceTileEntity.on_config(SERVER.e_furnace_speed_percent.get(), SERVER.e_furnace_power_consumption.get(), SERVER.e_furnace_automatic_pulling.get());
EdSolarPanel.SolarPanelTileEntity.on_config(SERVER.small_solar_panel_peak_production.get());
EdBreaker.BreakerTileEntity.on_config(SERVER.block_breaker_power_consumption.get(), SERVER.block_breaker_reluctance.get(), SERVER.block_breaker_min_breaking_time.get(), SERVER.block_breaker_requires_power.get());
EdTreeCutter.TreeCutterTileEntity.on_config(SERVER.tree_cuttter_energy_consumption.get(), SERVER.tree_cuttter_cutting_time_needed.get(), SERVER.tree_cuttter_requires_power.get());
EdTreeCutter.TreeCutterTileEntity.on_config(SERVER.tree_cutter_energy_consumption.get(), SERVER.tree_cutter_cutting_time_needed.get(), SERVER.tree_cutter_requires_power.get());
EdMilker.MilkerTileEntity.on_config(SERVER.milking_machine_energy_consumption.get(), SERVER.milking_machine_milking_delay.get());
EdSlabBlock.on_config(!SERVER.without_direct_slab_pickup.get());
EdSlabSliceBlock.on_config(!SERVER.without_direct_slab_pickup.get());
@ -683,7 +683,7 @@ public class ModConfig
// -----------------------------------------------------------------------------------------------------------------
{
// Check if the config is already synchronized or has to be synchronised.
server_config_.putBoolean("tree_cuttter_requires_power", SERVER.tree_cuttter_requires_power.get());
server_config_.putBoolean("tree_cutter_requires_power", SERVER.tree_cutter_requires_power.get());
server_config_.putBoolean("block_breaker_requires_power", SERVER.block_breaker_requires_power.get());
{
String s = String.join(",", optouts_);

View file

@ -42,6 +42,8 @@ import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.energy.IEnergyStorage;
import wile.engineersdecor.libmc.detail.RfEnergy;
import javax.annotation.Nullable;
import java.util.HashSet;
import java.util.List;
@ -135,7 +137,7 @@ public class EdBreaker
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class BreakerTileEntity extends TileEntity implements ITickableTileEntity, IEnergyStorage
public static class BreakerTileEntity extends TileEntity implements ITickableTileEntity
{
public static final int IDLE_TICK_INTERVAL = 40;
public static final int TICK_INTERVAL = 5;
@ -153,7 +155,8 @@ public class EdBreaker
private int active_timer_;
private int proc_time_elapsed_;
private int time_needed_;
private int energy_;
private final RfEnergy.Battery battery_;
private final LazyOptional<IEnergyStorage> energy_handler_;
public static void on_config(int boost_energy_per_tick, int breaking_time_per_hardness, int min_breaking_time_ticks, boolean power_required)
{
@ -166,19 +169,23 @@ public class EdBreaker
}
public BreakerTileEntity()
{ super(ModContent.TET_SMALL_BLOCK_BREAKER); }
{ this(ModContent.TET_SMALL_BLOCK_BREAKER); }
public BreakerTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
{
super(te_type);
battery_ = new RfEnergy.Battery(energy_max, boost_energy_consumption, 0);
energy_handler_ = battery_.createEnergyHandler();
}
public void block_updated()
{ if(tick_timer_ > 2) tick_timer_ = 2; }
public void readnbt(CompoundNBT nbt)
{ energy_ = nbt.getInt("energy"); }
{ battery_.load(nbt); }
private void writenbt(CompoundNBT nbt)
{ nbt.putInt("energy", energy_); }
{ battery_.save(nbt); }
public void state_message(PlayerEntity player)
{
@ -186,8 +193,7 @@ public class EdBreaker
if((proc_time_elapsed_ > 0) && (time_needed_ > 0)) {
progress = Integer.toString((int)MathHelper.clamp((((double)proc_time_elapsed_) / ((double)time_needed_) * 100), 0, 100));
}
String soc = Integer.toString(MathHelper.clamp((energy_*100/energy_max),0,100));
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_block_breaker.status", new Object[]{soc, energy_max, progress }));
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_block_breaker.status", new Object[]{battery_.getSOC(), energy_max, progress }));
}
// TileEntity ------------------------------------------------------------------------------
@ -207,38 +213,6 @@ public class EdBreaker
energy_handler_.invalidate();
}
// 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*2; }
@Override
public int getEnergyStored()
{ return energy_; }
@Override
public int extractEnergy(int maxExtract, boolean simulate)
{ return 0; }
@Override
public int receiveEnergy(int maxReceive, boolean simulate)
{
maxReceive = MathHelper.clamp(maxReceive, 0, Math.max(energy_max-energy_, 0));
if(!simulate) energy_ += maxReceive;
return maxReceive;
}
// Capability export ----------------------------------------------------------------------------
@Override
@ -349,8 +323,7 @@ public class EdBreaker
return;
}
time_needed_ = MathHelper.clamp((int)(target_state.getBlockHardness(world, pos) * breaking_reluctance) + min_breaking_time, min_breaking_time, MAX_BREAKING_TIME);
if(energy_ >= boost_energy_consumption) {
energy_ -= boost_energy_consumption;
if(battery_.draw(boost_energy_consumption)) {
proc_time_elapsed_ += TICK_INTERVAL * (1+BOOST_FACTOR);
time_needed_ += min_breaking_time * (3*BOOST_FACTOR/5);
active_timer_ = 2;

View file

@ -16,10 +16,12 @@ import net.minecraft.state.IntegerProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@ -67,6 +69,10 @@ public class EdChimneyBlock extends DecorBlock.Normal implements IDecorBlock
if(p != state.get(POWER)) world.setBlockState(pos, state.with(POWER, p), 2);
}
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)

View file

@ -88,6 +88,10 @@ public class EdCraftingTable
public CraftingTableBlock(long config, Block.Properties builder, final AxisAlignedBB[] unrotatedAABBs)
{ super(config, builder, unrotatedAABBs); }
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@ -269,8 +273,7 @@ public class EdCraftingTable
protected static final String ACTION_DECREASE_CRAFTING_STACKS = "dec-crafting-stacks";
public static final int CRAFTING_SLOTS_BEGIN = 0;
public static final int NUM_OF_CRAFTING_SLOTS = 9;
public static final int STORAGE_SLOTS_BEGIN = NUM_OF_CRAFTING_SLOTS;
public static final int CRAFTING_SLOTS_SIZE = 9;
public static final int NUM_OF_STORAGE_SLOTS = CraftingTableTileEntity.NUM_OF_STORAGE_SLOTS;
public static final int NUM_OF_STORAGE_ROWS = CraftingTableTileEntity.NUM_OF_STORAGE_ROWS;
@ -307,7 +310,7 @@ public class EdCraftingTable
matrix_.openInventory(player_);
crafting_result_range_= new InventoryRange(result_, 0, 1, 1);
crafting_grid_range_ = new InventoryRange(matrix_, 0, 9, 3);
block_storage_range_ = new InventoryRange(inventory_, STORAGE_SLOTS_BEGIN, NUM_OF_STORAGE_SLOTS, NUM_OF_STORAGE_ROWS);
block_storage_range_ = new InventoryRange(inventory_, CRAFTING_SLOTS_SIZE, NUM_OF_STORAGE_SLOTS, NUM_OF_STORAGE_ROWS);
player_storage_range_ = InventoryRange.fromPlayerStorage(player_);
player_hotbar_range_ = InventoryRange.fromPlayerHotbar(player_);
player_inventory_range_= InventoryRange.fromPlayerInventory(player_);
@ -334,7 +337,7 @@ public class EdCraftingTable
for(int x=0; x<9; ++x) {
addSlot(new Slot(pinv, x, 8+x*18, 168));
}
// container slotId 46..53 === TE slots 9..17 (storage)
// container slotId 46..63 === TE slots 9..27 (storage)
for(int y=0; y<2; ++y) {
for(int x=0; x<9; ++x) {
addSlot(new Slot(inventory_, 9+x+y*9, 8+x*18, 65+y*18));
@ -342,7 +345,6 @@ public class EdCraftingTable
}
if((!player_.world.isRemote) && (inventory_ instanceof CraftingTableTileEntity)) {
history_.read(((CraftingTableTileEntity)inventory_).history.copy());
syncHistory();
}
CRAFTING_SLOT_COORDINATES = ImmutableList.copyOf(slotpositions);
onCraftMatrixChanged(matrix_);
@ -377,7 +379,7 @@ public class EdCraftingTable
}
result_.setInventorySlotContents(0, stack);
player.connection.sendPacket(new SSetSlotPacket(windowId, 0, stack));
syncProperties();
sync();
} catch(Throwable exc) {
ModEngineersDecor.logger().error("Recipe failed:", exc);
}
@ -411,8 +413,8 @@ public class EdCraftingTable
ItemStack slotstack = slot.getStack();
ItemStack stack = slotstack.copy();
if(index == 0) {
if(!this.mergeItemStack(slotstack, 10, 46+NUM_OF_STORAGE_SLOTS, false)) return ItemStack.EMPTY;
wpc_.consume((world, pos)->slotstack.getItem().onCreated(slotstack, world, player));
if(!this.mergeItemStack(slotstack, 10, 46, true)) return ItemStack.EMPTY;
slot.onSlotChange(slotstack, stack);
} else if(index >= 10 && (index < 46)) {
if(!this.mergeItemStack(slotstack, 46, 46+NUM_OF_STORAGE_SLOTS, false)) return ItemStack.EMPTY;
@ -421,18 +423,11 @@ public class EdCraftingTable
} else if(!this.mergeItemStack(slotstack, 10, 46, false)) {
return ItemStack.EMPTY;
}
if(slotstack.isEmpty()) {
slot.putStack(ItemStack.EMPTY);
} else {
slot.onSlotChanged();
}
if(slotstack.getCount() == stack.getCount()) {
return ItemStack.EMPTY;
}
if(slotstack.isEmpty()) slot.putStack(ItemStack.EMPTY);
slot.onSlotChanged();
if((index != 0) && (slotstack.getCount() == stack.getCount())) return ItemStack.EMPTY;
ItemStack itemstack2 = slot.onTake(player, slotstack);
if(index == 0) {
player.dropItem(itemstack2, false);
}
if(index == 0) player.dropItem(itemstack2, false);
return stack;
}
@ -466,8 +461,15 @@ public class EdCraftingTable
@Override
public void onServerPacketReceived(int windowId, CompoundNBT nbt)
{
if(nbt.contains("history")) history_.read(nbt.getCompound("history"));
if(nbt.contains("hascollision")) has_recipe_collision_ = nbt.getBoolean("hascollision");
if(nbt.contains("history")) {
history_.read(nbt.getCompound("history"));
}
if(nbt.contains("hascollision")) {
has_recipe_collision_ = nbt.getBoolean("hascollision");
}
if(nbt.contains("inventory")) {
Inventories.readNbtStacks(nbt, "inventory", inventory_);
}
}
@Override
@ -479,22 +481,22 @@ public class EdCraftingTable
switch(nbt.getString("action")) {
case BUTTON_NEXT: {
history_.next();
syncHistory();
// implicitly clear the grid, so that the player can see the refab, and that no recipe is active.
if(clear_grid_to_storage(player)) changed = true;
if(clear_grid_to_player(player)) { changed = true; player_inventory_changed = true; }
if(crafting_grid_range_.move(block_storage_range_)) changed = true;
if(crafting_grid_range_.move(player_inventory_range_)) { changed = true; player_inventory_changed = true; }
sync();
} break;
case BUTTON_PREV: {
history_.prev();
syncHistory();
if(clear_grid_to_storage(player)) changed = true;
if(clear_grid_to_player(player)) { changed = true; player_inventory_changed = true; }
if(crafting_grid_range_.move(block_storage_range_)) changed = true;
if(crafting_grid_range_.move(player_inventory_range_)) { changed = true; player_inventory_changed = true; }
sync();
} break;
case BUTTON_CLEAR_GRID: {
history_.reset_selection();
syncHistory();
if(clear_grid_to_storage(player)) changed = true;
if(clear_grid_to_player(player)) { changed = true; player_inventory_changed = true; }
sync();
if(crafting_grid_range_.move(block_storage_range_)) changed = true;
if(crafting_grid_range_.move(player_inventory_range_)) { changed = true; player_inventory_changed = true; }
} break;
case ACTION_PLACE_CURRENT_HISTORY_SEL: {
if(place_stacks(
@ -550,8 +552,12 @@ public class EdCraftingTable
} else if(container_slot_id < 10) {
// from crafting grid to player inventory, we clear the grid here as this is most likely
// what is wanted in the end. Saves clicking the other grid stacks.
if(clear_grid_to_storage(player)) changed = true;
if(clear_grid_to_player(player)) { changed = true; player_inventory_changed = true; }
if(crafting_grid_range_.move(player_inventory_range_, true)) {
crafting_grid_range_.move(player_inventory_range_, false, false, true);
changed = true; player_inventory_changed = true;
}
if(crafting_grid_range_.move(block_storage_range_)) changed = true;
if(crafting_grid_range_.move(player_inventory_range_, true)) { changed = true; player_inventory_changed = true; }
break;
}
IInventory from_inventory;
@ -560,7 +566,7 @@ public class EdCraftingTable
if(container_slot_id >= 46) {
// from storage to player inventory
from_inventory = inventory_;
from_slot = container_slot_id - 46 + STORAGE_SLOTS_BEGIN;
from_slot = container_slot_id - 46 + CRAFTING_SLOTS_SIZE;
to_ranges = new InventoryRange[] {player_storage_range_, player_hotbar_range_};
} else {
// from player to storage (otherwise ACTION_PLACE_SHIFTCLICKED_STACK would have been used)
@ -606,32 +612,24 @@ public class EdCraftingTable
public CraftingHistory history()
{ return history_; }
private void syncHistory()
private void sync()
{
if(!with_assist) return;
this.wpc_.consume((world,pos)->{
if(world.isRemote()) return;
CompoundNBT hist_nbt = history_.write();
final CompoundNBT nbt = new CompoundNBT();
if((inventory_ instanceof CraftingTableTileEntity)) {
((CraftingTableTileEntity)inventory_).history = hist_nbt.copy();
inventory_.markDirty();
nbt.put("inventory", ((CraftingTableTileEntity)inventory_).mainInventory().save(false));
}
final CompoundNBT nbt = new CompoundNBT();
nbt.put("history", hist_nbt);
nbt.putBoolean("hascollision", has_recipe_collision_);
Networking.PacketContainerSyncServerToClient.sendToListeners(world, this, nbt);
});
}
private void syncProperties()
{
this.wpc_.consume((world,pos)->{
final CompoundNBT nbt = new CompoundNBT();
nbt.putBoolean("hascollision", has_recipe_collision_);
Networking.PacketContainerSyncServerToClient.sendToListeners(world, this, nbt);
});
}
// private aux methods ---------------------------------------------------------------------
public boolean has_recipe_collision()
@ -772,7 +770,6 @@ public class EdCraftingTable
}
if(recipe != null) {
onCraftMatrixChanged(inventory_);
syncHistory();
}
}
@ -850,12 +847,6 @@ public class EdCraftingTable
return stacks;
}
private boolean clear_grid_to_storage(PlayerEntity player)
{ return crafting_grid_range_.move(block_storage_range_); }
private boolean clear_grid_to_player(PlayerEntity player)
{ return crafting_grid_range_.move(player_inventory_range_); }
private PlacementResult place_stacks(final InventoryRange[] ranges, final List<ItemStack> to_fill)
{
if(history_.current_recipe() != null) result_.setRecipeUsed(history_.current_recipe());
@ -1168,7 +1159,7 @@ public class EdCraftingTable
palce_in_crafting_grid = (!history.isEmpty());
if(!palce_in_crafting_grid) {
for(int i = 0; i < 9; ++i) {
if(!(getContainer().getSlot(i).getStack().isEmpty())) {
if(!Inventories.areItemStacksDifferent(getContainer().getSlot(i).getStack(), slot.getStack())) {
palce_in_crafting_grid = true;
break;
}
@ -1190,7 +1181,7 @@ public class EdCraftingTable
action(CraftingTableContainer.ACTION_MOVE_ALL_STACKS, nbt);
return;
} else if((slotId > 0) && (slotId <= 9)) {
// Move from grid to storage or player inventory
// Move from crafting grid to inventory
CompoundNBT nbt = new CompoundNBT();
nbt.putInt("containerslot", slotId);
action(CraftingTableContainer.ACTION_MOVE_STACK, nbt);
@ -1471,7 +1462,7 @@ public class EdCraftingTable
@Override
protected void onCrafting(ItemStack stack)
{
if((with_assist) && ((player.world!=null) && (!(player.world.isRemote))) && (!stack.isEmpty())) {
if((with_assist) && ((player.world!=null) && (!(player.world.isRemote()))) && (!stack.isEmpty())) {
final IRecipe recipe = ((CraftResultInventory)this.inventory).getRecipeUsed();
final ArrayList<ItemStack> grid = new ArrayList<ItemStack>();
grid.add(stack);
@ -1479,10 +1470,10 @@ public class EdCraftingTable
if(recipe instanceof ICraftingRecipe) {
container.history().add(grid, (ICraftingRecipe)recipe);
container.history().reset_current();
container.syncHistory();
}
}
super.onCrafting(stack);
container.sync();
}
}

View file

@ -11,6 +11,7 @@ package wile.engineersdecor.blocks;
import net.minecraft.inventory.container.ClickType;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer;
@ -45,17 +46,18 @@ 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 com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraftforge.items.wrapper.InvWrapper;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.libmc.client.ContainerGui;
import wile.engineersdecor.libmc.detail.Auxiliaries;
import wile.engineersdecor.libmc.detail.Inventories;
import wile.engineersdecor.libmc.detail.Inventories.InventoryRange;
import wile.engineersdecor.libmc.detail.Inventories.StorageInventory;
import wile.engineersdecor.libmc.detail.Networking;
import wile.engineersdecor.libmc.detail.TooltipDisplay;
import wile.engineersdecor.libmc.detail.TooltipDisplay.TipRange;
@ -158,7 +160,7 @@ public class EdDropper
}
stacks.add(stack);
} else {
for(ItemStack stack: ((DropperTileEntity)te).stacks_) {
for(ItemStack stack: ((DropperTileEntity)te).main_inventory_) {
if(!stack.isEmpty()) stacks.add(stack);
}
((DropperTileEntity)te).reset_rtstate();
@ -188,26 +190,15 @@ public class EdDropper
}
@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; }
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class DropperTileEntity extends TileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory
public static class DropperTileEntity extends TileEntity implements ITickableTileEntity, INameable, INamedContainerProvider
{
public static final int NUM_OF_FIELDS = 16;
public static final int TICK_INTERVAL = 32;
@ -242,9 +233,9 @@ public class EdDropper
private int drop_period_ = 0;
private int drop_slot_index_ = 0;
private int tick_timer_ = 0;
protected NonNullList<ItemStack> stacks_;
protected final InventoryRange storage_slot_range_;
protected final InventoryRange filter_slot_range_;
protected final Inventories.StorageInventory main_inventory_ = new StorageInventory(this, NUM_OF_SLOTS, 1);
protected final InventoryRange storage_slot_range_ = new InventoryRange(main_inventory_, INPUT_SLOTS_FIRST, INPUT_SLOTS_SIZE);
protected final InventoryRange filter_slot_range_ = new InventoryRange(main_inventory_, CTRL_SLOTS_FIRST, CTRL_SLOTS_SIZE);
public static void on_config(int cooldown_ticks)
{
@ -255,19 +246,13 @@ public class EdDropper
{ this(ModContent.TET_FACTORY_DROPPER); }
public DropperTileEntity(TileEntityType<?> te_type)
{
super(te_type);
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
storage_slot_range_ = new InventoryRange(this, INPUT_SLOTS_FIRST, INPUT_SLOTS_SIZE);
filter_slot_range_ = new InventoryRange(this, CTRL_SLOTS_FIRST, CTRL_SLOTS_SIZE);
reset_rtstate();
}
{ super(te_type); 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);
main_inventory_.clear();
reset_rtstate();
triggered_ = false;
block_power_updated_ = false;
@ -283,9 +268,7 @@ public class EdDropper
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);
main_inventory_.load(nbt);
block_power_signal_ = nbt.getBoolean("powered");
open_timer_ = nbt.getInt("open_timer");
drop_speed_ = nbt.getInt("drop_speed");
@ -300,7 +283,7 @@ public class EdDropper
protected void writenbt(CompoundNBT nbt, boolean update_packet)
{
ItemStackHelper.saveAllItems(nbt, stacks_);
main_inventory_.save(nbt);
nbt.putBoolean("powered", block_power_signal_);
nbt.putInt("open_timer", open_timer_);
nbt.putInt("drop_speed", drop_speed_);
@ -339,7 +322,7 @@ public class EdDropper
public void remove()
{
super.remove();
Arrays.stream(item_handlers).forEach(LazyOptional::invalidate);
item_handler_.invalidate();
}
// INamable ----------------------------------------------------------------------------------------------
@ -364,66 +347,7 @@ public class EdDropper
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new DropperContainer(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 ((getWorld().getTileEntity(getPos()) == this)) && (getPos().distanceSq(player.getPosition()) < 64); }
@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(); }
{ return new DropperContainer(id, inventory, main_inventory_, IWorldPosCallable.of(world, pos), fields); }
// Fields -----------------------------------------------------------------------------------------------
@ -473,33 +397,14 @@ public class EdDropper
}
};
// 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 ------------------------------------------------------------------------------------
protected LazyOptional<? extends IItemHandler> item_handler_ = LazyOptional.of(()->new InvWrapper(storage_slot_range_));
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return item_handlers[0].cast();
if(capability==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return item_handler_.cast();
return super.getCapability(capability, facing);
}
@ -613,7 +518,7 @@ public class EdDropper
int last_filter_matches_[] = filter_matches_.clone();
for(int ci=0; ci<CTRL_SLOTS_SIZE; ++ci) {
filter_matches_[ci] = 0;
final ItemStack cmp_stack = stacks_.get(CTRL_SLOTS_FIRST+ci);
final ItemStack cmp_stack = main_inventory_.getStackInSlot(CTRL_SLOTS_FIRST+ci);
if(cmp_stack.isEmpty()) continue;
filter_matches_[ci] = 1;
final int cmp_stack_count = cmp_stack.getCount();
@ -671,34 +576,34 @@ public class EdDropper
if(drop_slot_index_ >= INPUT_SLOTS_SIZE) drop_slot_index_ = 0;
final int ic = drop_slot_index_;
drop_slot_index_ = next_slot(drop_slot_index_);
ItemStack ds = stacks_.get(ic);
ItemStack ds = main_inventory_.getStackInSlot(ic);
if((!ds.isEmpty()) && (ds.getCount() >= drop_count_)) {
boolean skip_stack = false;
for(int ci = 0; (ci<CTRL_SLOTS_SIZE)&&(!skip_stack); ++ci) {
final ItemStack cmp_stack = stacks_.get(CTRL_SLOTS_FIRST+ci);
final ItemStack cmp_stack = main_inventory_.getStackInSlot(CTRL_SLOTS_FIRST+ci);
if(Inventories.areItemStacksIdentical(ds, cmp_stack)) skip_stack = true;
}
if(skip_stack) continue;
drop_stacks[0] = ds.split(drop_count_);
stacks_.set(ic, ds);
main_inventory_.setInventorySlotContents(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();
drop_stacks[fi] = main_inventory_.getStackInSlot(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);
ItemStack stack = main_inventory_.getStackInSlot(i);
if(Inventories.areItemStacksDifferent(stack, drop_stacks[fi])) continue;
if(stack.getCount() <= ntoremove) {
ntoremove -= stack.getCount();
stacks_.set(i, ItemStack.EMPTY);
main_inventory_.setInventorySlotContents(i, ItemStack.EMPTY);
} else {
stack.shrink(ntoremove);
ntoremove = 0;
stacks_.set(i, stack);
main_inventory_.setInventorySlotContents(i, stack);
}
}
if(ntoremove > 0) drop_stacks[fi].shrink(ntoremove);
@ -727,7 +632,7 @@ public class EdDropper
{
boolean found = false;
for(int i = 0; i < storage_slot_range_.size; ++i) {
if(!stacks_.get(drop_slot_index_).isEmpty()) { found=true; break; }
if(!main_inventory_.getStackInSlot(drop_slot_index_).isEmpty()) { found=true; break; }
drop_slot_index_ = next_slot(drop_slot_index_);
}
if(!found) drop_slot_index_ = 0;
@ -850,7 +755,7 @@ public class EdDropper
@Override
public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt)
{
if(!(inventory_ instanceof DropperTileEntity)) return;
if((!(inventory_ instanceof StorageInventory)) || (!(((StorageInventory)inventory_).getTileEntity() instanceof DropperTileEntity))) return;
if(nbt.contains("action")) {
boolean changed = false;
final int slotId = nbt.contains("slot") ? nbt.getInt("slot") : -1;
@ -869,7 +774,7 @@ public class EdDropper
detectAndSendChanges();
}
} else {
DropperTileEntity te = (DropperTileEntity)inventory_;
DropperTileEntity te = (DropperTileEntity)((StorageInventory)inventory_).getTileEntity();
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);

View file

@ -9,6 +9,7 @@
package wile.engineersdecor.blocks;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
@ -20,7 +21,6 @@ import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.item.*;
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.entity.player.PlayerEntity;
@ -44,20 +44,20 @@ 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 wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.blocks.EdFurnace.FurnaceTileEntity;
import wile.engineersdecor.libmc.detail.Inventories.StorageInventory;
import wile.engineersdecor.libmc.detail.Inventories.MappedItemHandler;
import wile.engineersdecor.libmc.detail.TooltipDisplay;
import wile.engineersdecor.libmc.detail.TooltipDisplay.TipRange;
import wile.engineersdecor.libmc.client.ContainerGui;
import wile.engineersdecor.libmc.detail.Inventories;
import wile.engineersdecor.libmc.detail.Networking;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Random;
@ -116,28 +116,29 @@ public class EdElectricalFurnace
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class ElectricalFurnaceTileEntity extends EdFurnace.FurnaceTileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory, IEnergyStorage
public static class ElectricalFurnaceTileEntity extends EdFurnace.FurnaceTileEntity implements ITickableTileEntity, INameable, INamedContainerProvider
{
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 = 1024;
public static final int MAX_ENERGY_BUFFER = 32000;
public static final int MAX_SPEED_SETTING = 3;
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 = 250;
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;
private static final int NUM_OF_FIELDS = 7;
private static final int TICK_INTERVAL = 4;
private static final int FIFO_INTERVAL = 20;
private static final int HEAT_CAPACITY = 200;
private static final int HEAT_INCREMENT = 20;
private static final int MAX_BURNTIME = 0x7fff;
private static final int MAX_XP_STORED = 65535;
private static final int MAX_ENERGY_TRANSFER = 1024;
private static final int MAX_ENERGY_BUFFER = 32000;
private static final int MAX_SPEED_SETTING = 3;
private static final int NUM_OF_SLOTS = 7;
private static final int SMELTING_INPUT_SLOT_NO = 0;
private static final int SMELTING_AUX_SLOT_NO = 1;
private static final int SMELTING_OUTPUT_SLOT_NO = 2;
private static final int FIFO_INPUT_0_SLOT_NO = 3;
private static final int FIFO_INPUT_1_SLOT_NO = 4;
private static final int FIFO_OUTPUT_0_SLOT_NO = 5;
private static final int FIFO_OUTPUT_1_SLOT_NO = 6;
public static final int DEFAULT_SPEED_PERCENT = 290;
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 ----------------------------------------------------------------------------------
@ -158,66 +159,78 @@ public class EdElectricalFurnace
// ElectricalFurnaceTileEntity -----------------------------------------------------------------------------
private int burntime_left_ = 0;
private int proc_time_elapsed_ = 0;
private int proc_time_needed_ = 0;
private int energy_stored_ = 0;
private int field_max_energy_stored_ = 0;
private int field_isburning_ = 0;
private int speed_ = 1;
private int tick_timer_ = 0;
private int fifo_timer_ = 0;
private boolean enabled_ = false;
private final LazyOptional<IItemHandler> item_handler_;
public ElectricalFurnaceTileEntity()
{ this(ModContent.TET_SMALL_ELECTRICAL_FURNACE); }
public ElectricalFurnaceTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
{
super(te_type, NUM_OF_SLOTS);
battery_.setMaxEnergyStored(MAX_ENERGY_BUFFER);
battery_.setChargeRate(MAX_ENERGY_TRANSFER);
battery_.setDischargeRate(0);
inventory_.setValidator((index, 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;
}
});
item_handler_ = MappedItemHandler.createGenericHandler(inventory_,
(slot,stack)->((slot==FIFO_OUTPUT_0_SLOT_NO) || (slot==FIFO_OUTPUT_1_SLOT_NO)),
(slot,stack)->((slot==FIFO_INPUT_0_SLOT_NO) || (slot==FIFO_INPUT_1_SLOT_NO)),
Arrays.asList(FIFO_OUTPUT_0_SLOT_NO,FIFO_OUTPUT_1_SLOT_NO,FIFO_INPUT_0_SLOT_NO,FIFO_INPUT_1_SLOT_NO)
);
}
public void reset()
{
super.reset();
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
inventory_.clear();
burntime_left_ = 0;
proc_time_elapsed_ = 0;
proc_time_needed_ = 0;
fifo_timer_ = 0;
tick_timer_ = 0;
energy_stored_ = 0;
battery_.clear();
speed_ = 1;
field_max_energy_stored_ = getMaxEnergyStored();
field_isburning_ = 0;
field_is_burning_ = 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");
xp_stored_ = nbt.getFloat("XpStored");
speed_ = nbt.getInt("SpeedSetting");
speed_ = (speed_ < 0) ? (1) : ((speed_>MAX_SPEED_SETTING) ? MAX_SPEED_SETTING : speed_);
battery_.load(nbt, "Energy");
inventory_.load(nbt);
}
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("CookTime", MathHelper.clamp((int)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_);
nbt.putFloat("XpStored", MathHelper.clamp(xp_stored_, 0, MAX_XP_STORED));
battery_.save(nbt, "Energy");
inventory_.save(nbt);
}
public int getComparatorOutput()
{
return (energy_stored_ <= 0) ? (0) : (
(stacks_.get(FIFO_INPUT_1_SLOT_NO).isEmpty() ? 0 : 5) +
(stacks_.get(FIFO_INPUT_0_SLOT_NO).isEmpty() ? 0 : 5) +
(stacks_.get(SMELTING_INPUT_SLOT_NO).isEmpty() ? 0 : 5)
return (battery_.isEmpty()) ? (0) : (
(inventory_.getStackInSlot(FIFO_INPUT_1_SLOT_NO).isEmpty() ? 0 : 5) +
(inventory_.getStackInSlot(FIFO_INPUT_0_SLOT_NO).isEmpty() ? 0 : 5) +
(inventory_.getStackInSlot(SMELTING_INPUT_SLOT_NO).isEmpty() ? 0 : 5)
);
}
@ -235,7 +248,6 @@ public class EdElectricalFurnace
public void remove()
{
super.remove();
Arrays.stream(item_handlers).forEach(LazyOptional::invalidate);
item_handler_.invalidate();
energy_handler_.invalidate();
}
@ -250,26 +262,7 @@ public class EdElectricalFurnace
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new EdElectricalFurnace.ElectricalFurnaceContainer(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]); }
{ return new EdElectricalFurnace.ElectricalFurnaceContainer(id, inventory, inventory_, IWorldPosCallable.of(world, pos), fields); }
// Fields -----------------------------------------------------------------------------------------------
@ -280,12 +273,12 @@ public class EdElectricalFurnace
{
switch(id) {
case 0: return ElectricalFurnaceTileEntity.this.burntime_left_;
case 1: return ElectricalFurnaceTileEntity.this.energy_stored_;
case 2: return ElectricalFurnaceTileEntity.this.proc_time_elapsed_;
case 1: return ElectricalFurnaceTileEntity.this.battery_.getEnergyStored();
case 2: return (int)ElectricalFurnaceTileEntity.this.proc_time_elapsed_;
case 3: return ElectricalFurnaceTileEntity.this.proc_time_needed_;
case 4: return ElectricalFurnaceTileEntity.this.speed_;
case 5: return ElectricalFurnaceTileEntity.this.field_max_energy_stored_;
case 6: return ElectricalFurnaceTileEntity.this.field_isburning_;
case 5: return ElectricalFurnaceTileEntity.this.battery_.getMaxEnergyStored();
case 6: return ElectricalFurnaceTileEntity.this.field_is_burning_;
default: return 0;
}
}
@ -294,172 +287,18 @@ public class EdElectricalFurnace
{
switch(id) {
case 0: ElectricalFurnaceTileEntity.this.burntime_left_ = value; break;
case 1: ElectricalFurnaceTileEntity.this.energy_stored_ = value; break;
case 1: ElectricalFurnaceTileEntity.this.battery_.setEnergyStored(value); break;
case 2: ElectricalFurnaceTileEntity.this.proc_time_elapsed_ = value; break;
case 3: ElectricalFurnaceTileEntity.this.proc_time_needed_ = value; break;
case 4: ElectricalFurnaceTileEntity.this.speed_ = value; break;
case 5: ElectricalFurnaceTileEntity.this.field_max_energy_stored_ = value; break;
case 6: ElectricalFurnaceTileEntity.this.field_isburning_ = value; break;
case 5: ElectricalFurnaceTileEntity.this.battery_.setMaxEnergyStored(value); break;
case 6: ElectricalFurnaceTileEntity.this.field_is_burning_ = 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 ((index==FIFO_INPUT_0_SLOT_NO) || (index==FIFO_INPUT_1_SLOT_NO)) && isItemValidForSlot(index, itemStackIn); }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return (index==FIFO_OUTPUT_0_SLOT_NO) || (index==FIFO_OUTPUT_1_SLOT_NO); }
// 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 ElectricalFurnaceTileEntity te;
BItemHandler(ElectricalFurnaceTileEntity 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)
{
@ -491,25 +330,25 @@ public class EdElectricalFurnace
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(energy_stored_ < energy_consumption()) {
if(battery_.getEnergyStored() < energy_consumption()) {
enabled_ = false;
} else if(energy_stored_ >= (MAX_ENERGY_BUFFER/2)) {
} else if(battery_.getEnergyStored() >= (MAX_ENERGY_BUFFER/2)) {
enabled_ = true;
}
if((!(stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty()) && (enabled_) && (speed_>0)) {
if((!(inventory_.getStackInSlot(SMELTING_INPUT_SLOT_NO)).isEmpty()) && (enabled_) && (speed_>0)) {
IRecipe last_recipe = currentRecipe();
updateCurrentRecipe();
if(currentRecipe() != last_recipe) {
proc_time_elapsed_ = 0;
proc_time_needed_ = getSmeltingTimeNeeded(world, stacks_.get(SMELTING_INPUT_SLOT_NO));
proc_time_needed_ = getSmeltingTimeNeeded(world, inventory_.getStackInSlot(SMELTING_INPUT_SLOT_NO));
}
final boolean can_smelt = canSmeltCurrentItem();
if((!can_smelt) && (getSmeltingResult(stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty())) {
if((!can_smelt) && (getSmeltingResult(inventory_.getStackInSlot(SMELTING_INPUT_SLOT_NO)).isEmpty())) {
// bypass
if(transferItems(SMELTING_INPUT_SLOT_NO, SMELTING_OUTPUT_SLOT_NO, 1)) dirty = true;
} else {
// smelt, automatically choke speed on low power storage
final int speed = MathHelper.clamp((getEnergyStored()>getMaxEnergyStored()/5)? (speed_) : (1), 1, MAX_SPEED_SETTING);
final int speed = (battery_.getSOC() >= 25)? (speed_) : (1);
if(!burning() && can_smelt) {
if(heat_up(speed)) { dirty = true; update_blockstate = true; }
}
@ -518,7 +357,7 @@ public class EdElectricalFurnace
proc_time_elapsed_ += (int)(TICK_INTERVAL * proc_speed_percent_ * speed_setting_factor_[speed] / 100);
if(proc_time_elapsed_ >= proc_time_needed_) {
proc_time_elapsed_ = 0;
proc_time_needed_ = getSmeltingTimeNeeded(world, stacks_.get(SMELTING_INPUT_SLOT_NO));
proc_time_needed_ = getSmeltingTimeNeeded(world, inventory_.getStackInSlot(SMELTING_INPUT_SLOT_NO));
smeltCurrentItem();
dirty = true;
shift_out = true;
@ -528,7 +367,7 @@ public class EdElectricalFurnace
}
}
} else if(proc_time_elapsed_ > 0) {
proc_time_elapsed_ -= ((stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty() ? 20 : 1);
proc_time_elapsed_ -= ((inventory_.getStackInSlot(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) {
@ -537,31 +376,24 @@ public class EdElectricalFurnace
}
if(adjacent_inventory_shift(shift_in, shift_out)) dirty = true;
if(dirty) markDirty();
field_max_energy_stored_ = getMaxEnergyStored();
field_isburning_ = burning() ? 1 : 0;
field_is_burning_ = burning() ? 1 : 0;
}
// Furnace --------------------------------------------------------------------------------------
protected void updateCurrentRecipe()
{ setCurrentRecipe(getSmeltingResult(RECIPE_TYPE, world, stacks_.get(SMELTING_INPUT_SLOT_NO))); }
public boolean burning()
{ return burntime_left_ > 0; }
private boolean is_accepted_hopper(final ItemStack stack)
{ return (stack.getItem() == Blocks.HOPPER.asItem()) || (stack.getItem() == ModContent.FACTORY_HOPPER.asItem()); }
private boolean transferItems(final int index_from, final int index_to, int count)
{
ItemStack from = stacks_.get(index_from);
ItemStack from = inventory_.getStackInSlot(index_from);
if(from.isEmpty()) return false;
ItemStack to = stacks_.get(index_to);
ItemStack to = inventory_.getStackInSlot(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));
inventory_.setInventorySlotContents(index_to, from.split(count));
} else if(to.getCount() >= to.getMaxStackSize()) {
changed = false;
} else if(Inventories.areItemStacksDifferent(from, to)) {
@ -576,7 +408,7 @@ public class EdElectricalFurnace
}
}
if(from.isEmpty() && from!=ItemStack.EMPTY) {
stacks_.set(index_from, ItemStack.EMPTY);
inventory_.setInventorySlotContents(index_from, ItemStack.EMPTY);
changed = true;
}
return changed;
@ -585,25 +417,25 @@ public class EdElectricalFurnace
private boolean adjacent_inventory_shift(boolean inp, boolean out)
{
boolean dirty = false;
if(energy_stored_ < transfer_energy_consumption_) return false;
if(battery_.getEnergyStored() < transfer_energy_consumption_) return false;
final BlockState state = world.getBlockState(pos);
if(!(state.getBlock() instanceof ElectricalFurnaceBlock)) return false;
final Direction out_facing = state.get(ElectricalFurnaceBlock.HORIZONTAL_FACING);
if(out && (!stacks_.get(FIFO_OUTPUT_1_SLOT_NO).isEmpty())) {
if(out && (!inventory_.getStackInSlot(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_;
ItemStack remaining = ItemHandlerHelper.insertItemStacked(hnd, inventory_.getStackInSlot(FIFO_OUTPUT_1_SLOT_NO).copy(), false);
inventory_.setInventorySlotContents(FIFO_OUTPUT_1_SLOT_NO, remaining);
battery_.draw(transfer_energy_consumption_);
dirty = true;
}
}
}
if(with_automatic_inventory_pulling_ || is_accepted_hopper(stacks_.get(SMELTING_AUX_SLOT_NO))) {
if(with_automatic_inventory_pulling_ || is_accepted_hopper(inventory_.getStackInSlot(SMELTING_AUX_SLOT_NO))) {
final Direction inp_facing = state.get(ElectricalFurnaceBlock.HORIZONTAL_FACING).getOpposite();
if(inp && (stacks_.get(FIFO_INPUT_1_SLOT_NO).isEmpty())) {
if(inp && (inventory_.getStackInSlot(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);
@ -612,10 +444,10 @@ public class EdElectricalFurnace
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());
if(my_stack.getCount() > inventory_.getInventoryStackLimit()) my_stack.setCount(inventory_.getInventoryStackLimit());
adj_stack.shrink(my_stack.getCount());
stacks_.set(FIFO_INPUT_1_SLOT_NO, my_stack);
energy_stored_ -= transfer_energy_consumption_;
inventory_.setInventorySlotContents(FIFO_INPUT_1_SLOT_NO, my_stack);
battery_.draw(transfer_energy_consumption_);
dirty = true;
break;
}
@ -642,10 +474,9 @@ public class EdElectricalFurnace
private boolean heat_up(int speed)
{
int p = energy_consumption(speed);
if((p<=0) || (energy_stored_ < p)) return false;
if(burntime_left_ >= (HEAT_CAPACITY-HEAT_INCREMENT)) return false;
energy_stored_ -= p;
int p = energy_consumption(speed);
if((p<=0) || (!battery_.draw(p))) return false;
burntime_left_ += HEAT_INCREMENT;
this.markDirty();
return true; // returns TE dirty
@ -689,7 +520,7 @@ public class EdElectricalFurnace
inventory_ = block_inventory;
wpc_ = wpc;
fields_ = fields;
recipe_type_ = ElectricalFurnaceTileEntity.RECIPE_TYPE;
recipe_type_ = FurnaceTileEntity.RECIPE_TYPE;
addSlot(new Slot(inventory_, 0, 59, 28)); // smelting input
addSlot(new Slot(inventory_, 1, 16, 52)); // aux
addSlot(new EdFurnace.FurnaceContainer.BSlotResult(player_, inventory_, 2, 101, 28)); // smelting result
@ -774,8 +605,8 @@ public class EdElectricalFurnace
public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt)
{
if(!(inventory_ instanceof ElectricalFurnaceTileEntity)) return;
ElectricalFurnaceTileEntity te = (ElectricalFurnaceTileEntity)inventory_;
if(!(inventory_ instanceof StorageInventory)) return;
ElectricalFurnaceTileEntity te = (ElectricalFurnaceTileEntity)(((StorageInventory)inventory_).getTileEntity());
if(nbt.contains("speed")) te.speed_ = MathHelper.clamp(nbt.getInt("speed"), 0, ElectricalFurnaceTileEntity.MAX_SPEED_SETTING);
te.markDirty();
}

View file

@ -11,11 +11,7 @@ package wile.engineersdecor.blocks;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.util.*;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.libmc.blocks.StandardBlocks;
import wile.engineersdecor.libmc.detail.Auxiliaries;
import wile.engineersdecor.libmc.detail.Fluidics;
import wile.engineersdecor.libmc.detail.Overlay;
import net.minecraft.world.IWorldReader;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.BlockItem;
@ -49,6 +45,11 @@ import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.libmc.blocks.StandardBlocks;
import wile.engineersdecor.libmc.detail.Auxiliaries;
import wile.engineersdecor.libmc.detail.Fluidics;
import wile.engineersdecor.libmc.detail.Overlay;
import javax.annotation.Nullable;
import java.util.ArrayList;
@ -209,6 +210,10 @@ public class EdFluidBarrel
return (int)MathHelper.clamp(((FluidBarrelTileEntity)te).getNormalizedFillLevel() * 15, 0, 15);
}
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
}
//--------------------------------------------------------------------------------------------------------------------
@ -218,8 +223,26 @@ public class EdFluidBarrel
public static class FluidBarrelTileEntity extends TileEntity implements ICapabilityProvider, ITickableTileEntity
{
private final int TICK_INTERVAL = 10;
private final Fluidics.Tank tank_ = new Fluidics.Tank(capacity_);
private int tick_timer_ = 0;
private final Fluidics.Tank tank_;
private final LazyOptional<IFluidHandler> fluid_handler_;
public FluidBarrelTileEntity()
{ this(ModContent.TET_FLUID_BARREL); }
public FluidBarrelTileEntity(TileEntityType<?> te_type)
{
super(te_type);
tank_ = new Fluidics.Tank(capacity_);
tank_.setInteractionNotifier((t,d)->on_tank_changed());
fluid_handler_ = tank_.createFluidHandler();
}
public void readnbt(CompoundNBT nbt)
{ tank_.load(nbt); }
public CompoundNBT writenbt(CompoundNBT nbt)
{ tank_.save(nbt); return nbt; }
public boolean handlePlayerInteraction(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand)
{
@ -256,31 +279,11 @@ public class EdFluidBarrel
public double getNormalizedFillLevel()
{ return (tank_.isEmpty()) ? (0) : ((double)tank_.getFluidAmount()/(double)tank_.getCapacity()); }
public void readnbt(CompoundNBT nbt)
{
if(nbt.contains("tank", Constants.NBT.TAG_COMPOUND)) tank_.readnbt(nbt.getCompound("tank"));
}
public CompoundNBT writenbt(CompoundNBT nbt)
{
if(!tank_.isEmpty()) nbt.put("tank", tank_.writenbt(new CompoundNBT()));
return nbt;
}
protected void on_tank_changed()
{ if(tick_timer_ > 2) tick_timer_ = 2; }
// TileEntity ------------------------------------------------------------------------------
public FluidBarrelTileEntity()
{ this(ModContent.TET_FLUID_BARREL); }
public FluidBarrelTileEntity(TileEntityType<?> te_type)
{
super(te_type);
tank_.setInteractionNotifier((t,d)->on_tank_changed());
}
@Override
public void read(BlockState state, CompoundNBT nbt)
{ super.read(state, nbt); readnbt(nbt); }
@ -294,16 +297,10 @@ public class EdFluidBarrel
{ super.remove(); fluid_handler_.invalidate(); }
public CompoundNBT clear_getnbt()
{
CompoundNBT nbt = new CompoundNBT();
if(!tank_.isEmpty()) nbt.put("tank", tank_.writenbt(new CompoundNBT()));
return nbt;
}
{ return tank_.save(new CompoundNBT()); }
// ICapabilityProvider --------------------------------------------------------------------
private final LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> new Fluidics.SingleTankFluidHandler(tank_));
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{

View file

@ -10,6 +10,7 @@
*/
package wile.engineersdecor.blocks;
import net.minecraft.world.IWorldReader;
import wile.engineersdecor.ModContent;
import net.minecraft.block.*;
import net.minecraft.entity.LivingEntity;
@ -39,8 +40,8 @@ import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.libmc.detail.Fluidics;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
@ -153,13 +154,17 @@ public class EdFluidFunnel
@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 FluidFunnelTileEntity) ((FluidFunnelTileEntity)te).block_changed(); }
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
}
//--------------------------------------------------------------------------------------------------------------------
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class FluidFunnelTileEntity extends TileEntity implements ITickableTileEntity, ICapabilityProvider, IFluidTank
public static class FluidFunnelTileEntity extends TileEntity implements ITickableTileEntity, ICapabilityProvider
{
public static final int TANK_CAPACITY = 3000;
public static final int TICK_INTERVAL = 10; // ca 500ms
@ -169,7 +174,6 @@ public class EdFluidFunnel
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;
@ -177,26 +181,32 @@ public class EdFluidFunnel
private int total_pick_counter_ = 0;
private BlockPos last_pick_pos_ = BlockPos.ZERO;
private ArrayList<Vector3i> search_offsets_ = null;
public void block_changed()
{ tick_timer_ = TICK_INTERVAL; } // collect after flowing fluid has a stable state, otherwise it looks odd.
private final Fluidics.Tank tank_;
private final LazyOptional<IFluidHandler> fluid_handler_;
public FluidFunnelTileEntity()
{ this(ModContent.TET_SMALL_FLUID_FUNNEL); }
public FluidFunnelTileEntity(TileEntityType<?> te_type)
{ super(te_type); }
{
super(te_type);
tank_ = new Fluidics.Tank(TANK_CAPACITY, 0, TANK_CAPACITY);
fluid_handler_ = tank_.createOutputFluidHandler();
}
public void readnbt(CompoundNBT nbt)
{
tank_ = (!nbt.contains("tank")) ? (FluidStack.EMPTY) : (FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
tank_.load(nbt);
}
public void writenbt(CompoundNBT nbt)
{
if(!tank_.isEmpty()) nbt.put("tank", tank_.writeToNBT(new CompoundNBT()));
tank_.save(nbt);
}
public void block_changed()
{ tick_timer_ = TICK_INTERVAL; }
// TileEntity -----------------------------------------------------------------------------------------
@Override
@ -216,20 +226,7 @@ public class EdFluidFunnel
// ICapabilityProvider / Output flow handler ----------------------------------------------------------
private static class OutputFluidHandler implements IFluidHandler
{
private final FluidFunnelTileEntity te;
OutputFluidHandler(FluidFunnelTileEntity 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) { return te.drain(resource, action); }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return te.drain(maxDrain, action); }
}
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)
@ -238,56 +235,10 @@ public class EdFluidFunnel
return super.getCapability(capability, facing);
}
// IFluidTank ------------------------------------------------------------------------------------------
@Override
@Nonnull
public FluidStack getFluid()
{ return tank_.copy(); }
@Override
public int getFluidAmount()
{ return tank_.getAmount(); }
@Override
public int getCapacity()
{ return TANK_CAPACITY; }
@Override
public boolean isFluidValid(FluidStack stack)
{ return true; }
@Override
public int fill(FluidStack resource, FluidAction action)
{ return 0; }
@Override
@Nonnull
public FluidStack drain(FluidStack resource, FluidAction action)
{
if((resource==null) || (tank_.isEmpty())) return FluidStack.EMPTY;
return (!(tank_.isFluidEqual(resource))) ? (FluidStack.EMPTY) : drain(resource.getAmount(), action);
}
@Override
@Nonnull
public FluidStack drain(int maxDrain, FluidAction action)
{
if(tank_.isEmpty()) return FluidStack.EMPTY;
FluidStack res = tank_.copy();
maxDrain = MathHelper.clamp(maxDrain ,0 , tank_.getAmount());
res.setAmount(maxDrain);
if(action != FluidAction.EXECUTE) return res;
tank_.setAmount(tank_.getAmount()-maxDrain);
if(tank_.getAmount() <= 0) tank_ = FluidStack.EMPTY;
return res;
}
// ITickableTileEntity --------------------------------------------------------------------------------
private FluidState 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();
@ -313,9 +264,9 @@ public class EdFluidFunnel
}
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();
tank_.setFluid(fs.copy());
} else if(tank_.isFluidEqual(fs)) {
tank_.setAmount(MathHelper.clamp(tank_.getAmount()+fs.getAmount(), 0, TANK_CAPACITY));
tank_.fill(fs, FluidAction.EXECUTE);
} else {
return false;
}
@ -352,7 +303,7 @@ public class EdFluidFunnel
FluidState 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((!tank_.isEmpty()) && (!tank_.getFluid().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_;
@ -420,7 +371,7 @@ public class EdFluidFunnel
if(!(funnel_state.getBlock() instanceof FluidFunnelBlock)) return;
boolean dirty = false;
// Collection
if((collection_timer_ >= COLLECTION_INTERVAL) && ((tank_==null) || (tank_.getAmount() <= (TANK_CAPACITY-1000)))) {
if((collection_timer_ >= COLLECTION_INTERVAL) && ((tank_==null) || (tank_.getFluidAmount() <= (TANK_CAPACITY-1000)))) {
collection_timer_ = 0;
if(!world.isBlockPowered(pos)) { // redstone disable feature
if(last_pick_pos_==null) last_pick_pos_ = pos.up();
@ -431,12 +382,11 @@ public class EdFluidFunnel
te = null;
} else if(tank_.isEmpty()) {
FluidStack fs = fh.drain(1000, FluidAction.EXECUTE);
if((fs!=null) && (!fs.isEmpty())) tank_ = fs.copy();
if((fs!=null) && (!fs.isEmpty())) tank_.setFluid(fs.copy());
dirty = true;
} else {
FluidStack todrain = new FluidStack(tank_.getFluid(), 1000);
FluidStack fs = fh.drain(todrain, FluidAction.EXECUTE);
if((fs!=null) && (!fs.isEmpty())) tank_.setAmount(tank_.getAmount()+fs.getAmount());
} else if (!tank_.isFull()) {
FluidStack todrain = new FluidStack(tank_.getFluid(), Math.min(tank_.getCapacity()-tank_.getFluidAmount(), 1000));
tank_.fill(fh.drain(todrain, FluidAction.EXECUTE), FluidAction.EXECUTE);
dirty = true;
}
}
@ -446,17 +396,17 @@ public class EdFluidFunnel
}
}
// Gravity fluid transfer
if((tank_.getAmount() >= 1000)) {
if((tank_.getFluidAmount() >= 1000)) {
IFluidHandler fh = FluidUtil.getFluidHandler(world, pos.down(), Direction.UP).orElse(null);
if(fh != null) {
FluidStack fs = new FluidStack(tank_.getFluid(), 1000);
FluidStack fs = new FluidStack(tank_.getFluid().getFluid(), 1000);
int nfilled = MathHelper.clamp(fh.fill(fs, FluidAction.EXECUTE), 0, 1000);
tank_.shrink(nfilled);
tank_.drain(nfilled);
dirty = true;
}
}
// Block state
int fill_level = (tank_==null) ? 0 : (MathHelper.clamp(tank_.getAmount()/1000,0, FluidFunnelBlock.FILL_LEVEL_MAX));
int fill_level = (tank_==null) ? 0 : (MathHelper.clamp(tank_.getFluidAmount()/1000,0, FluidFunnelBlock.FILL_LEVEL_MAX));
if(funnel_state.get(FluidFunnelBlock.FILL_LEVEL) != fill_level) world.setBlockState(pos, funnel_state.with(FluidFunnelBlock.FILL_LEVEL, fill_level), 2|16);
if(dirty) markDirty();
}

View file

@ -9,9 +9,7 @@
*/
package wile.engineersdecor.blocks;
import net.minecraftforge.common.util.Constants;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraft.block.*;
@ -40,6 +38,8 @@ import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import wile.engineersdecor.libmc.detail.Fluidics;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -135,6 +135,10 @@ public class EdFreezer
}
}
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
@Override
@OnlyIn(Dist.CLIENT)
public void animateTick(BlockState state, World world, BlockPos pos, Random rnd)
@ -155,6 +159,7 @@ public class EdFreezer
public static final int MAX_FLUID_LEVEL = 2000;
public static final int MAX_ENERGY_BUFFER = 32000;
public static final int MAX_ENERGY_TRANSFER = 8192;
public static final int TANK_CAPACITY = 2000;
public static final int DEFAULT_ENERGY_CONSUMPTION = 92;
public static final int DEFAULT_COOLDOWN_RATE = 2;
public static final int PHASE_EMPTY = 0;
@ -166,7 +171,7 @@ public class EdFreezer
private static int energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
private static int cooldown_rate = DEFAULT_COOLDOWN_RATE;
private static int reheat_rate = 1;
private final Fluidics.Tank tank_ = new Fluidics.Tank(2000, fs->fs.getFluid()==Fluids.WATER);
private final Fluidics.Tank tank_ = new Fluidics.Tank(TANK_CAPACITY, TANK_CAPACITY, TANK_CAPACITY, fs->fs.getFluid()==Fluids.WATER);
private int tick_timer_;
private int energy_stored_;
private int progress_;
@ -226,14 +231,14 @@ public class EdFreezer
{
energy_stored_ = nbt.getInt("energy");
progress_ = nbt.getInt("progress");
if(nbt.contains("tank", Constants.NBT.TAG_COMPOUND)) tank_.readnbt(nbt.getCompound("tank"));
tank_.load(nbt);
}
protected void writenbt(CompoundNBT nbt)
{
nbt.putInt("energy", MathHelper.clamp(energy_stored_,0 , MAX_ENERGY_BUFFER));
nbt.putInt("progress", MathHelper.clamp(progress_,0 , 100));
if(!tank_.isEmpty()) nbt.put("tank", tank_.writenbt(new CompoundNBT()));
tank_.save(nbt);
}
// TileEntity ------------------------------------------------------------------------------

View file

@ -29,6 +29,7 @@ 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.IWorldReader;
import net.minecraft.world.World;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
@ -53,13 +54,16 @@ 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 wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.ExternalObjects;
import wile.engineersdecor.libmc.client.ContainerGui;
import wile.engineersdecor.libmc.detail.Inventories;
import wile.engineersdecor.libmc.detail.Inventories.StorageInventory;
import wile.engineersdecor.libmc.detail.Inventories.MappedItemHandler;
import wile.engineersdecor.libmc.detail.Networking;
import wile.engineersdecor.libmc.detail.RfEnergy;
import javax.annotation.Nullable;
import java.util.*;
@ -104,6 +108,10 @@ public class EdFurnace
return (te instanceof FurnaceTileEntity) ? ((FurnaceTileEntity)te).getComparatorOutput() : 0;
}
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@ -148,7 +156,7 @@ public class EdFurnace
}
stacks.add(stack);
} else {
for(ItemStack stack: ((FurnaceTileEntity)te).stacks_) stacks.add(stack);
for(ItemStack stack: ((FurnaceTileEntity)te).inventory_) stacks.add(stack);
((FurnaceTileEntity)te).reset();
}
return stacks;
@ -190,27 +198,28 @@ public class EdFurnace
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class FurnaceTileEntity extends TileEntity implements ITickableTileEntity, INameable, IInventory, INamedContainerProvider, ISidedInventory, IEnergyStorage
public static class FurnaceTileEntity extends TileEntity implements ITickableTileEntity, INameable, INamedContainerProvider
{
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;
protected static final IRecipeType<FurnaceRecipe> RECIPE_TYPE = IRecipeType.SMELTING;
private static final int MAX_BURNTIME = 0x7fff;
private static final int MAX_XP_STORED = 65535;
private static final int NUM_OF_FIELDS = 5;
private static final int TICK_INTERVAL = 4;
private static final int FIFO_INTERVAL = 20;
private static final int DEFAULT_SMELTING_TIME = 200;
private static final int DEFAULT_BOOST_ENERGY = 32;
private static final int NUM_OF_SLOTS = 11;
private static final int SMELTING_INPUT_SLOT_NO = 0;
private static final int SMELTING_FUEL_SLOT_NO = 1;
private static final int SMELTING_OUTPUT_SLOT_NO = 2;
private static final int FIFO_INPUT_0_SLOT_NO = 3;
private static final int FIFO_INPUT_1_SLOT_NO = 4;
private static final int FIFO_FUEL_0_SLOT_NO = 5;
private static final int FIFO_FUEL_1_SLOT_NO = 6;
private static final int FIFO_OUTPUT_0_SLOT_NO = 7;
private static final int FIFO_OUTPUT_1_SLOT_NO = 8;
private static final int AUX_0_SLOT_NO = 9;
private static final int AUX_1_SLOT_NO =10;
// Config ----------------------------------------------------------------------------------
@ -228,26 +237,81 @@ public class EdFurnace
// DecorFurnaceTileEntity -----------------------------------------------------------------------------
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 int tick_timer_;
protected int fifo_timer_;
protected double proc_time_elapsed_;
protected int proc_time_needed_;
protected int burntime_left_;
protected int field_is_burning_;
protected float xp_stored_;
protected @Nullable IRecipe current_recipe_ = null;
private final List<String> recent_recipes_ = new ArrayList<>();
private int fuel_burntime_;
private int field_proc_time_elapsed_;
private boolean heater_inserted_ = false;
protected final RfEnergy.Battery battery_;
protected final StorageInventory inventory_;
protected final LazyOptional<IEnergyStorage> energy_handler_;
private final LazyOptional<IItemHandler> item_extraction_handler_;
private final LazyOptional<IItemHandler> item_insertion_handler_;
private final LazyOptional<IItemHandler> item_fuel_insertion_handler_;
public FurnaceTileEntity()
{ this(ModContent.TET_SMALL_LAB_FURNACE); }
public FurnaceTileEntity(TileEntityType<?> te_type)
{ super(te_type); reset(); }
{ this(te_type, NUM_OF_SLOTS); }
public FurnaceTileEntity(TileEntityType<?> te_type, int num_slots)
{
super(te_type);
inventory_ = new StorageInventory(this, num_slots) {
@Override
public void setInventorySlotContents(int index, ItemStack stack)
{
ItemStack slot_stack = stacks_.get(index);
boolean already_in_slot = (!stack.isEmpty()) && (Inventories.areItemStacksIdentical(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();
}
}
};
inventory_.setValidator((index, stack)->{
// applies to gui and handlers
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 = inventory_.getStackInSlot(FIFO_FUEL_1_SLOT_NO);
return isFuel(world, stack) || FurnaceFuelSlot.isBucket(stack) && (slot_stack.getItem() != Items.BUCKET);
}
}
});
item_extraction_handler_ = MappedItemHandler.createExtractionHandler(inventory_,
(slot,stack)->(slot!=SMELTING_FUEL_SLOT_NO) || (stack.getItem()==Items.BUCKET) || (!isFuel(getWorld(), stack)),
Arrays.asList(FIFO_OUTPUT_0_SLOT_NO, FIFO_OUTPUT_1_SLOT_NO, SMELTING_FUEL_SLOT_NO)
);
item_insertion_handler_ = MappedItemHandler.createInsertionHandler(inventory_,
FIFO_INPUT_1_SLOT_NO,FIFO_INPUT_0_SLOT_NO,SMELTING_INPUT_SLOT_NO
);
item_fuel_insertion_handler_ = MappedItemHandler.createInsertionHandler(inventory_,
FIFO_FUEL_1_SLOT_NO,FIFO_FUEL_0_SLOT_NO,SMELTING_FUEL_SLOT_NO
);
battery_ = new RfEnergy.Battery(boost_energy_consumption * 16, boost_energy_consumption, 0);
energy_handler_ = battery_.createEnergyHandler();
}
public CompoundNBT reset_getnbt()
{
@ -259,53 +323,48 @@ public class EdFurnace
public void reset()
{
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
inventory_.clear();
proc_time_elapsed_ = 0;
proc_time_needed_ = 0;
burntime_left_ = 0;
fuel_burntime_ = 0;
fifo_timer_ = 0;
tick_timer_ = 0;
xp_stored_ = 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);
}
xp_stored_ = nbt.getFloat("XpStored");
battery_.load(nbt, "Energy");
inventory_.load(nbt);
}
private void writenbt(CompoundNBT nbt)
protected 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);
nbt.putFloat("XpStored", MathHelper.clamp(xp_stored_, 0, MAX_XP_STORED));
battery_.save(nbt, "Energy");
inventory_.save(nbt);
}
public int getComparatorOutput()
{
if(stacks_.get(FIFO_FUEL_0_SLOT_NO).isEmpty() && stacks_.get(FIFO_FUEL_1_SLOT_NO).isEmpty() && stacks_.get(SMELTING_FUEL_SLOT_NO).isEmpty()) {
if(inventory_.getStackInSlot(FIFO_FUEL_0_SLOT_NO).isEmpty() && inventory_.getStackInSlot(FIFO_FUEL_1_SLOT_NO).isEmpty() && inventory_.getStackInSlot(SMELTING_FUEL_SLOT_NO).isEmpty()) {
return 0; // fuel completely empty
} else {
return (
(stacks_.get(FIFO_INPUT_1_SLOT_NO).isEmpty() ? 0 : 5) +
(stacks_.get(FIFO_INPUT_0_SLOT_NO).isEmpty() ? 0 : 5) +
(stacks_.get(SMELTING_INPUT_SLOT_NO).isEmpty() ? 0 : 5)
(inventory_.getStackInSlot(FIFO_INPUT_1_SLOT_NO).isEmpty() ? 0 : 5) +
(inventory_.getStackInSlot(FIFO_INPUT_0_SLOT_NO).isEmpty() ? 0 : 5) +
(inventory_.getStackInSlot(SMELTING_INPUT_SLOT_NO).isEmpty() ? 0 : 5)
);
}
}
@ -324,7 +383,9 @@ public class EdFurnace
public void remove()
{
super.remove();
Arrays.stream(item_handlers).forEach(LazyOptional::invalidate);
item_extraction_handler_.invalidate();
item_insertion_handler_.invalidate();
item_fuel_insertion_handler_.invalidate();
energy_handler_.invalidate();
}
@ -350,89 +411,7 @@ public class EdFurnace
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new FurnaceContainer(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()) && (Inventories.areItemStacksIdentical(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 ((getWorld().getTileEntity(getPos()) == this)) && (getPos().distanceSq(player.getPosition()) < 64); }
@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(); }
{ return new FurnaceContainer(id, inventory, inventory_, IWorldPosCallable.of(world, pos), fields); }
// Fields -----------------------------------------------------------------------------------------------
@ -463,73 +442,15 @@ public class EdFurnace
}
};
// 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 ((index==FIFO_INPUT_1_SLOT_NO) || (index==FIFO_INPUT_0_SLOT_NO) || (index==FIFO_FUEL_1_SLOT_NO) || (index==FIFO_FUEL_0_SLOT_NO)) && 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(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();
if(facing == Direction.UP) return item_insertion_handler_.cast();
if(facing == Direction.DOWN) return item_extraction_handler_.cast();
return item_fuel_insertion_handler_.cast();
} else if(capability== CapabilityEnergy.ENERGY) {
return energy_handler_.cast();
}
@ -560,17 +481,16 @@ public class EdFurnace
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_ = (ExternalObjects.IE_EXTERNAL_HEATER==null) // without IE always allow electrical boost
|| (stacks_.get(AUX_0_SLOT_NO).getItem()==ExternalObjects.IE_EXTERNAL_HEATER)
|| (stacks_.get(AUX_1_SLOT_NO).getItem()==ExternalObjects.IE_EXTERNAL_HEATER);
if(!burning()) cleanupRecentRecipes();
|| (inventory_.getStackInSlot(AUX_0_SLOT_NO).getItem()==ExternalObjects.IE_EXTERNAL_HEATER)
|| (inventory_.getStackInSlot(AUX_1_SLOT_NO).getItem()==ExternalObjects.IE_EXTERNAL_HEATER);
}
ItemStack fuel = stacks_.get(SMELTING_FUEL_SLOT_NO);
if(burning() || (!fuel.isEmpty()) && (!(stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty())) {
ItemStack fuel = inventory_.getStackInSlot(SMELTING_FUEL_SLOT_NO);
if(burning() || (!fuel.isEmpty()) && (!(inventory_.getStackInSlot(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));
proc_time_needed_ = getSmeltingTimeNeeded(world, inventory_.getStackInSlot(SMELTING_INPUT_SLOT_NO));
}
if(!burning() && canSmeltCurrentItem()) {
burntime_left_ = (int)MathHelper.clamp((proc_fuel_efficiency_ * getFuelBurntime(world, fuel)), 0, MAX_BURNTIME);
@ -580,19 +500,18 @@ public class EdFurnace
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(fuel.isEmpty()) inventory_.setInventorySlotContents(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;
if(heater_inserted_ && battery_.draw(boost_energy_consumption)) {
proc_time_elapsed_ += (TICK_INTERVAL * proc_speed_)*2;
}
if(proc_time_elapsed_ >= proc_time_needed_) {
proc_time_elapsed_ = 0;
proc_time_needed_ = getSmeltingTimeNeeded(world, stacks_.get(SMELTING_INPUT_SLOT_NO));
proc_time_needed_ = getSmeltingTimeNeeded(world, inventory_.getStackInSlot(SMELTING_INPUT_SLOT_NO));
smeltCurrentItem();
dirty = true;
}
@ -624,10 +543,6 @@ public class EdFurnace
return world.getRecipeManager().getRecipe(recipe_type, inventory, world).orElse(null);
}
@Nullable
protected IRecipe currentRecipe()
{ return current_recipe_; }
public boolean burning()
{ return burntime_left_ > 0; }
@ -637,19 +552,19 @@ public class EdFurnace
AbstractCookingRecipe recipe = getSmeltingResult(RECIPE_TYPE, world, stack);
if(recipe == null) return 0;
int t = recipe.getCookTime();
return (t<=0) ? STD_SMELTING_TIME : t;
return (t<=0) ? DEFAULT_SMELTING_TIME : t;
}
private boolean transferItems(final int index_from, final int index_to, int count)
{
ItemStack from = stacks_.get(index_from);
ItemStack from = inventory_.getStackInSlot(index_from);
if(from.isEmpty()) return false;
ItemStack to = stacks_.get(index_to);
ItemStack to = inventory_.getStackInSlot(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));
inventory_.setInventorySlotContents(index_to, from.split(count));
} else if(to.getCount() >= to.getMaxStackSize()) {
changed = false;
} else if(Inventories.areItemStacksDifferent(from, to)) {
@ -664,7 +579,7 @@ public class EdFurnace
}
}
if(from.isEmpty() && from!=ItemStack.EMPTY) {
stacks_.set(index_from, ItemStack.EMPTY);
inventory_.setInventorySlotContents(index_from, ItemStack.EMPTY);
changed = true;
}
return changed;
@ -672,29 +587,30 @@ public class EdFurnace
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((currentRecipe()==null) || (inventory_.getStackInSlot(SMELTING_INPUT_SLOT_NO).isEmpty())) return false;
final ItemStack recipe_result_items = getSmeltingResult(inventory_.getStackInSlot(SMELTING_INPUT_SLOT_NO));
if(recipe_result_items.isEmpty()) return false;
final ItemStack result_stack = stacks_.get(SMELTING_OUTPUT_SLOT_NO);
final ItemStack result_stack = inventory_.getStackInSlot(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;
if(result_stack.getCount() + recipe_result_items.getCount() <= inventory_.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 smelting_input_stack = inventory_.getStackInSlot(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);
final ItemStack smelting_output_stack = inventory_.getStackInSlot(SMELTING_OUTPUT_SLOT_NO);
final float xp = getCurrentSmeltingXp(smelting_output_stack);
if(smelting_output_stack.isEmpty()) {
stacks_.set(SMELTING_OUTPUT_SLOT_NO, recipe_result_items.copy());
inventory_.setInventorySlotContents(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);
xp_stored_ += xp;
}
public static int getFuelBurntime(World world, ItemStack stack)
@ -705,50 +621,39 @@ public class EdFurnace
}
public static boolean isFuel(World world, ItemStack stack)
{ return getFuelBurntime(world, stack) > 0; }
{ return (getFuelBurntime(world, stack) > 0) || (stack.getItem()==Items.LAVA_BUCKET); }
public float getSmeltingExperience(ItemStack stack)
public int consumeSmeltingExperience(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;
if(xp_stored_ < 1) return 0;
float xp = xp_stored_;
if(xp >= 15) xp /= 2;
xp = Math.min((float)Math.floor(xp), 150);
xp_stored_ -= xp;
return (int)xp;
}
public ItemStack getSmeltingResult(final ItemStack stack)
{ return (currentRecipe()==null) ? (ItemStack.EMPTY) : (currentRecipe().getRecipeOutput()); }
public float getCurrentSmeltingXp(final ItemStack stack)
{
float xp = (currentRecipe() instanceof AbstractCookingRecipe) ? (((AbstractCookingRecipe)currentRecipe()).getExperience()) : (stack.getItem().getSmeltingExperience(stack));
return (xp <= 0) ? 0.7f : xp; // default value for recipes without defined xp
}
public static boolean canSmelt(World world, final ItemStack stack)
{ return getSmeltingResult(RECIPE_TYPE, world, stack) != null; }
@Nullable
protected IRecipe currentRecipe()
{ return current_recipe_; }
protected void updateCurrentRecipe()
{ setCurrentRecipe(getSmeltingResult(RECIPE_TYPE, world, stacks_.get(SMELTING_INPUT_SLOT_NO))); }
{ setCurrentRecipe(getSmeltingResult(RECIPE_TYPE, getWorld(), inventory_.getStackInSlot(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();
}
{ current_recipe_ = recipe; }
}
//--------------------------------------------------------------------------------------------------------------------
@ -806,15 +711,9 @@ public class EdFurnace
protected void onCrafting(ItemStack stack)
{
stack.onCrafting(player_.world, player_, removeCount);
if((!player_.world.isRemote) && (inventory_ instanceof FurnaceTileEntity)) {
FurnaceTileEntity te = (FurnaceTileEntity)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));
}
if((!player_.world.isRemote()) && (inventory_ instanceof StorageInventory)) {
FurnaceTileEntity te = (FurnaceTileEntity)(((StorageInventory)inventory_).getTileEntity());
int xp = te.consumeSmeltingExperience(stack);
while(xp > 0) {
int k = ExperienceOrbEntity.getXPSplit(xp);
xp -= k;
@ -1024,7 +923,7 @@ public class EdFurnace
{ 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) : (FurnaceTileEntity.STD_SMELTING_TIME))); }
{ int ibt = getContainer().field(1); return ((getContainer().field(0) * pixels) / ((ibt>0) ? (ibt) : (FurnaceTileEntity.DEFAULT_SMELTING_TIME))); }
}
}

View file

@ -96,6 +96,10 @@ public class EdHatchBlock extends DecorBlock.HorizontalWaterLoggable implements
world.setBlockState(pos, state.with(OPEN, powered).with(POWERED, powered), 1|2);
}
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
@Override
@SuppressWarnings("deprecation")
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity)

View file

@ -8,15 +8,11 @@
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.libmc.blocks.StandardBlocks;
import wile.engineersdecor.libmc.client.ContainerGui;
import wile.engineersdecor.libmc.detail.Auxiliaries;
import wile.engineersdecor.libmc.detail.Inventories.InventoryRange;
import wile.engineersdecor.libmc.detail.Networking;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.matrix.MatrixStack;
import javafx.util.Pair;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.world.World;
import net.minecraft.block.material.PushReaction;
import net.minecraft.block.Block;
@ -52,15 +48,21 @@ import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import com.mojang.blaze3d.platform.GlStateManager;
import com.mojang.blaze3d.matrix.MatrixStack;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.libmc.blocks.StandardBlocks;
import wile.engineersdecor.libmc.client.ContainerGui;
import wile.engineersdecor.libmc.detail.Auxiliaries;
import wile.engineersdecor.libmc.detail.Inventories;
import wile.engineersdecor.libmc.detail.Inventories.InventoryRange;
import wile.engineersdecor.libmc.detail.Inventories.StorageInventory;
import wile.engineersdecor.libmc.detail.Inventories.MappedItemHandler;
import wile.engineersdecor.libmc.detail.Networking;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class EdLabeledCrate
@ -96,6 +98,10 @@ public class EdLabeledCrate
public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos)
{ return Container.calcRedstone(world.getTileEntity(pos)); }
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@ -139,7 +145,7 @@ public class EdLabeledCrate
Auxiliaries.setItemLabel(stack, ((LabeledCrateTileEntity)te).getCustomName());
stacks.add(stack);
} else {
for(ItemStack stack: ((LabeledCrateTileEntity)te).stacks_) stacks.add(stack);
for(ItemStack stack: ((LabeledCrateTileEntity)te).main_inventory_) stacks.add(stack);
((LabeledCrateTileEntity)te).reset_getnbt();
}
return stacks;
@ -169,28 +175,40 @@ public class EdLabeledCrate
super.addInformation(stack, world, tooltip, flag);
return;
}
NonNullList<ItemStack> items = NonNullList.withSize(LabeledCrateTileEntity.NUM_OF_SLOTS, ItemStack.EMPTY);
int num_used_slots = 0;
int total_items = 0;
ItemStack frameStack = ItemStack.EMPTY;
int num_used_slots = 0, total_items = 0;
String stats = "";
if(stack.hasTag() && stack.getTag().contains("tedata")) {
final CompoundNBT nbt = stack.getTag().getCompound("tedata");
if(nbt.contains("Items")) {
ItemStackHelper.loadAllItems(nbt, items);
for(int i=0; i<LabeledCrateTileEntity.ITEMFRAME_SLOTNO; ++i) {
final ItemStack st = items.get(i);
if(st.isEmpty()) continue;
++num_used_slots;
total_items += st.getCount();
NonNullList<ItemStack> all_items = NonNullList.withSize(LabeledCrateTileEntity.NUM_OF_SLOTS, ItemStack.EMPTY);
ItemStackHelper.loadAllItems(nbt, all_items);
frameStack = all_items.get(LabeledCrateTileEntity.ITEMFRAME_SLOTNO);
all_items.set(LabeledCrateTileEntity.ITEMFRAME_SLOTNO, ItemStack.EMPTY);
Map<Item,Integer> item_map = new HashMap<>();
for(ItemStack e:all_items) { // ok, the whole stream map collector seems to be actually slower than a simple loop.
if(!e.isEmpty()) {
item_map.put(e.getItem(), item_map.getOrDefault(e.getItem(), 0) + e.getCount());
++num_used_slots;
total_items += e.getCount();
}
}
List<Pair<String,Integer>> itmes = new ArrayList<>();
for(Map.Entry<Item,Integer> e:item_map.entrySet()) itmes.add(new Pair<>(e.getKey().getTranslationKey(), e.getValue()));
itmes.sort((a,b)->b.getValue()-a.getValue());
boolean dotdotdot = false;
if(itmes.size() > 8) { itmes.subList(8, itmes.size()).clear(); dotdotdot = true; }
stats = itmes.stream().map(e->Auxiliaries.localize(e.getKey())).collect(Collectors.joining(", "));
if(dotdotdot) stats += "...";
}
}
int num_free_slots = LabeledCrateTileEntity.ITEMFRAME_SLOTNO - num_used_slots;
ItemStack frameStack = items.get(LabeledCrateTileEntity.ITEMFRAME_SLOTNO);
String[] lines = Auxiliaries.localize(getTranslationKey()+".tip", new Object[] {
String[] lines = Auxiliaries.localize(getTranslationKey()+".tip", new Object[] {
(frameStack.isEmpty() ? (new StringTextComponent("-/-")) : (new TranslationTextComponent(frameStack.getTranslationKey()))),
num_used_slots,
num_free_slots,
total_items
total_items,
stats
}).split("\n");
for(String line:lines) {
tooltip.add(new StringTextComponent(line.trim()));
@ -202,22 +220,28 @@ public class EdLabeledCrate
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class LabeledCrateTileEntity extends TileEntity implements INameable, IInventory, INamedContainerProvider, ISidedInventory
public static class LabeledCrateTileEntity extends TileEntity implements INameable, INamedContainerProvider, Networking.IPacketTileNotifyReceiver
{
public static final int NUM_OF_FIELDS = 1;
public static final int NUM_OF_SLOTS = 55;
public static final int ITEMFRAME_SLOTNO = 54;
public static final int NUM_OF_STORAGE_SLOTS = 54;
public static final int NUM_OF_STORAGE_ROWS = 6;
public static final int ITEMFRAME_SLOTNO = NUM_OF_STORAGE_SLOTS;
// BTileEntity -----------------------------------------------------------------------------
protected NonNullList<ItemStack> stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
protected final Inventories.StorageInventory main_inventory_ = new StorageInventory(this, NUM_OF_SLOTS, 1);
protected final InventoryRange storage_range_ = new InventoryRange(main_inventory_, 0, NUM_OF_STORAGE_SLOTS, NUM_OF_STORAGE_ROWS);
private @Nullable ITextComponent custom_name_;
public LabeledCrateTileEntity()
{ this(ModContent.TET_LABELED_CRATE); }
public LabeledCrateTileEntity(TileEntityType<?> te_type)
{ super(te_type); reset(); }
{
super(te_type); reset();
main_inventory_.setCloseAction(player->{
if(!getWorld().isRemote()) Networking.PacketTileNotifyServerToClient.sendToPlayers(this, writenbt(new CompoundNBT()));
});
}
public CompoundNBT reset_getnbt()
{
@ -228,31 +252,34 @@ public class EdLabeledCrate
}
protected void reset()
{
stacks_ = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
}
{ main_inventory_.clear(); }
public void readnbt(CompoundNBT nbt)
public CompoundNBT readnbt(CompoundNBT nbt)
{
NonNullList<ItemStack> stacks = NonNullList.<ItemStack>withSize(NUM_OF_SLOTS, ItemStack.EMPTY);
if(!nbt.isEmpty()) ItemStackHelper.loadAllItems(nbt, stacks);
while(stacks.size() < NUM_OF_SLOTS) stacks.add(ItemStack.EMPTY);
if(nbt.contains("name", NBT.TAG_STRING)) custom_name_ = Auxiliaries.unserializeTextComponent(nbt.getString("name"));
stacks_ = stacks;
main_inventory_.load(nbt);
return nbt;
}
protected void writenbt(CompoundNBT nbt)
protected CompoundNBT writenbt(CompoundNBT nbt)
{
if(custom_name_ != null) nbt.putString("name", Auxiliaries.serializeTextComponent(custom_name_));
if(!stacks_.stream().allMatch(ItemStack::isEmpty)) ItemStackHelper.saveAllItems(nbt, stacks_);
if(!main_inventory_.isEmpty()) main_inventory_.save(nbt);
return nbt;
}
public ItemStack getItemFrameStack()
{ return (stacks_.size() > ITEMFRAME_SLOTNO) ? (stacks_.get(ITEMFRAME_SLOTNO)) : (ItemStack.EMPTY); }
{ return main_inventory_.getStackInSlot(ITEMFRAME_SLOTNO); }
protected static boolean inacceptable(ItemStack stack)
{ return (stack.hasTag() && (!stack.getTag().isEmpty()) && (unstorable_containers.contains(stack.getItem()))); }
// IPacketTileNotifyReceiver ---------------------------------------------------------------
@Override
public void onServerPacketReceived(CompoundNBT nbt)
{ readnbt(nbt); }
// TileEntity ------------------------------------------------------------------------------
@Override
@ -281,11 +308,7 @@ public class EdLabeledCrate
@Override
public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) // on client
{
//@todo: check if needed: super.read(pkt.getNbtCompound());
readnbt(pkt.getNbtCompound());
super.onDataPacket(net, pkt);
}
{ readnbt(pkt.getNbtCompound()); super.onDataPacket(net, pkt); }
@Override
public void handleUpdateTag(BlockState state, CompoundNBT tag) // on client
@ -326,70 +349,7 @@ public class EdLabeledCrate
@Override
public Container createMenu(int id, PlayerInventory inventory, PlayerEntity player )
{ return new LabeledCrateContainer(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 >= 0) && (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)
{
if(stack.getCount() > getInventoryStackLimit()) stack.setCount(getInventoryStackLimit());
stacks_.set(index, stack);
markDirty();
if(getWorld() instanceof ServerWorld) {
// This should result in sending TE data (getUpdateTag etc) to the client for the TER.
BlockState state = world.getBlockState(getPos());
getWorld().notifyBlockUpdate(getPos(), state, state, 2|16|32);
}
}
@Override
public int getInventoryStackLimit()
{ return 64; }
@Override
public void markDirty()
{ super.markDirty(); }
@Override
public boolean isUsableByPlayer(PlayerEntity player)
{ return ((getWorld().getTileEntity(getPos()) == this)) && (getPos().distanceSq(player.getPosition()) < 64); }
@Override
public void openInventory(PlayerEntity player)
{}
@Override
public void closeInventory(PlayerEntity player)
{ markDirty(); }
@Override
public boolean isItemValidForSlot(int index, ItemStack stack)
{ return (index != ITEMFRAME_SLOTNO) && (!inacceptable(stack)); }
@Override
public void clear()
{ stacks_.clear(); }
{ return new LabeledCrateContainer(id, inventory, main_inventory_, IWorldPosCallable.of(world, pos), fields); }
// Fields -----------------------------------------------------------------------------------------------
@ -411,120 +371,13 @@ public class EdLabeledCrate
}
};
// ISidedInventory ----------------------------------------------------------------------------
private static final int[] SIDED_INV_SLOTS;
static {
// that useless unoptimised language ... no proper inline conv to int[]?
// private static final int[] SIDED_INV_SLOTS = IntStream.rangeClosed(0, BTileEntity.NUM_OF_SLOTS-2).boxed().collect(Collectors.toList()).toArray();
SIDED_INV_SLOTS = new int[LabeledCrateTileEntity.NUM_OF_SLOTS-1];
for(int i=0; i<SIDED_INV_SLOTS.length; ++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 true; }
@Override
public boolean canExtractItem(int index, ItemStack stack, Direction direction)
{ return true; }
// IItemHandler --------------------------------------------------------------------------------
protected static class BItemHandler implements IItemHandler
{
private LabeledCrateTileEntity te;
BItemHandler(LabeledCrateTileEntity te)
{ this.te = te; }
@Override
public int getSlots()
{ return ITEMFRAME_SLOTNO; } // iframe slot is the last
@Override
public int getSlotLimit(int index)
{ return te.getInventoryStackLimit(); }
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack)
{ return te.isItemValidForSlot(slot, stack); }
@Override
@Nonnull
public ItemStack insertItem(int slotno, @Nonnull ItemStack stack, boolean simulate)
{
if(stack.isEmpty()) return ItemStack.EMPTY;
if((slotno < 0) || ((slotno >= NUM_OF_SLOTS)) || ((slotno == ITEMFRAME_SLOTNO)) ) return stack;
if((!isItemValid(slotno, stack))) return stack;
ItemStack slotstack = getStackInSlot(slotno);
if(!slotstack.isEmpty()) {
if(slotstack.getCount() >= Math.min(slotstack.getMaxStackSize(), getSlotLimit(slotno))) 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(slotno)) - 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(slotno));
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((index < 0) || ((index >= NUM_OF_SLOTS)) || ((index == ITEMFRAME_SLOTNO)) ) return ItemStack.EMPTY;
if(!simulate) return ItemStackHelper.getAndSplit(te.stacks_, index, amount);
ItemStack stack = te.stacks_.get(index).copy();
if(stack.getCount() > amount) stack.setCount(amount);
return stack;
}
@Override
@Nonnull
public ItemStack getStackInSlot(int index)
{ return te.getStackInSlot(index); }
}
// Capability export ----------------------------------------------------------------------------
protected LazyOptional<IItemHandler> item_handler_ = LazyOptional.of(() -> new LabeledCrateTileEntity.BItemHandler(this));
protected LazyOptional<IItemHandler> item_handler_ = MappedItemHandler.createGenericHandler(storage_range_,
(slot,stack)->(slot!=ITEMFRAME_SLOTNO),
(slot,stack)->(slot!=ITEMFRAME_SLOTNO),
IntStream.range(0, NUM_OF_STORAGE_SLOTS).boxed().collect(Collectors.toList())
);
@Override
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
@ -589,6 +442,7 @@ public class EdLabeledCrate
player_ = player_inventory.player;
inventory_ = block_inventory;
wpc_ = wpc;
wpc_.consume((w,p)->inventory_.openInventory(player_));
fields_ = fields;
block_storage_range_ = new InventoryRange(inventory_, 0, LabeledCrateTileEntity.ITEMFRAME_SLOTNO);
player_inventory_range_ = new InventoryRange(player_inventory, 0, 36);
@ -624,7 +478,10 @@ public class EdLabeledCrate
@Override
public void onContainerClosed(PlayerEntity player)
{ super.onContainerClosed(player); }
{
super.onContainerClosed(player);
inventory_.closeInventory(player);
}
@Override
public ItemStack transferStackInSlot(PlayerEntity player, int index)

View file

@ -8,13 +8,11 @@
*/
package wile.engineersdecor.blocks;
import wile.engineersdecor.libmc.detail.Auxiliaries;
import wile.engineersdecor.libmc.detail.Fluidics;
import wile.engineersdecor.libmc.detail.Inventories;
import net.minecraftforge.common.util.Constants;
import wile.engineersdecor.libmc.detail.*;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.detail.ExternalObjects;
import wile.engineersdecor.libmc.detail.Overlay;
import net.minecraft.world.World;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.IBlockReader;
@ -97,6 +95,10 @@ public class EdMilker
return (te==null) ? 0 : MathHelper.clamp((16 * te.fluid_level())/MilkerTileEntity.TANK_CAPACITY, 0, 15);
}
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }
@ -153,7 +155,7 @@ public class EdMilker
// Tile entity
//--------------------------------------------------------------------------------------------------------------------
public static class MilkerTileEntity extends TileEntity implements ITickableTileEntity, IEnergyStorage, IFluidTank, ICapabilityProvider
public static class MilkerTileEntity extends TileEntity implements ITickableTileEntity, IFluidTank, ICapabilityProvider
{
public static final int BUCKET_SIZE = 1000;
public static final int TICK_INTERVAL = 80;
@ -171,21 +173,24 @@ public class EdMilker
private static FluidStack milk_fluid_ = NO_MILK_FLUID;
private static HashMap<ItemStack, ItemStack> milk_containers_ = new HashMap<>();
private static int energy_consumption = DEFAULT_ENERGY_CONSUMPTION;
private static long min_milking_delay_per_cow_ticks = DEFAULT_MILKING_DELAY_PER_COW;
private static int energy_consumption_ = DEFAULT_ENERGY_CONSUMPTION;
private static long min_milking_delay_per_cow_ticks_ = DEFAULT_MILKING_DELAY_PER_COW;
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;
private final RfEnergy.Battery battery_;
private final LazyOptional<IEnergyStorage> energy_handler_;
private final Fluidics.Tank tank_;
private final LazyOptional<IFluidHandler> fluid_handler_;
public static void on_config(int energy_consumption_per_tick, int min_milking_delay_per_cow)
{
energy_consumption = MathHelper.clamp(energy_consumption_per_tick, 0, 1024);
min_milking_delay_per_cow_ticks = MathHelper.clamp(min_milking_delay_per_cow, 1000, 24000);
energy_consumption_ = MathHelper.clamp(energy_consumption_per_tick, 0, 1024);
min_milking_delay_per_cow_ticks_ = MathHelper.clamp(min_milking_delay_per_cow, 1000, 24000);
{
ResourceLocation milk_rl = ForgeRegistries.FLUIDS.getKeys().stream().filter(rl->rl.getPath().equals("milk")).findFirst().orElse(null);
if(milk_rl != null) {
@ -198,7 +203,7 @@ public class EdMilker
if(ExternalObjects.BOTTLED_MILK_BOTTLE_DRINKLABLE!=null) milk_containers_.put(new ItemStack(Items.GLASS_BOTTLE), new ItemStack(ExternalObjects.BOTTLED_MILK_BOTTLE_DRINKLABLE));
}
ModEngineersDecor.logger().info(
"Config milker: energy consumption:" + energy_consumption + "rf/t"
"Config milker: energy consumption:" + energy_consumption_ + "rf/t"
+ ((milk_fluid_==NO_MILK_FLUID)?"":" [milk fluid available]")
+ ((ExternalObjects.BOTTLED_MILK_BOTTLE_DRINKLABLE==null)?"":" [bottledmilk mod available]")
);
@ -208,12 +213,19 @@ public class EdMilker
{ this(ModContent.TET_SMALL_MILKING_MACHINE); }
public MilkerTileEntity(TileEntityType<?> te_type)
{ super(te_type); reset(); }
{
super(te_type);
tank_ = new Fluidics.Tank(TANK_CAPACITY, 0, BUCKET_SIZE, (fs)->(has_milk_fluid() && fs.isFluidEqual(milk_fluid_)));
fluid_handler_ = tank_.createFluidHandler();
battery_ = new RfEnergy.Battery(MAX_ENERGY_BUFFER, MAX_ENERGY_TRANSFER, 0);
energy_handler_ = battery_.createEnergyHandler();
reset();
}
public void reset()
{
tank_level_ = 0;
energy_stored_ = 0;
tank_.clear();
battery_.clear();
tick_timer_ = 0;
tracked_cow_ = null;
state_ = MilkingState.IDLE;
@ -232,29 +244,29 @@ public class EdMilker
public void readnbt(CompoundNBT nbt, boolean update_packet)
{
tank_level_ = nbt.getInt("tank");
energy_stored_ = nbt.getInt("energy");
battery_.load(nbt);
tank_.load(nbt);
}
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_ );
tank_.save(nbt);
if(!battery_.isEmpty()) battery_.save(nbt);
}
private IFluidHandler fluid_handler()
{ return fluid_handler_.orElse(null); }
private int fluid_level()
{ return MathHelper.clamp(tank_level_, 0, TANK_CAPACITY); }
{ return tank_.getFluidAmount(); }
private void drain(int amount)
{ tank_level_ = MathHelper.clamp(tank_level_-BUCKET_SIZE, 0, TANK_CAPACITY); markDirty(); }
private FluidStack drain(int amount)
{ return tank_.drain(amount); }
public void state_message(PlayerEntity player)
{
ITextComponent rf = (energy_consumption <= 0) ? (new StringTextComponent("")) : (Auxiliaries.localizable("block.engineersdecor.small_milking_machine.status.rf", new Object[]{energy_stored_}));
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_milking_machine.status", new Object[]{tank_level_, rf}));
ITextComponent rf = (energy_consumption_ <= 0) ? (new StringTextComponent("")) : (Auxiliaries.localizable("block.engineersdecor.small_milking_machine.status.rf", new Object[]{battery_.getEnergyStored()}));
Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_milking_machine.status", new Object[]{tank_.getFluidAmount(), rf}));
}
// TileEntity ------------------------------------------------------------------------------
@ -275,30 +287,6 @@ public class EdMilker
fluid_handler_.invalidate();
}
// 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 ---------------------------------------------------------------------------------------
private LazyOptional<IFluidHandler> fluid_handler_ = LazyOptional.of(() -> (IFluidHandler)new Fluidics.SingleTankFluidHandler(this));
// IFluidTank ------------------------------------------------------------------------------------------
private boolean has_milk_fluid()
@ -335,10 +323,7 @@ public class EdMilker
public FluidStack drain(int maxDrain, FluidAction action)
{
if((!has_milk_fluid()) || (fluid_level() <= 0)) return FluidStack.EMPTY;
FluidStack fs = milk_fluid_.copy();
fs.setAmount(Math.min(fs.getAmount(), fluid_level()));
if(action==FluidAction.EXECUTE) tank_level_ -= fs.getAmount();
return fs;
return tank_.drain(maxDrain, action);
}
// ICapabilityProvider ---------------------------------------------------------------------------
@ -347,7 +332,7 @@ public class EdMilker
public <T> LazyOptional<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable Direction facing)
{
if((capability == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) && has_milk_fluid()) return fluid_handler_.cast();
if((capability == CapabilityEnergy.ENERGY) && (energy_consumption>0)) return energy_handler_.cast();
if((capability == CapabilityEnergy.ENERGY) && (energy_consumption_>0)) return energy_handler_.cast();
return super.getCapability(capability, facing);
}
@ -369,13 +354,13 @@ public class EdMilker
if(src==null) { src = dst; } else if(dst==null) { dst = src; }
if((src==null) || (dst==null)) return false;
boolean dirty = false;
while((tank_level_ >= BUCKET_SIZE)) {
while((tank_.getFluidAmount() >= BUCKET_SIZE)) {
boolean inserted = false;
for(Entry<ItemStack,ItemStack> e:milk_containers_.entrySet()) {
if(Inventories.extract(src, e.getKey(), 1, true).isEmpty()) continue;
if(!Inventories.insert(dst, e.getValue().copy(), false).isEmpty()) continue;
Inventories.extract(src, e.getKey(), 1, false);
tank_level_ -= BUCKET_SIZE;
tank_.drain(BUCKET_SIZE);
inserted = true;
dirty = true;
break;
@ -392,7 +377,7 @@ public class EdMilker
for(Direction dir:Direction.values()) {
int amount = Fluidics.fill(getWorld(), getPos().offset(dir), dir.getOpposite(), fs);
if(amount > 0) {
tank_level_ = Math.max(fluid_level() - amount, 0);
tank_.drain(amount);
return true;
}
}
@ -429,7 +414,7 @@ public class EdMilker
if(e.getUniqueID().equals(tracked_cow_)) return true;
if((tracked_cow_!=null) || e.isChild() || e.isInLove() || e.isBeingRidden()) return false;
if(!e.getNavigator().noPath()) return false;
if(Math.abs(tracked_cows_.getOrDefault(e.getEntityId(), 0L)-t) < min_milking_delay_per_cow_ticks) return false;
if(Math.abs(tracked_cows_.getOrDefault(e.getEntityId(), 0L)-t) < min_milking_delay_per_cow_ticks_) return false;
return true;
}
);
@ -512,7 +497,7 @@ public class EdMilker
return false;
}
case MILKING: {
tank_level_ = MathHelper.clamp(tank_level_+BUCKET_SIZE, 0, TANK_CAPACITY);
tank_.fill(milk_fluid_.copy(), FluidAction.EXECUTE);
state_timeout_ = 600;
state_ = MilkingState.LEAVING;
state_timer_ = 20;
@ -558,24 +543,19 @@ public class EdMilker
final BlockState block_state = world.getBlockState(pos);
if(!(block_state.getBlock() instanceof MilkerBlock)) return;
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);
}
if((energy_consumption_ > 0) && (!battery_.draw(energy_consumption_))) return;
// Track and milk cows
if(milking_process()) dirty = true;
// Fluid transfer
if((milk_fluid_.getAmount() > 0) && (fluid_level() >= BUCKET_SIZE)) {
if(has_milk_fluid() && (!tank_.isEmpty())) {
log("Fluid transfer");
for(Direction facing: FLUID_TRANSFER_DIRECTRIONS) {
IFluidHandler fh = FluidUtil.getFluidHandler(world, pos.offset(facing), facing.getOpposite()).orElse(null);
final 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);
final FluidStack fs = tank_.drain(BUCKET_SIZE, FluidAction.SIMULATE);
int nfilled = fh.fill(fs, FluidAction.EXECUTE);
if(nfilled <= 0) continue;
tank_level_ -= nfilled;
if(tank_level_ < 0) tank_level_ = 0;
tank_.drain(nfilled, FluidAction.EXECUTE);
dirty = true;
break;
}

View file

@ -9,6 +9,7 @@
*/
package wile.engineersdecor.blocks;
import net.minecraft.world.IWorldReader;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.world.IBlockReader;
@ -85,6 +86,10 @@ public class EdMineralSmelter
public int getComparatorInputOverride(BlockState state, World world, BlockPos pos)
{ return MathHelper.clamp((state.get(PHASE)*5), 0, 15); }
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }

View file

@ -9,6 +9,7 @@
*/
package wile.engineersdecor.blocks;
import net.minecraft.world.IWorldReader;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import net.minecraft.world.IWorld;
@ -143,6 +144,10 @@ public class EdPipeValve
public boolean canConnectRedstone(BlockState state, IBlockReader world, BlockPos pos, @Nullable Direction side)
{ return (side!=null) && (side!=state.get(FACING)) && (side!=state.get(FACING).getOpposite()); }
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
@Override
@SuppressWarnings("deprecation")
public boolean canProvidePower(BlockState state)

View file

@ -13,6 +13,7 @@ import net.minecraft.inventory.container.ClickType;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.block.*;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
import net.minecraft.tileentity.ITickableTileEntity;
@ -89,6 +90,10 @@ public class EdPlacer
public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos)
{ return Container.calcRedstone(world.getTileEntity(pos)); }
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }

View file

@ -8,6 +8,7 @@
*/
package wile.engineersdecor.blocks;
import net.minecraft.world.IWorldReader;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.libmc.detail.Auxiliaries;
@ -77,6 +78,10 @@ public class EdSolarPanel
if(te instanceof SolarPanelTileEntity) ((SolarPanelTileEntity)te).state_message(player);
return ActionResultType.CONSUME;
}
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
}
//--------------------------------------------------------------------------------------------------------------------

View file

@ -8,6 +8,7 @@
*/
package wile.engineersdecor.blocks;
import net.minecraft.world.IWorldReader;
import wile.engineersdecor.ModContent;
import wile.engineersdecor.ModEngineersDecor;
import wile.engineersdecor.detail.TreeCutting;
@ -95,6 +96,10 @@ public class EdTreeCutter
if(te instanceof TreeCutterTileEntity) ((TreeCutterTileEntity)te).state_message(player);
return ActionResultType.CONSUME;
}
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
}
//--------------------------------------------------------------------------------------------------------------------

View file

@ -23,6 +23,7 @@ import net.minecraft.util.text.StringTextComponent;
import net.minecraft.world.IBlockReader;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
@ -93,6 +94,10 @@ public class EdWasteIncinerator
public int getComparatorInputOverride(BlockState blockState, World world, BlockPos pos)
{ return Container.calcRedstone(world.getTileEntity(pos)); }
@Override
public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side)
{ return false; }
@Override
public boolean hasTileEntity(BlockState state)
{ return true; }

View file

@ -150,14 +150,10 @@ public class ModRenderers
double ox = tr[di][0], oy = tr[di][1], oz = tr[di][2];
float ry = (float)tr[di][3];
mxs.push();
//GlStateManager.disableLighting();
//RenderHelper.enableStandardItemLighting();
mxs.translate(0.5+ox, 0.5+oy, 0.5+oz);
mxs.rotate(Vector3f.YP.rotationDegrees(ry));
mxs.scale(scaler, scaler, scaler);
Minecraft.getInstance().getItemRenderer().renderItem(stack, net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType.FIXED, i5, i6, mxs, buf);
//RenderHelper.disableStandardItemLighting();
//GlStateManager.enableLighting();
mxs.pop();
} catch(Throwable e) {
if(--tesr_error_counter<=0) {

View file

@ -151,7 +151,7 @@ public class Auxiliaries
if(!r) m = "";
}
}
mt.appendReplacement(sb, (new TranslationTextComponent(m)).getString().trim());
mt.appendReplacement(sb, Matcher.quoteReplacement((new TranslationTextComponent(m)).getString().trim()));
}
mt.appendTail(sb);
return sb.toString();

View file

@ -16,9 +16,11 @@ import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidActionResult;
import net.minecraftforge.fluids.FluidStack;
@ -56,6 +58,19 @@ public class Fluidics
@Override public FluidStack drain(int maxDrain, FluidAction action) { return tank_.drain(maxDrain, action); }
}
private static class SingleTankOutputFluidHandler implements IFluidHandler
{
private final IFluidTank tank_;
public SingleTankOutputFluidHandler(IFluidTank tank) { tank_ = tank; }
@Override public int getTanks() { return 1; }
@Override public FluidStack getFluidInTank(int tank) { return tank_.getFluid().copy(); }
@Override public int getTankCapacity(int tank) { return tank_.getCapacity(); }
@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 tank_.drain(resource, action); }
@Override public FluidStack drain(int maxDrain, FluidAction action) { return tank_.drain(maxDrain, action); }
}
/**
* Simple fluid tank, validator concept according to reference implementation by KingLemming.
*/
@ -65,24 +80,41 @@ public class Fluidics
private BiConsumer<Tank,Integer> interaction_notifier_ = ((tank,diff)->{});
private FluidStack fluid_ = FluidStack.EMPTY;
private int capacity_;
private int fill_rate_;
private int drain_rate_;
public Tank(int capacity)
{ capacity_ = capacity; }
{ this(capacity, capacity, capacity); }
public Tank(int capacity, Predicate<FluidStack> validator)
{ capacity_ = capacity; setValidator(validator); }
public Tank(int capacity, int fill_rate, int drain_rate)
{ this(capacity, fill_rate, drain_rate, e->true); }
public Tank readnbt(CompoundNBT nbt)
{ setFluid(FluidStack.loadFluidStackFromNBT(nbt)); return this; }
public Tank(int capacity, int fill_rate, int drain_rate, Predicate<FluidStack> validator)
{
capacity_ = capacity;
setMaxFillRate(fill_rate);
setMaxDrainRate(drain_rate);
setValidator(validator);
}
public CompoundNBT writenbt()
{ return writenbt(new CompoundNBT()); }
public Tank load(CompoundNBT nbt)
{
if(nbt.contains("tank", Constants.NBT.TAG_COMPOUND)) {
setFluid(FluidStack.loadFluidStackFromNBT(nbt.getCompound("tank")));
} else {
clear();
}
return this;
}
public CompoundNBT writenbt(CompoundNBT nbt)
{ fluid_.writeToNBT(nbt); return nbt; }
public CompoundNBT save(CompoundNBT nbt)
{ if(!isEmpty()) { nbt.put("tank", fluid_.writeToNBT(new CompoundNBT())); } return nbt; }
public void reset()
{ setFluid(null); }
{ clear(); }
public Tank clear()
{ setFluid(null); return this; }
public int getCapacity()
{ return capacity_; }
@ -90,12 +122,32 @@ public class Fluidics
public Tank setCapacity(int capacity)
{ capacity_ = capacity; return this; }
public int getMaxDrainRate()
{ return drain_rate_; }
public Tank setMaxDrainRate(int rate)
{ drain_rate_ = MathHelper.clamp(rate, 0, capacity_); return this; }
public int getMaxFillRate()
{ return fill_rate_; }
public Tank setMaxFillRate(int rate)
{ fill_rate_ = MathHelper.clamp(rate, 0, capacity_); return this; }
public Tank setValidator(Predicate<FluidStack> validator)
{ validator_ = (validator!=null) ? validator : ((e)->true); return this; }
public Tank setInteractionNotifier(BiConsumer<Tank,Integer> notifier)
{ interaction_notifier_ = (notifier!=null) ? notifier : ((tank,diff)->{}); return this; }
public LazyOptional<IFluidHandler> createFluidHandler()
{ return LazyOptional.of(() -> new Fluidics.SingleTankFluidHandler(this)); }
public LazyOptional<IFluidHandler> createOutputFluidHandler()
{ return LazyOptional.of(() -> new Fluidics.SingleTankOutputFluidHandler(this)); }
// IFluidTank ------------------------------------------------------------------------------------
@Nonnull
public FluidStack getFluid()
{ return fluid_; }
@ -109,13 +161,19 @@ public class Fluidics
public boolean isEmpty()
{ return fluid_.isEmpty(); }
public boolean isFull()
{ return getFluidAmount() >= getCapacity(); }
public boolean isFluidValid(FluidStack stack)
{ return validator_.test(stack); }
public boolean isFluidEqual(FluidStack stack)
{ return (stack==null) ? (fluid_.isEmpty()) : fluid_.isFluidEqual(stack); }
@Override
public int fill(FluidStack fs, FluidAction action)
{
if(fs.isEmpty() || (!isFluidValid(fs))) {
if((fs==null) || fs.isEmpty() || (!isFluidValid(fs))) {
return 0;
} else if(action.simulate()) {
if(fluid_.isEmpty()) return Math.min(capacity_, fs.getAmount());

View file

@ -23,16 +23,20 @@ import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.ISidedInventory;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.wrapper.InvWrapper;
import net.minecraftforge.items.wrapper.SidedInvWrapper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@ -116,6 +120,169 @@ public class Inventories
return remaining;
}
//--------------------------------------------------------------------------------------------------------------------
public static class MappedItemHandler implements IItemHandler
{
private BiPredicate<Integer, ItemStack> extraction_predicate_;
private BiPredicate<Integer, ItemStack> insertion_predicate_;
private List<Integer> slot_map_;
private final IInventory inv_;
public MappedItemHandler(IInventory inv, List<Integer> slot_map, BiPredicate<Integer, ItemStack> extraction_predicate, BiPredicate<Integer, ItemStack> insertion_predicate)
{ inv_ = inv; extraction_predicate_ = extraction_predicate; insertion_predicate_ = insertion_predicate; slot_map_ = slot_map; }
public MappedItemHandler(IInventory inv, BiPredicate<Integer, ItemStack> extraction_predicate, BiPredicate<Integer, ItemStack> insertion_predicate)
{ this(inv, IntStream.range(0, inv.getSizeInventory()).boxed().collect(Collectors.toList()), extraction_predicate, insertion_predicate); }
public MappedItemHandler(IInventory inv)
{ this(inv, (i,s)->true, (i,s)->true); }
@Override
public int hashCode()
{ return inv_.hashCode(); }
@Override
public boolean equals(Object o)
{ return (o==this) || ((o!=null) && (getClass()==o.getClass()) && (inv_.equals(((MappedItemHandler)o).inv_))); }
// IItemHandler -----------------------------------------------------------------------------------------------
@Override
public int getSlots()
{ return slot_map_.size(); }
@Override
@Nonnull
public ItemStack getStackInSlot(int slot)
{ return (slot >= slot_map_.size()) ? ItemStack.EMPTY : inv_.getStackInSlot(slot_map_.get(slot)); }
@Override
public int getSlotLimit(int slot)
{ return inv_.getInventoryStackLimit(); }
@Override
public boolean isItemValid(int slot, @Nonnull ItemStack stack)
{
if(slot >= slot_map_.size()) return false;
slot = slot_map_.get(slot);
return insertion_predicate_.test(slot, stack) && inv_.isItemValidForSlot(slot, stack);
}
@Override
@Nonnull
public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate)
{
if(stack.isEmpty()) return ItemStack.EMPTY;
if(slot >= slot_map_.size()) return stack;
slot = slot_map_.get(slot);
if(!insertion_predicate_.test(slot, stack)) return stack;
if(!inv_.isItemValidForSlot(slot, stack)) return stack;
ItemStack sst = inv_.getStackInSlot(slot);
final int slot_limit = inv_.getInventoryStackLimit();
if(!sst.isEmpty()) {
if(sst.getCount() >= Math.min(sst.getMaxStackSize(), slot_limit)) return stack;
if(!ItemHandlerHelper.canItemStacksStack(stack, sst)) return stack;
final int limit = Math.min(stack.getMaxStackSize(), slot_limit) - sst.getCount();
if(stack.getCount() <= limit) {
if(!simulate) {
stack = stack.copy();
stack.grow(sst.getCount());
inv_.setInventorySlotContents(slot, stack);
inv_.markDirty();
}
return ItemStack.EMPTY;
} else {
stack = stack.copy();
if(simulate) {
stack.shrink(limit);
} else {
ItemStack diff = stack.split(limit);
diff.grow(sst.getCount());
inv_.setInventorySlotContents(slot, diff);
inv_.markDirty();
}
return stack;
}
} else {
final int limit = Math.min(slot_limit, stack.getMaxStackSize());
if(stack.getCount() >= limit) {
stack = stack.copy();
if(simulate) {
stack.shrink(limit);
} else {
inv_.setInventorySlotContents(slot, stack.split(limit));
inv_.markDirty();
}
return stack;
} else {
if(!simulate) {
inv_.setInventorySlotContents(slot, stack.copy());
inv_.markDirty();
}
return ItemStack.EMPTY;
}
}
}
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate)
{
if(amount <= 0) return ItemStack.EMPTY;
if(slot >= slot_map_.size()) return ItemStack.EMPTY;
slot = slot_map_.get(slot);
ItemStack stack = inv_.getStackInSlot(slot);
if(!extraction_predicate_.test(slot, stack)) return ItemStack.EMPTY;
if(simulate) {
stack = stack.copy();
if(amount < stack.getCount()) stack.setCount(amount);
} else {
stack = inv_.decrStackSize(slot, Math.min(stack.getCount(), amount));
inv_.markDirty();
}
return stack;
}
// Factories --------------------------------------------------------------------------------------------
public static LazyOptional<IItemHandler> createGenericHandler(IInventory inv, BiPredicate<Integer, ItemStack> extraction_predicate, BiPredicate<Integer, ItemStack> insertion_predicate, List<Integer> slot_map)
{ return LazyOptional.of(() -> new MappedItemHandler(inv, slot_map, extraction_predicate, insertion_predicate)); }
public static LazyOptional<IItemHandler> createGenericHandler(IInventory inv, BiPredicate<Integer, ItemStack> extraction_predicate, BiPredicate<Integer, ItemStack> insertion_predicate)
{ return LazyOptional.of(() -> new MappedItemHandler(inv, extraction_predicate, insertion_predicate)); }
public static LazyOptional<IItemHandler> createGenericHandler(IInventory inv)
{ return LazyOptional.of(() -> new MappedItemHandler(inv)); }
public static LazyOptional<IItemHandler> createExtractionHandler(IInventory inv, BiPredicate<Integer, ItemStack> extraction_predicate, List<Integer> slot_map)
{ return LazyOptional.of(() -> new MappedItemHandler(inv, slot_map, extraction_predicate, (i, s)->false)); }
public static LazyOptional<IItemHandler> createExtractionHandler(IInventory inv, BiPredicate<Integer, ItemStack> extraction_predicate)
{ return LazyOptional.of(() -> new MappedItemHandler(inv, extraction_predicate, (i, s)->false)); }
public static LazyOptional<IItemHandler> createExtractionHandler(IInventory inv, Integer... slots)
{ return LazyOptional.of(() -> new MappedItemHandler(inv, Arrays.asList(slots), (i, s)->true, (i, s)->false)); }
public static LazyOptional<IItemHandler> createExtractionHandler(IInventory inv)
{ return LazyOptional.of(() -> new MappedItemHandler(inv, (i, s)->true, (i, s)->false)); }
public static LazyOptional<IItemHandler> createInsertionHandler(IInventory inv, BiPredicate<Integer, ItemStack> insertion_predicate, List<Integer> slot_map)
{ return LazyOptional.of(() -> new MappedItemHandler(inv, slot_map, (i, s)->false, insertion_predicate)); }
public static LazyOptional<IItemHandler> createInsertionHandler(IInventory inv, Integer... slots)
{ return LazyOptional.of(() -> new MappedItemHandler(inv, Arrays.asList(slots), (i, s)->false, (i, s)->true)); }
public static LazyOptional<IItemHandler> createInsertionHandler(IInventory inv, BiPredicate<Integer, ItemStack> insertion_predicate)
{ return LazyOptional.of(() -> new MappedItemHandler(inv, (i, s)->false, insertion_predicate)); }
public static LazyOptional<IItemHandler> createInsertionHandler(IInventory inv)
{ return LazyOptional.of(() -> new MappedItemHandler(inv, (i, s)->false, (i, s)->true)); }
}
//--------------------------------------------------------------------------------------------------------------------
public static class InventoryRange implements IInventory, Iterable<ItemStack>
{
public final IInventory inventory;
@ -385,6 +552,9 @@ public class Inventories
return changed;
}
public boolean move(final InventoryRange target_range, boolean only_fillup)
{ return move(target_range, only_fillup, false, true); }
public boolean move(final InventoryRange target_range)
{ return move(target_range, false, false, true); }
@ -428,6 +598,9 @@ public class Inventories
protected Consumer<PlayerEntity> open_action_ = (player)->{};
protected Consumer<PlayerEntity> close_action_ = (player)->{};
public StorageInventory(TileEntity te, int size)
{ this(te, size, 1); }
public StorageInventory(TileEntity te, int size, int num_rows)
{
te_ = te;
@ -442,16 +615,22 @@ public class Inventories
public CompoundNBT save(CompoundNBT nbt, boolean save_empty)
{ return ItemStackHelper.saveAllItems(nbt, stacks_, save_empty); }
public CompoundNBT save(boolean save_empty)
{ return save(new CompoundNBT(), save_empty); }
public StorageInventory load(CompoundNBT nbt)
{
stacks_.clear();
ItemStackHelper.loadAllItems(nbt, stacks_);
while(stacks_.size() < size_) stacks_.add(ItemStack.EMPTY);
return this;
}
public NonNullList<ItemStack> stacks()
{ return stacks_; }
public TileEntity getTileEntity()
{ return te_; }
public StorageInventory setOpenAction(Consumer<PlayerEntity> fn)
{ open_action_ = fn; return this; }
@ -461,6 +640,9 @@ public class Inventories
public StorageInventory setStackLimit(int max_slot_stack_size)
{ stack_limit_ = Math.max(max_slot_stack_size, 1); return this; }
public StorageInventory setValidator(BiPredicate<Integer, ItemStack> validator)
{ validator_ = validator; return this; }
// Iterable<ItemStack> ---------------------------------------------------------------------
public Iterator<ItemStack> iterator()
@ -521,7 +703,7 @@ public class Inventories
@Override
public void clear()
{ stacks_.clear(); }
{ stacks_.clear(); markDirty(); }
}
@ -541,6 +723,13 @@ public class Inventories
//--------------------------------------------------------------------------------------------------------------------
public static IInventory readNbtStacks(CompoundNBT nbt, String key, IInventory target)
{
NonNullList<ItemStack> stacks = Inventories.readNbtStacks(nbt, key, target.getSizeInventory());
for(int i=0; i<stacks.size(); ++i) target.setInventorySlotContents(i, stacks.get(i));
return target;
}
public static NonNullList<ItemStack> readNbtStacks(CompoundNBT nbt, String key, int size)
{
NonNullList<ItemStack> stacks = NonNullList.withSize(size, ItemStack.EMPTY);

View file

@ -111,6 +111,12 @@ public class Networking
DEFAULT_CHANNEL.sendTo(new PacketTileNotifyServerToClient(te, nbt), ((ServerPlayerEntity)player).connection.netManager, NetworkDirection.PLAY_TO_CLIENT);
}
public static void sendToPlayers(TileEntity te, CompoundNBT nbt)
{
if(te==null) return;
for(PlayerEntity player: te.getWorld().getPlayers()) sendToPlayer(player, te, nbt);
}
public PacketTileNotifyServerToClient()
{}

View file

@ -0,0 +1,142 @@
/*
* @file RfEnergy.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2020 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* General RF/FE energy handling functionality.
*/
package wile.engineersdecor.libmc.detail;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.energy.IEnergyStorage;
public class RfEnergy
{
public static class Battery implements IEnergyStorage
{
protected int capacity_;
protected int charge_rate_;
protected int discharge_rate_;
protected int energy_;
public Battery(int capacity)
{ this(capacity, capacity); }
public Battery(int capacity, int transfer_rate)
{ this(capacity, transfer_rate, transfer_rate, 0); }
public Battery(int capacity, int charge_rate, int discharge_rate)
{ this(capacity, charge_rate, discharge_rate, 0); }
public Battery(int capacity, int charge_rate, int discharge_rate, int energy)
{
capacity_ = Math.max(capacity, 1);
charge_rate_ = MathHelper.clamp(charge_rate, 0, capacity_);
discharge_rate_ = MathHelper.clamp(discharge_rate, 0, capacity_);
energy_ = MathHelper.clamp(energy, 0, capacity_);
}
// ---------------------------------------------------------------------------------------------------
public Battery setMaxEnergyStored(int capacity)
{ capacity_ = Math.max(capacity, 1); return this; }
public Battery setEnergyStored(int energy)
{ energy_ = MathHelper.clamp(energy, 0, capacity_); return this; }
public Battery setChargeRate(int in_rate)
{ charge_rate_ = MathHelper.clamp(in_rate, 0, capacity_); return this; }
public Battery setDischargeRate(int out_rate)
{ discharge_rate_ = MathHelper.clamp(out_rate, 0, capacity_); return this; }
public int getChargeRate()
{ return charge_rate_; }
public int getDischargeRate()
{ return discharge_rate_; }
public boolean isEmpty()
{ return energy_ <= 0; }
public boolean isFull()
{ return energy_ >= capacity_; }
public int getSOC()
{ return (int)MathHelper.clamp((100.0 * energy_ / capacity_ + .5), 0, 100); }
public int getComparatorOutput()
{ return (int)MathHelper.clamp((15.0 * energy_ / capacity_ + .2), 0, 15); }
public boolean draw(int energy)
{
if(energy_ < energy) return false;
energy_ -= energy;
return true;
}
public boolean feed(int energy)
{
energy_ = Math.min(energy_+energy, capacity_);
return energy_ >= capacity_;
}
public Battery clear()
{ energy_ = 0; return this; }
public Battery load(CompoundNBT nbt, String key)
{ setEnergyStored(nbt.getInt(key)); return this; }
public Battery load(CompoundNBT nbt)
{ return load(nbt, "Energy"); }
public CompoundNBT save(CompoundNBT nbt, String key)
{ nbt.putInt(key, energy_); return nbt; }
public CompoundNBT save(CompoundNBT nbt)
{ return save(nbt, "Energy"); }
public LazyOptional<IEnergyStorage> createEnergyHandler()
{ return LazyOptional.of(() -> (IEnergyStorage)this); }
// IEnergyStorage ------------------------------------------------------------------------------------
@Override
public int receiveEnergy(int feed_energy, boolean simulate)
{
if(!canReceive()) return 0;
int e = Math.min(Math.min(charge_rate_, feed_energy), capacity_-energy_);
if(!simulate) energy_ += e;
return e;
}
@Override
public int extractEnergy(int draw_energy, boolean simulate)
{
if(!canExtract()) return 0;
int e = Math.min(Math.min(discharge_rate_, draw_energy), energy_);
if(!simulate) energy_ -= e;
return e;
}
@Override
public int getEnergyStored()
{ return energy_; }
@Override
public int getMaxEnergyStored()
{ return capacity_; }
@Override
public boolean canExtract()
{ return discharge_rate_ > 0; }
@Override
public boolean canReceive()
{ return charge_rate_ > 0; }
}
}

View file

@ -140,12 +140,12 @@
"block.engineersdecor.iron_floor_edge_light": "Inset Floor Edge Light",
"block.engineersdecor.iron_floor_edge_light.help": "Small glowstone light source,\n placed at the edge of a floor\n block. Useful to light up places\n where electrical light\n installations are problematic.",
"block.engineersdecor.iron_hatch": "Iron Hatch",
"block.engineersdecor.iron_hatch.help": "An upside down trapdoor, placed\n above mainenance shafts or ladders.\n Creeper-proof, works as ladder\n when open.",
"block.engineersdecor.iron_hatch.help": "An upside down trapdoor, placed\n above maintenance shafts or ladders.\n Creeper-proof, works as ladder\n when open.",
"block.engineersdecor.iron_inset_light": "Inset Light",
"block.engineersdecor.iron_inset_light.help": "Small glowstone light source, sunk\n into the floor, ceiling or wall.\n Useful to light up places where\n electrical light installations\n are problematic.",
"block.engineersdecor.labeled_crate": "Labeled Crate",
"block.engineersdecor.labeled_crate.help": "A storage crate with 9x6 slots and\n a built-in item frame at the front.\n Place an item into the frame slot\n at the bottom right of the GUI to\n define the shown label.",
"block.engineersdecor.labeled_crate.tip": "§6Label:§r %1$s\n%2$s slots used / %3$s free\n%4$s total items stored",
"block.engineersdecor.labeled_crate.tip": "§6Label:§r %1$s\n%2$s slots used / %3$s free\n%4$s total items stored\n---\n%5$s",
"block.engineersdecor.metal_crafting_table": "Metal Crafting Table",
"block.engineersdecor.metal_crafting_table.help": "Decorative crafting table with\n advanced features. Eighteen storage\n slots, keeps inventory, no vanilla\n recipe book. Click up/down arrow\n buttons for crafting history\n selection, output slot for item\n placement, X-button to clear\n crafting grid and history.\n Shift-click stack: player-to-storage\n stack transfer when crafting grid\n empty, otherwise player-to-grid\n stack transfer. Automatically\n distributes the clicked stack.\n Shift-Ctrl-click stack: Move all\n same stacks. Mouse wheel over\n crafting slot: Increase/decrease\n crafting grid items.",
"block.engineersdecor.metal_crafting_table.tooltips.clear": "Clear grid to player inventory",
@ -167,7 +167,7 @@
"block.engineersdecor.old_industrial_wood_slabslice": "Old Industrial Wood Slab Slice",
"block.engineersdecor.old_industrial_wood_stairs": "Old Industrial Wood Stairs",
"block.engineersdecor.panzerglass_block": "Panzer Glass Block",
"block.engineersdecor.panzerglass_block.help": "Reinforced glass block.\n Expensive, explosion-proof.\n Dark gray tint, faint structural\n lines visible, multi texture for\n seemless look.",
"block.engineersdecor.panzerglass_block.help": "Reinforced glass block.\n Expensive, explosion-proof.\n Dark gray tint, faint structural\n lines visible, multi texture for\n seamless look.",
"block.engineersdecor.panzerglass_slab": "Panzer Glass Slab",
"block.engineersdecor.panzerglass_slab.help": "Reinforced glass slab.\n Expensive, explosion-proof.\n Dark gray tint, faint structural\n lines visible.",
"block.engineersdecor.rebar_concrete": "Rebar Concrete Block",
@ -223,7 +223,7 @@
"block.engineersdecor.small_lab_furnace": "Small Laboratory Furnace",
"block.engineersdecor.small_lab_furnace.help": "Small metal cased lab kiln. Solid\n fuel consuming, updraught. Slightly\n hotter and better isolated than a\n cobblestone furnace, therefore\n more efficient. Two auxiliary\n slots e.g. for storage. Two stack\n internal hopper fifos for input,\n output, and fuel. Place an\n external heater into a aux slot\n and connect power for electrical\n smelting speed boost.",
"block.engineersdecor.small_milking_machine": "Small Milking Machine",
"block.engineersdecor.small_milking_machine.help": "Occasionally milks cows. Has an\n internal fluid tank. Does not\n feed the animals. Use buckets to\n retrieve the milk. Pulls/stores\n milk container items from/to\n inventories at the back or bottom\n (preferrs extracting from the\n back and inserting below, but can\n also put filled vessels back into\n the same inventory). Supports fluid\n output to tanks or pipes below\n (only if milk exists as fluid).\n Care that it's not too crowdy in\n the cow pen, only happy animals\n stroll by voluntarily.",
"block.engineersdecor.small_milking_machine.help": "Occasionally milks cows. Has an\n internal fluid tank. Does not\n feed the animals. Use buckets to\n retrieve the milk. Pulls/stores\n milk container items from/to\n inventories at the back or bottom\n (prefers extracting from the\n back and inserting below, but can\n also put filled vessels back into\n the same inventory). Supports fluid\n output to tanks or pipes below\n (only if milk exists as fluid).\n Care that it's not too crowdy in\n the cow pen, only happy animals\n stroll by voluntarily.",
"block.engineersdecor.small_milking_machine.status": "Milk: %1$smB %2$s",
"block.engineersdecor.small_milking_machine.status.rf": "| %1$sRF",
"block.engineersdecor.small_mineral_smelter": "Small Mineral Melting Furnace",
@ -232,14 +232,14 @@
"block.engineersdecor.small_solar_panel.help": "Produces a small amount of power\n when exposed to sunlight. Useful\n for charging LF capacitors in remote\n systems with low consumption. The\n internal charge pump circuit\n accumulates and frequently\n transfers RF. Production depends\n on day time and the weather.\nClick to see State Of Charge,\n production, and progress.",
"block.engineersdecor.small_solar_panel.status": "SOC: %1$s%% of %2$sRF§r | producing %3$sRF/t | feeding %4$sRF/t",
"block.engineersdecor.small_tree_cutter": "Small Tree Cutter",
"block.engineersdecor.small_tree_cutter.help": "Chops grown trees in front of it.\n Does not collect the lumbers.\n Deactivate with a redstone signal.\n ${!tree_cuttter_requires_power?engineersdecor.tooltip.massive_speed_boost_with_rf_power} ${tree_cuttter_requires_power?engineersdecor.tooltip.requires_rf_power}",
"block.engineersdecor.small_tree_cutter.help": "Chops grown trees in front of it.\n Does not collect the lumbers.\n Deactivate with a redstone signal.\n ${!tree_cutter_requires_power?engineersdecor.tooltip.massive_speed_boost_with_rf_power} ${tree_cutter_requires_power?engineersdecor.tooltip.requires_rf_power}",
"block.engineersdecor.small_tree_cutter.status": "SOC: %1$s%% of %2$sRF§r | progress: %3$s%% (%4$ss)",
"block.engineersdecor.small_waste_incinerator": "Small Waste Incinerator",
"block.engineersdecor.small_waste_incinerator.help": "Trash with internal fifo slots.\n Items can be inserted on all sides,\n and are kept until there is no\n space left in the fifo. After that\n the oldest stack will be incinerated.\n Apply electrical RF/FE power to\n increase the processing speed.\n Keeps its inventory when being\n relocated.",
"block.engineersdecor.steel_catwalk": "Steel Catwalk",
"block.engineersdecor.steel_catwalk.help": "Simple catwalk for better access to\nbig machines. Can also be placed in\nlook direction from the top. Click\nwith a Railing to add the guardrail\nto a side (close click: exact\nplacemend, far click: auto best\nmatch). Click again to remove a\nguardrail.",
"block.engineersdecor.steel_catwalk.help": "Simple catwalk for better access to\nbig machines. Can also be placed in\nlook direction from the top. Click\nwith a Railing to add the guardrail\nto a side (close click: exact\nplacement, far click: auto best\nmatch). Click again to remove a\nguardrail.",
"block.engineersdecor.steel_catwalk_stairs": "Steel Catwalk Stairs",
"block.engineersdecor.steel_catwalk_stairs.help": "Click with a Steel Railing to add\nor remove guardrails. Cannot be\nplaced bottom-down, no corners\n(no'normal' Stairs).",
"block.engineersdecor.steel_catwalk_stairs.help": "Click with a Steel Railing to add\nor remove guardrails. Cannot be\nplaced bottom-down, no corners\n(no 'normal' Stairs).",
"block.engineersdecor.steel_catwalk_ta": "Raised Steel Catwalk",
"block.engineersdecor.steel_catwalk_ta.help": "Top aligned Catwalk, connects to\nSteel poles below.",
"block.engineersdecor.steel_double_t_support": "Steel Double T Support",

View file

@ -145,7 +145,7 @@
"block.engineersdecor.iron_inset_light.help": "Маленький источник света, интегрируемый в стены, пол или потолок.\n Полезно для освещения мест, где проблематичны электрические осветительные установки.",
"block.engineersdecor.labeled_crate": "Ящик с рамкой",
"block.engineersdecor.labeled_crate.help": "Ящик для хранения со слотами 9x6 и встроенной рамкой для предмета спереди.\nПоместите предмет в слот рамки в правом нижнем углу GUI, чтобы обозначить ящик.",
"block.engineersdecor.labeled_crate.tip": "§6Метка:§r %1$s\n%2$s слотов использовано / %3$s свободно\n%4$s общее количество хранимых предметов",
"block.engineersdecor.labeled_crate.tip": "§6Метка:§r %1$s\n%2$s слотов использовано / %3$s свободно\n%4$s общее количество хранимых предметов\n---\n%5$s",
"block.engineersdecor.metal_crafting_table": "Верстак из обработанного дерева",
"block.engineersdecor.metal_crafting_table.help": "Прочный и устойчивый к погодным условиям. Восемь слотов для хранения. Хранит инвентарь. Нажимайте кнопки со стрелками вверх/вниз для выбора из истории, выходной слот для размещения предметов, X-кнопка очистить сетку крафта и историю. Shift-клик по стеку: передача стека от игрока в хранилище при создании если сетка пуста, в противном случае перенос от игрока в сетку. Автоматически распределяет кликаемый стек. Shift-Ctrl-клик по стаку: перемещает одинаковые стаки. Колёсико мыши: добавляет/отнимает предметы в сетке.",
"block.engineersdecor.metal_crafting_table.tooltips.clear": "Очистить сетку в инвентарь игрока",
@ -232,7 +232,7 @@
"block.engineersdecor.small_solar_panel.help": "Вырабатывает небольшое количество энергии при воздействии солнечного света.\n Полезно для зарядки низковольтных конденсаторов в удаленных системах с низким потреблением.\nВнутренний контур насоса накапливает и часто передает RF.\nПроизводство зависит от времени суток и погоды.",
"block.engineersdecor.small_solar_panel.status": "SOC: %1$s%% из %2$sRF§r | производит %3$sRF/тик | отдаёт %4$sRF/тик",
"block.engineersdecor.small_tree_cutter": "Малый лесоруб",
"block.engineersdecor.small_tree_cutter.help": "Вырубает деревья перед ним.\n Не собирает срубленное. Выключается с помощью сигнала красного камня. ${!tree_cuttter_requires_power?engineersdecor.tooltip.massive_speed_boost_with_rf_power} ${tree_cuttter_requires_power?engineersdecor.tooltip.requires_rf_power}",
"block.engineersdecor.small_tree_cutter.help": "Вырубает деревья перед ним.\n Не собирает срубленное. Выключается с помощью сигнала красного камня. ${!tree_cutter_requires_power?engineersdecor.tooltip.massive_speed_boost_with_rf_power} ${tree_cutter_requires_power?engineersdecor.tooltip.requires_rf_power}",
"block.engineersdecor.small_tree_cutter.status": "SOC: %1$s%% из %2$sRF§r | прогресс: %3$s%% (%4$sсек)",
"block.engineersdecor.small_waste_incinerator": "Компактный сжигатель отходов",
"block.engineersdecor.small_waste_incinerator.help": "Отходы с слотами для очереди. Предметы могут помещаться с любой стороны,\nи храниться до тех пор, пока в очереди не останется свободного места.\nПосле этого самый старый стек будет сожжен. Подключите электричество (RF/FE)\nдля увеличения скорости обработки.\nСохраняет инвентарь при перемещении.",

View file

@ -145,7 +145,7 @@
"block.engineersdecor.iron_inset_light.help": "§6小型荧石光源能嵌入地板、天花板或墙里。§r\n 用于照亮电力光源难以安装的地方。 亮度与火把一样。",
"block.engineersdecor.labeled_crate": "贴标签的板条箱",
"block.engineersdecor.labeled_crate.help": "§6具备 9x6 大小格子的木箱前面自带一个物品展示框。§r\n将物品放置在 GUI 右下角的框架槽内,可以定义所显示的标签。",
"block.engineersdecor.labeled_crate.tip": "§6标签§r %1$s\n已使用 %2$s / 剩余 %3$s \n共存储 %4$s 件物品",
"block.engineersdecor.labeled_crate.tip": "§6标签§r %1$s\n已使用 %2$s / 剩余 %3$s \n共存储 %4$s 件物品\n---\n%5$s",
"block.engineersdecor.metal_crafting_table": "防腐木合成台",
"block.engineersdecor.metal_crafting_table.help": "§6坚固防风防雨。§r内含八个存储格破坏后保留内容物没有原版合成书。\n 单击上/下箭头按钮可选择合成历史单击输出格自动放置物品单击X按钮 清除合成栏和历史。Shift单击一叠物品合成格空时转移到存储格 非空时到合成栏。会自动分配转移的物品。",
"block.engineersdecor.metal_crafting_table.tooltips.clear": "Clear grid to player inventory",

View file

@ -0,0 +1,30 @@
{
"type": "forge:conditional",
"recipes": [
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:clinker_brick_block"
}
],
"recipe": {
"type": "minecraft:crafting_shaped",
"pattern": [
"BAB",
"ANA",
"BAB"
],
"key": {
"A": { "item": "minecraft:brick" },
"B": { "tag" : "engineersdecor:brick_ingots" },
"N": { "item": "minecraft:bricks" }
},
"result": {
"item": "engineersdecor:clinker_brick_block",
"count": 8
}
}
}
]
}

View file

@ -1,6 +1,30 @@
{
"type": "forge:conditional",
"recipes": [
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:treated_wood_ladder",
"required": ["#forge:treated_wood"]
}
],
"recipe": {
"type": "minecraft:crafting_shaped",
"pattern": [
"S S",
"SSS",
"S S"
],
"key": {
"S": { "tag": "forge:treated_wood" }
},
"result": {
"item": "engineersdecor:treated_wood_ladder",
"count": 8
}
}
},
{
"conditions": [
{
@ -21,31 +45,7 @@
},
"result": {
"item": "engineersdecor:treated_wood_ladder",
"count": 6
}
}
},
{
"conditions": [
{
"type": "engineersdecor:optional",
"result": "engineersdecor:treated_wood_ladder",
"required": ["minecraft:ladder"]
}
],
"recipe": {
"type": "minecraft:crafting_shaped",
"pattern": [
"S S",
"SSS",
"S S"
],
"key": {
"S": { "item": "minecraft:ladder"}
},
"result": {
"item": "engineersdecor:treated_wood_ladder",
"count": 7
"count": 8
}
}
}