From 80bf3fd5f64564d92d664f17e83a3a34159842ad Mon Sep 17 00:00:00 2001 From: stfwi Date: Fri, 5 Apr 2019 16:12:32 +0200 Subject: [PATCH] Fixed window rendering issue (#15). Lab furnace electrical speed-up implemented. --- 1.12/gradle.properties | 2 +- 1.12/meta/update.json | 3 +- 1.12/readme.md | 5 + .../engineersdecor/ModEngineersDecor.java | 45 +- .../blocks/BlockDecorCraftingTable.java | 394 ++++++++++++++++-- .../blocks/BlockDecorFurnace.java | 66 ++- .../blocks/BlockDecorWindow.java | 3 - .../engineersdecor/detail/ClientProxy.java | 13 +- .../wile/engineersdecor/detail/ExtItems.java | 21 + .../engineersdecor/detail/ModAuxiliaries.java | 8 +- .../wile/engineersdecor/detail/ModConfig.java | 18 +- .../engineersdecor/detail/Networking.java | 119 ++++++ .../detail/RecipeCondModSpecific.java | 1 - .../engineersdecor/detail/ServerProxy.java | 14 +- .../assets/engineersdecor/lang/en_us.lang | 13 +- .../assets/engineersdecor/lang/ru_ru.lang | 9 +- .../glass/window_glass_texture-orig.png | Bin 0 -> 560 bytes .../blocks/glass/window_glass_texture.png | Bin 578 -> 560 bytes .../gui/treated_wood_crafting_table.png | Bin 25349 -> 25665 bytes meta/update.json | 3 +- 20 files changed, 634 insertions(+), 103 deletions(-) create mode 100644 1.12/src/main/java/wile/engineersdecor/detail/ExtItems.java create mode 100644 1.12/src/main/java/wile/engineersdecor/detail/Networking.java create mode 100644 1.12/src/main/resources/assets/engineersdecor/textures/blocks/glass/window_glass_texture-orig.png diff --git a/1.12/gradle.properties b/1.12/gradle.properties index 1eaf9ad..c72f4b8 100644 --- a/1.12/gradle.properties +++ b/1.12/gradle.properties @@ -4,4 +4,4 @@ org.gradle.jvmargs=-Xmx8G version_minecraft=1.12.2 version_forge=14.23.5.2768 version_jei=4.10.0.198 -version_engineersdecor=1.0.3-b3 +version_engineersdecor=1.0.3-b4 diff --git a/1.12/meta/update.json b/1.12/meta/update.json index 73e7050..3a236fa 100644 --- a/1.12/meta/update.json +++ b/1.12/meta/update.json @@ -1,6 +1,7 @@ { "homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/", "1.12.2": { + "1.0.3-b4": "[A] Lab furnace supports electrical speedup when a IE external is placed in one of the two auxiliary slots.\n[F] Fixed window rendering issue (issue #15, thanks to ILLOMIURGE).\n[M] Updated ru_ru lang file (Yaroslavik).", "1.0.3-b3": "[A] Added sitting on treated wood stool, Zombies included.\n[A] Added steel framed window.\n[A] Added treated wood pole support head/foot and heavy duty support.\n[A] Added language Russian language support, thanks to yaroslav4167.\n[A] Added config for furnace smelting speed (percent of vanilla furnace).\n[A] Added config for furnace fuel efficiency (in percent, ref is vanilla).\n[F] Treated pole model changed to circumvent potential texture bleeding.\n[M] Treated wood table bounding box aligned with the legs.\n[M] Treated wood crafting table bounding box aligned with the legs.\n[M] Treated wood window can be vertically placed for rooflights.\n[M] Treated wood window can be vertically placed for rooflights.", "1.0.3-b2": "[A] Added config options for selective feature opt-outs (soft opt-out).\n[A] Added config skip registration of opt-out features (hard opt-out).\n[A] Added config to disable all internal recipes (for packs).\n[A] Added JEI API adapter for soft opt-outs.\n[A] Added lab furnace recipe override config to smelt ores to nuggets that would normally be smelted into ingots. Can be changed on-the-fly.", "1.0.3-b1": "[A] Added small laboratory furnace.\n[M] Panzer glass opacity/light level set explicitly 0.", @@ -21,6 +22,6 @@ }, "promos": { "1.12.2-recommended": "1.0.2", - "1.12.2-latest": "1.0.3-b3" + "1.12.2-latest": "1.0.3-b4" } } \ No newline at end of file diff --git a/1.12/readme.md b/1.12/readme.md index 82e8a83..d1d9874 100644 --- a/1.12/readme.md +++ b/1.12/readme.md @@ -10,6 +10,11 @@ Mod sources for Minecraft version 1.12.2. ---- ## Revision history + - v1.0.3-b4 [A] Lab furnace supports electrical speedup when a IE external + is placed in one of the two auxiliary slots. + [F] Fixed window rendering issue (issue #15, thanks to ILLOMIURGE). + [M] Updated ru_ru lang file (Yaroslavik). + - v1.0.3-b3 [A] Added sitting on treated wood stool, Zombies included. [A] Added steel framed window. [A] Added treated wood pole support head/foot and heavy duty support. diff --git a/1.12/src/main/java/wile/engineersdecor/ModEngineersDecor.java b/1.12/src/main/java/wile/engineersdecor/ModEngineersDecor.java index 98be6f6..b515a1b 100644 --- a/1.12/src/main/java/wile/engineersdecor/ModEngineersDecor.java +++ b/1.12/src/main/java/wile/engineersdecor/ModEngineersDecor.java @@ -8,38 +8,40 @@ */ package wile.engineersdecor; +import wile.engineersdecor.detail.ModConfig; +import wile.engineersdecor.detail.ExtItems; +import wile.engineersdecor.detail.Networking; +import wile.engineersdecor.detail.RecipeCondModSpecific; +import wile.engineersdecor.blocks.*; +import net.minecraft.world.World; +import net.minecraft.tileentity.TileEntity; import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.entity.player.EntityPlayer; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Item; +import net.minecraft.creativetab.CreativeTabs; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.entity.living.LivingEvent; import net.minecraftforge.fml.common.network.IGuiHandler; import net.minecraftforge.fml.common.network.NetworkRegistry; import net.minecraftforge.fml.common.registry.EntityRegistry; -import wile.engineersdecor.blocks.*; -import wile.engineersdecor.detail.ModConfig; -import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.SidedProxy; -import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.relauncher.Side; -import net.minecraft.creativetab.CreativeTabs; -import net.minecraft.item.ItemStack; -import net.minecraft.block.Block; -import net.minecraft.item.Item; +import net.minecraftforge.event.entity.living.LivingEvent; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.fml.relauncher.SideOnly; import org.apache.logging.log4j.Logger; -import wile.engineersdecor.detail.RecipeCondModSpecific; - import javax.annotation.Nonnull; + @Mod( modid = ModEngineersDecor.MODID, name = ModEngineersDecor.MODNAME, @@ -63,6 +65,10 @@ public class ModEngineersDecor @Mod.Instance public static ModEngineersDecor instance; + //-------------------------------------------------------------------------------------------------------------------- + // Side handling + //-------------------------------------------------------------------------------------------------------------------- + @SidedProxy(clientSide = "wile.engineersdecor.detail.ClientProxy", serverSide = "wile.engineersdecor.detail.ServerProxy") public static IProxy proxy; @@ -71,8 +77,13 @@ public class ModEngineersDecor default void preInit(final FMLPreInitializationEvent e) {} default void init(final FMLInitializationEvent e) {} default void postInit(final FMLPostInitializationEvent e) {} + default World getWorlClientSide() { return null; } } + //-------------------------------------------------------------------------------------------------------------------- + // Init + //-------------------------------------------------------------------------------------------------------------------- + @Mod.EventHandler public void preInit(final FMLPreInitializationEvent event) { @@ -85,6 +96,7 @@ public class ModEngineersDecor } proxy.preInit(event); MinecraftForge.EVENT_BUS.register(new PlayerEventHandler()); + Networking.init(); } @Mod.EventHandler @@ -102,6 +114,7 @@ public class ModEngineersDecor proxy.postInit(event); if(RecipeCondModSpecific.num_skipped > 0) logger.info("Excluded " + RecipeCondModSpecific.num_skipped + " recipes due to config opt-out."); if(ModConfig.zmisc.with_experimental) logger.info("Included experimental features due to mod config."); + ExtItems.onPostInit(); } @Mod.EventBusSubscriber @@ -128,6 +141,10 @@ public class ModEngineersDecor { return new ItemStack(ModBlocks.TREATED_WOOD_LADDER); } }); + //-------------------------------------------------------------------------------------------------------------------- + // Player interaction/notification + //-------------------------------------------------------------------------------------------------------------------- + public static final class GuiHandler implements IGuiHandler { public static final int GUIID_CRAFTING_TABLE = 213101; diff --git a/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorCraftingTable.java b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorCraftingTable.java index 9bdd4e8..d9a7d74 100644 --- a/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorCraftingTable.java +++ b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorCraftingTable.java @@ -9,40 +9,54 @@ */ package wile.engineersdecor.blocks; +import net.minecraft.client.gui.GuiButtonImage; import wile.engineersdecor.ModEngineersDecor; import net.minecraft.block.Block; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; +import net.minecraft.world.World; import net.minecraft.world.Explosion; -import net.minecraft.client.gui.inventory.GuiContainer; -import net.minecraft.client.renderer.GlStateManager; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.inventory.*; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.init.Items; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; +import net.minecraft.util.*; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TextComponentTranslation; -import net.minecraft.world.World; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.gui.GuiButton; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; - +import com.google.common.collect.ImmutableList; +import wile.engineersdecor.detail.Networking; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; public class BlockDecorCraftingTable extends BlockDecorDirected { + public static boolean with_assist = true; + + public static final void on_config(boolean without_crafting_assist) + { + with_assist = !without_crafting_assist; + CraftingHistory.max_history_size(32); + } public BlockDecorCraftingTable(@Nonnull String registryName, long config, @Nullable Material material, float hardness, float resistance, @Nullable SoundType sound, @Nonnull AxisAlignedBB unrotatedAABB) { @@ -137,6 +151,142 @@ public class BlockDecorCraftingTable extends BlockDecorDirected public static Object getClientGuiElement(final EntityPlayer player, final World world, final BlockPos pos, final TileEntity te) { return (te instanceof BTileEntity) ? (new BGui(player.inventory, world, pos, (BTileEntity)te)) : null; } + //-------------------------------------------------------------------------------------------------------------------- + // Crafting history + //-------------------------------------------------------------------------------------------------------------------- + + private static class CraftingHistory + { + public static final List NOTHING = new ArrayList(); + + private List history_ = new ArrayList(); + private int current_ = -1; + private static int max_history_size_ = 5; + + public CraftingHistory() + {} + + public static int max_history_size() + { return max_history_size_; } + + public static int max_history_size(int newsize) + { return max_history_size_ = MathHelper.clamp(newsize, 0, 32); } + + public void read(final NBTTagCompound nbt) + { + try { + clear(); + final NBTTagCompound subsect = nbt.getCompoundTag("history"); + if(subsect.isEmpty()) return; + { + String s = subsect.getString("elements"); + if((s!=null) && (s.length() > 0)) { + String[] ls = s.split("[|]"); + for(String e:ls) history_.add(e.toLowerCase().trim()); + } + } + current_ = (!subsect.hasKey("current")) ? (-1) : MathHelper.clamp(subsect.getInteger("current"), -1, history_.size()-1); + } catch(Throwable ex) { + ModEngineersDecor.logger.error("Exception reading crafting table history NBT, resetting, exception is:" + ex.getMessage()); + clear(); + } + } + + public void write(final NBTTagCompound nbt) + { + final NBTTagCompound subsect = new NBTTagCompound(); + subsect.setInteger("current", current_); + subsect.setString("elements", String.join("|", history_)); + nbt.setTag("history", subsect); + } + + public void clear() + { current_ = -1; history_.clear(); } + + public void reset_curent() + { current_ = -1; } + + public void add(final List grid_stacks) + { + if(!with_assist) { clear(); return; } + String s = stacks2str(grid_stacks); + if(s.isEmpty()) return; + history_.removeIf(e->e.equals(s)); + history_.add(s); + while(history_.size() > max_history_size()) history_.remove(0); + if(current_ >= history_.size()) current_ = -1; + } + + public String stacks2str(final List grid_stacks) + { + if((grid_stacks==null) || (grid_stacks.size() != 10)) return ""; + if(grid_stacks.get(0).isEmpty()) return ""; + final ArrayList items = new ArrayList(); + for(ItemStack st:grid_stacks) { + int meta = st.getMetadata(); + items.add( (st.isEmpty()) ? ("") : ((st.getItem().getRegistryName().toString().trim()) + ((meta==0)?(""):("/"+meta)) )); + } + return String.join(";", items); + } + + public List str2stacks(final String entry) + { + try { + if((entry == null) || (entry.isEmpty())) return NOTHING; + ArrayList item_regnames = new ArrayList(Arrays.asList(entry.split("[;]"))); + if((item_regnames == null) || (item_regnames.size() > 10)) return NOTHING; + while(item_regnames.size() < 10) item_regnames.add(""); + List stacks = new ArrayList(); + for(String regname : item_regnames) { + ItemStack stack = ItemStack.EMPTY; + if(!regname.isEmpty()) { + int meta = 0; + if(regname.indexOf('/') >= 0) { + String[] itemdetails = regname.split("[/]"); + if(itemdetails.length>0) regname = itemdetails[0]; + try { if(itemdetails.length>1) meta = Integer.parseInt(itemdetails[1]); } catch(Throwable e){meta=0;} // ignore exception here + } + final Item item = Item.REGISTRY.getObject(new ResourceLocation(regname)); + stack = ((item == null) || (item == Items.AIR)) ? ItemStack.EMPTY : (new ItemStack(item, 1, meta)); + } + stacks.add(stack); + } + if((stacks.size() != 10) || (stacks.get(0).isEmpty())) return NOTHING; // invalid size or no result + return stacks; + } catch(Throwable ex) { + ModEngineersDecor.logger.error("History stack building failed: " + ex.getMessage()); + return NOTHING; + } + } + + public List current() + { + if((current_ < 0) || (current_ >= history_.size())) { current_ = -1; return NOTHING; } + return str2stacks(history_.get(current_)); + } + + public void next() + { + if(history_.isEmpty()) { current_ = -1; return; } + current_ = ((++current_) >= history_.size()) ? (-1) : (current_); + } + + public void prev() + { + if(history_.isEmpty()) { current_ = -1; return; } + current_ = ((--current_) < -1) ? (history_.size()-1) : (current_); + } + + public String toString() + { + StringBuilder s = new StringBuilder("{ current:" + current_ + ", elements:[ "); + for(int i=0; i buttons = new ArrayList(); + + public BGui(InventoryPlayer playerInventory, World world, BlockPos pos, BTileEntity te) + { super(new BContainer(playerInventory, world, pos, te)); this.te = te; } @Override + @SuppressWarnings("unused") public void initGui() - { super.initGui(); } + { + super.initGui(); + final int x0=((width - xSize)/2), y0=((height - ySize)/2); + buttons.clear(); + if(with_assist) { + buttons.add(addButton(new GuiButtonImage(BUTTON_NEXT, x0+156,y0+44, 12,12, 194,44, 12, BACKGROUND))); + buttons.add(addButton(new GuiButtonImage(BUTTON_PREV, x0+156,y0+30, 12,12, 180,30, 12, BACKGROUND))); + // buttons.add(addButton(new GuiButtonImage(BUTTON_FROM_STORAGE, x0+49,y0+34, 9,17, 219,34, 17, BACKGROUND))); + // buttons.add(addButton(new GuiButtonImage(BUTTON_TO_STORAGE, x0+49,y0+52, 9,17, 208,16, 17, BACKGROUND))); + // buttons.add(addButton(new GuiButtonImage(BUTTON_FROM_PLAYER, x0+77,y0+71, 17,9, 198,71, 9, BACKGROUND))); + // buttons.add(addButton(new GuiButtonImage(BUTTON_TO_PLAYER, x0+59,y0+71, 17,9, 180,71, 9, BACKGROUND))); + } + } @Override public void drawScreen(int mouseX, int mouseY, float partialTicks) { - this.drawDefaultBackground(); + drawDefaultBackground(); super.drawScreen(mouseX, mouseY, partialTicks); renderHoveredToolTip(mouseX, mouseY); } @@ -162,9 +335,94 @@ public class BlockDecorCraftingTable extends BlockDecorDirected @Override protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { - GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F); - this.mc.getTextureManager().bindTexture(new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/treated_wood_crafting_table.png")); - drawTexturedModalRect(((this.width - this.xSize)/2), ((this.height - this.ySize)/2), 0, 0, this.xSize, this.ySize); + GlStateManager.color(1f, 1f, 1f, 1f); + mc.getTextureManager().bindTexture(BACKGROUND); + final int x0=((width - xSize)/2), y0=((height - ySize)/2); + drawTexturedModalRect(x0, y0, 0, 0, xSize, ySize); + if(with_assist) { + List crafting_template = te.history.current(); + if((crafting_template == null) || (crafting_template.isEmpty())) return; + if(inventorySlots.getSlot(0).getHasStack()) return; + { + int i = 0; + for(Tuple e : ((BContainer) inventorySlots).CRAFTING_SLOT_POSITIONS) { + if((inventorySlots.getSlot(i).getHasStack())) { + if(!inventorySlots.getSlot(i).getStack().getItem().equals(crafting_template.get(i).getItem())) { + return; // user has placed another recipe + } + } + ++i; + } + } + { + int i = 0; + for(Tuple e : ((BContainer) inventorySlots).CRAFTING_SLOT_POSITIONS) { + final ItemStack stack = crafting_template.get(i); + if(!stack.isEmpty()) drawTemplateItemAt(stack, x0, y0, e.getFirst(), e.getSecond()); + ++i; + } + } + } + } + + protected void drawTemplateItemAt(ItemStack stack, int x0, int y0, int x, int y) + { + RenderHelper.disableStandardItemLighting(); + RenderHelper.enableGUIStandardItemLighting(); + float zl = itemRender.zLevel; + itemRender.zLevel = -50; + itemRender.renderItemIntoGUI(stack, x0+x, y0+y); + itemRender.zLevel = zl; + zLevel = 100; + GlStateManager.color(0.7f, 0.7f, 0.7f, 0.8f); + mc.getTextureManager().bindTexture(BACKGROUND); + drawTexturedModalRect(x0+x, y0+y, x, y, 16, 16); + RenderHelper.enableStandardItemLighting(); + } + + @Override + protected void actionPerformed(GuiButton button) + { + switch(button.id) { + case BUTTON_NEXT: + case BUTTON_PREV: + case BUTTON_FROM_STORAGE: + case BUTTON_TO_STORAGE: + case BUTTON_FROM_PLAYER: + case BUTTON_TO_PLAYER: { + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setInteger("button", button.id); + Networking.PacketTileNotify.sendToServer(te, nbt); + break; + } + } + } + } + + //-------------------------------------------------------------------------------------------------------------------- + // Crafting slot of container + //-------------------------------------------------------------------------------------------------------------------- + + public static class BSlotCrafting extends SlotCrafting + { + private final BTileEntity te; + private final EntityPlayer player; + + public BSlotCrafting(BTileEntity te, EntityPlayer player, InventoryCrafting craftingInventory, IInventory inventoryIn, int slotIndex, int xPosition, int yPosition) + { super(player, craftingInventory, inventoryIn, slotIndex, xPosition, yPosition); this.te = te; this.player=player; } + + @Override + protected void onCrafting(ItemStack stack) + { + if((with_assist) && ((player.world!=null) && (!(player.world.isRemote))) && (!stack.isEmpty())) { + final ArrayList grid = new ArrayList(); + grid.add(stack); + for(int i = 0; i < 9; ++i) grid.add(te.stacks.get(i)); + te.history.add(grid); + te.history.reset_curent(); + te.syncHistory(player); + } + super.onCrafting(stack); } } @@ -180,36 +438,42 @@ public class BlockDecorCraftingTable extends BlockDecorDirected private final BTileEntity te; public BInventoryCrafting craftMatrix; public InventoryCraftResult craftResult = new InventoryCraftResult(); - + public final ImmutableList> CRAFTING_SLOT_POSITIONS; public BContainer(InventoryPlayer playerInventory, World world, BlockPos pos, BTileEntity te) { + ArrayList> slotpositions = new ArrayList>(); this.player = playerInventory.player; this.world = world; this.pos = pos; this.te = te; - this.craftMatrix = new BInventoryCrafting(this, te); - this.craftMatrix.openInventory(player); - this.addSlotToContainer(new SlotCrafting(playerInventory.player, this.craftMatrix, this.craftResult, 0, 124+14, 35)); + craftMatrix = new BInventoryCrafting(this, te); + craftMatrix.openInventory(player); + addSlotToContainer(new BSlotCrafting(te, playerInventory.player, craftMatrix, craftResult, 0, 134, 35)); + slotpositions.add(new Tuple<>(134, 35)); for(int y=0; y<3; ++y) { for(int x=0; x<3; ++x) { - addSlotToContainer(new Slot(this.craftMatrix, x+y*3, 28+30+x*18, 17+y*18)); // block slots 0..8 + int xpos = 60+x*18; + int ypos = 17+y*18; + addSlotToContainer(new Slot(craftMatrix, x+y*3, xpos, ypos)); // block slots 0..8 + slotpositions.add(new Tuple<>(xpos, ypos)); } } + CRAFTING_SLOT_POSITIONS = ImmutableList.copyOf(slotpositions); for(int y=0; y<3; ++y) { for (int x=0; x<9; ++x) { - this.addSlotToContainer(new Slot(playerInventory, x+y*9+9, 8+x*18, 86+y*18)); // player slots: 9..35 + addSlotToContainer(new Slot(playerInventory, x+y*9+9, 8+x*18, 86+y*18)); // player slots: 9..35 } } - for (int x=0; x<9; ++x) { - this.addSlotToContainer(new Slot(playerInventory, x, 8+x*18, 144)); // player slots: 0..8 + for(int x=0; x<9; ++x) { + addSlotToContainer(new Slot(playerInventory, x, 8+x*18, 144)); // player slots: 0..8 } for(int y=0; y<4; ++y) { for (int x=0; x<2; ++x) { - this.addSlotToContainer(new Slot(this.craftMatrix, x+y*2+9, 8+x*18, 9+y*18)); // block slots 9..17 + addSlotToContainer(new Slot(craftMatrix, x+y*2+9, 8+x*18, 9+y*18)); // block slots 9..17 } } - this.onCraftMatrixChanged(this.craftMatrix); + onCraftMatrixChanged(craftMatrix); } @Override @@ -220,7 +484,7 @@ public class BlockDecorCraftingTable extends BlockDecorDirected public void onCraftMatrixChanged(IInventory inv) { try { - slotChangedCraftingGrid(this.world, this.player, this.craftMatrix, this.craftResult); + slotChangedCraftingGrid(world, player, craftMatrix, craftResult); } catch(Throwable exc) { ModEngineersDecor.logger.error("Recipe failed:", exc); } @@ -243,12 +507,12 @@ public class BlockDecorCraftingTable extends BlockDecorDirected @Override public boolean canMergeSlot(ItemStack stack, Slot slot) - { return (slot.inventory != this.craftResult) && (super.canMergeSlot(stack, slot)); } + { return (slot.inventory != craftResult) && (super.canMergeSlot(stack, slot)); } @Override public ItemStack transferStackInSlot(EntityPlayer playerIn, int index) { - Slot slot = this.inventorySlots.get(index); + Slot slot = inventorySlots.get(index); if((slot == null) || (!slot.getHasStack())) return ItemStack.EMPTY; ItemStack slotstack = slot.getStack(); ItemStack stack = slotstack.copy(); @@ -333,12 +597,13 @@ public class BlockDecorCraftingTable extends BlockDecorDirected //-------------------------------------------------------------------------------------------------------------------- // Tile entity //-------------------------------------------------------------------------------------------------------------------- - public static class BTileEntity extends TileEntity implements IInventory + public static class BTileEntity extends TileEntity implements IInventory, Networking.IPacketReceiver { public static final int NUM_OF_CRAFTING_SLOTS = 9; - public static final int NUM_OF_STORAGE_SLOTS = 9; + public static final int NUM_OF_STORAGE_SLOTS = 8; public static final int NUM_OF_SLOTS = NUM_OF_CRAFTING_SLOTS+NUM_OF_STORAGE_SLOTS; protected NonNullList stacks; + protected final CraftingHistory history = new CraftingHistory(); public BTileEntity() { stacks = NonNullList.withSize(NUM_OF_SLOTS, ItemStack.EMPTY); } @@ -349,12 +614,63 @@ public class BlockDecorCraftingTable extends BlockDecorDirected public void readnbt(NBTTagCompound compound) { reset(); - ItemStackHelper.loadAllItems(compound, this.stacks); - while(this.stacks.size() < NUM_OF_SLOTS) this.stacks.add(ItemStack.EMPTY); + ItemStackHelper.loadAllItems(compound, stacks); + while(stacks.size() < NUM_OF_SLOTS) stacks.add(ItemStack.EMPTY); + history.read(compound); } private void writenbt(NBTTagCompound compound) - { ItemStackHelper.saveAllItems(compound, this.stacks); } + { + ItemStackHelper.saveAllItems(compound, stacks); + history.write(compound); + } + + // Networking.IPacketReceiver -------------------------------------------------------------- + + @Override + public void onClientPacketReceived(EntityPlayer player, NBTTagCompound nbt) + { + if(with_assist && nbt.hasKey("button")) { + switch(nbt.getInteger("button")) { + case BGui.BUTTON_NEXT: + history.next(); + syncHistory(player); + break; + case BGui.BUTTON_PREV: + history.prev(); + syncHistory(player); + break; + case BGui.BUTTON_FROM_STORAGE: + //System.out.println("BUTTON_FROM_STORAGE"); + break; + case BGui.BUTTON_TO_STORAGE: + //System.out.println("BUTTON_TO_STORAGE"); + break; + case BGui.BUTTON_FROM_PLAYER: + //System.out.println("BUTTON_FROM_PLAYER"); + break; + case BGui.BUTTON_TO_PLAYER: + //System.out.println("BUTTON_TO_PLAYER"); + break; + } + } + } + + @Override + public void onServerPacketReceived(NBTTagCompound nbt) + { + if(nbt.hasKey("historydata")) history.read(nbt.getCompoundTag("historydata")); + } + + private void syncHistory(EntityPlayer player) + { + if(!with_assist) return; + NBTTagCompound history_nbt = new NBTTagCompound(); + history.write(history_nbt); + NBTTagCompound rnbt = new NBTTagCompound(); + rnbt.setTag("historydata", history_nbt); + Networking.PacketTileNotify.sendToPlayer(player, this, rnbt); + } // TileEntity ------------------------------------------------------------------------------ @@ -363,12 +679,16 @@ public class BlockDecorCraftingTable extends BlockDecorDirected { return (os.getBlock() != ns.getBlock()) || (!(ns.getBlock() instanceof BlockDecorCraftingTable)); } @Override - public void readFromNBT(NBTTagCompound compound) - { super.readFromNBT(compound); readnbt(compound); } + public void readFromNBT(NBTTagCompound nbt) + { super.readFromNBT(nbt); readnbt(nbt); } @Override - public NBTTagCompound writeToNBT(NBTTagCompound compound) - { super.writeToNBT(compound); writenbt(compound); return compound; } + public NBTTagCompound writeToNBT(NBTTagCompound nbt) + { super.writeToNBT(nbt); writenbt(nbt); return nbt; } + + @Override + public NBTTagCompound getUpdateTag() + { NBTTagCompound nbt = new NBTTagCompound(); super.writeToNBT(nbt); writenbt(nbt); return nbt; } // IWorldNamable --------------------------------------------------------------------------- diff --git a/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorFurnace.java b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorFurnace.java index 21f0d87..5ffda4d 100644 --- a/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorFurnace.java +++ b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorFurnace.java @@ -11,6 +11,8 @@ package wile.engineersdecor.blocks; import com.google.common.collect.Maps; import net.minecraft.entity.item.EntityXPOrb; import net.minecraft.init.SoundEvents; +import net.minecraftforge.energy.CapabilityEnergy; +import net.minecraftforge.energy.IEnergyStorage; import wile.engineersdecor.ModEngineersDecor; import net.minecraft.stats.StatList; import net.minecraft.block.properties.PropertyBool; @@ -46,12 +48,12 @@ import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.wrapper.SidedInvWrapper; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; +import wile.engineersdecor.detail.ExtItems; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Map; import java.util.Random; - public class BlockDecorFurnace extends BlockDecorDirected { public static final PropertyBool LIT = PropertyBool.create("lit"); @@ -428,11 +430,12 @@ public class BlockDecorFurnace extends BlockDecorDirected // Tile entity //-------------------------------------------------------------------------------------------------------------------- - public static class BTileEntity extends TileEntity implements ITickable, ISidedInventory + public static class BTileEntity extends TileEntity implements ITickable, ISidedInventory, IEnergyStorage { public static final int TICK_INTERVAL = 4; public static final int FIFO_INTERVAL = 20; public static final int MAX_BURNTIME = 0x7fff; + public static final int DEFAULT_BOOST_ENERGY = 32; public static final int VANILLA_FURNACE_SPEED_INTERVAL = 200; public static final int DEFAULT_SPEED_INTERVAL = 150; public static final int NUM_OF_SLOTS = 11; @@ -454,9 +457,9 @@ public class BlockDecorFurnace extends BlockDecorDirected private final IItemHandler sided_itemhandler_top_ = new SidedInvWrapper(this, EnumFacing.UP); private final IItemHandler sided_itemhandler_down_ = new SidedInvWrapper(this, EnumFacing.DOWN); private final IItemHandler sided_itemhandler_sides_ = new SidedInvWrapper(this, EnumFacing.WEST); - - private static int proc_speed_interval_ = DEFAULT_SPEED_INTERVAL; private static double proc_fuel_efficiency_ = 1.0; + private static int proc_speed_interval_ = DEFAULT_SPEED_INTERVAL; + private static int boost_energy_consumption = DEFAULT_BOOST_ENERGY * TICK_INTERVAL; private int tick_timer_; private int fifo_timer_; @@ -464,13 +467,16 @@ public class BlockDecorFurnace extends BlockDecorDirected private int fuel_burntime_; private int proc_time_elapsed_; private int proc_time_needed_; + private int boost_energy_; // small, not saved in nbt. + private boolean heater_inserted_ = false; private NonNullList stacks_; - public static void on_config(int speed_percent, int fuel_efficiency_percent) + public static void on_config(int speed_percent, int fuel_efficiency_percent, int boost_energy_per_tick) { double ratio = (100.0 / MathHelper.clamp(speed_percent, 10, 500)) ; proc_speed_interval_ = MathHelper.clamp((int)(ratio * VANILLA_FURNACE_SPEED_INTERVAL), 20, 400); proc_fuel_efficiency_ = ((double) MathHelper.clamp(fuel_efficiency_percent, 10, 500)) / 100; + boost_energy_consumption = TICK_INTERVAL * MathHelper.clamp(boost_energy_per_tick, 16, 512); ModEngineersDecor.logger.info("Config lab furnace interval:" + proc_speed_interval_ + ", efficiency:" + proc_fuel_efficiency_); } @@ -663,6 +669,9 @@ public class BlockDecorFurnace extends BlockDecorDirected if(transferItems(FIFO_FUEL_1_SLOT_NO, FIFO_FUEL_0_SLOT_NO, 1)) dirty = true; if(transferItems(FIFO_INPUT_0_SLOT_NO, SMELTING_INPUT_SLOT_NO, 1)) dirty = true; if(transferItems(FIFO_INPUT_1_SLOT_NO, FIFO_INPUT_0_SLOT_NO, 1)) dirty = true; + heater_inserted_ = (ExtItems.IE_EXTERNAL_HEATER==null) // without IE always allow electrical boost + || (stacks_.get(AUX_0_SLOT_NO).getItem()==ExtItems.IE_EXTERNAL_HEATER) + || (stacks_.get(AUX_1_SLOT_NO).getItem()==ExtItems.IE_EXTERNAL_HEATER); } ItemStack fuel = stacks_.get(SMELTING_FUEL_SLOT_NO); if(isBurning() || (!fuel.isEmpty()) && (!(stacks_.get(SMELTING_INPUT_SLOT_NO)).isEmpty())) { @@ -680,6 +689,7 @@ public class BlockDecorFurnace extends BlockDecorDirected } if(isBurning() && canSmelt()) { proc_time_elapsed_ += TICK_INTERVAL; + if(heater_inserted_ && (boost_energy_ >= boost_energy_consumption)) { boost_energy_ = 0; proc_time_elapsed_ += TICK_INTERVAL; } if(proc_time_elapsed_ >= proc_time_needed_) { proc_time_elapsed_ = 0; proc_time_needed_ = getCookTime(stacks_.get(SMELTING_INPUT_SLOT_NO)); @@ -775,6 +785,8 @@ public class BlockDecorFurnace extends BlockDecorDirected public static boolean isItemFuel(ItemStack stack) { return TileEntityFurnace.isItemFuel(stack); } + // ISidedInventory ---------------------------------------------------------------------------- + @Override public int[] getSlotsForFace(EnumFacing side) { @@ -794,17 +806,51 @@ public class BlockDecorFurnace extends BlockDecorDirected return (stack.getItem()==Items.BUCKET); } + // IEnergyStorage ---------------------------------------------------------------------------- + + public boolean canExtract() + { return false; } + + public boolean canReceive() + { return true; } + + public int getMaxEnergyStored() + { return boost_energy_consumption; } + + public int getEnergyStored() + { return boost_energy_; } + + public int extractEnergy(int maxExtract, boolean simulate) + { return 0; } + + public int receiveEnergy(int maxReceive, boolean simulate) + { // only speedup support, no buffering, not in nbt -> no markdirty + if((boost_energy_ >= boost_energy_consumption) || (maxReceive < boost_energy_consumption)) return 0; + if(!simulate) boost_energy_ = boost_energy_consumption; + return boost_energy_consumption; + } + + // Capability export ---------------------------------------------------------------------------- + + @Override + public boolean hasCapability(Capability cap, EnumFacing facing) + { return ((cap==CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) || (cap==CapabilityEnergy.ENERGY)) || super.hasCapability(cap, facing); } + @Override @SuppressWarnings("unchecked") @Nullable public T getCapability(Capability capability, @Nullable EnumFacing facing) { - if((facing == null) || (capability != CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)) return super.getCapability(capability, facing); - if(facing == EnumFacing.DOWN) return (T) sided_itemhandler_down_; - if(facing == EnumFacing.UP) return (T) sided_itemhandler_top_; - return (T) sided_itemhandler_sides_; + if((facing != null) && (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)) { + if(facing == EnumFacing.DOWN) return (T) sided_itemhandler_down_; + if(facing == EnumFacing.UP) return (T) sided_itemhandler_top_; + return (T) sided_itemhandler_sides_; + } else if(capability == CapabilityEnergy.ENERGY) { + return (T)this; + } else { + return super.getCapability(capability, facing); + } } - } //-------------------------------------------------------------------------------------------------------------------- diff --git a/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorWindow.java b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorWindow.java index 93edf43..44df0be 100644 --- a/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorWindow.java +++ b/1.12/src/main/java/wile/engineersdecor/blocks/BlockDecorWindow.java @@ -53,7 +53,4 @@ public class BlockDecorWindow extends BlockDecorDirected public boolean doesSideBlockRendering(IBlockState state, IBlockAccess world, BlockPos pos, EnumFacing face) { return false; } - @Override - public boolean canRenderInLayer(IBlockState state, BlockRenderLayer layer) - { return (layer==BlockRenderLayer.TRANSLUCENT) || (layer==BlockRenderLayer.CUTOUT); } } diff --git a/1.12/src/main/java/wile/engineersdecor/detail/ClientProxy.java b/1.12/src/main/java/wile/engineersdecor/detail/ClientProxy.java index 9a9bb4e..3c43afc 100644 --- a/1.12/src/main/java/wile/engineersdecor/detail/ClientProxy.java +++ b/1.12/src/main/java/wile/engineersdecor/detail/ClientProxy.java @@ -8,20 +8,19 @@ */ package wile.engineersdecor.detail; +import net.minecraft.world.World; import wile.engineersdecor.ModEngineersDecor; +import net.minecraft.client.Minecraft; import net.minecraftforge.client.model.obj.OBJLoader; -import net.minecraftforge.fml.common.event.FMLInitializationEvent; -import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; public class ClientProxy implements ModEngineersDecor.IProxy { + @Override public void preInit(FMLPreInitializationEvent e) { OBJLoader.INSTANCE.addDomain(ModEngineersDecor.MODID); } - public void init(FMLInitializationEvent e) - {} - - public void postInit(FMLPostInitializationEvent e) - {} + @Override + public World getWorlClientSide() + { return Minecraft.getMinecraft().world; } } diff --git a/1.12/src/main/java/wile/engineersdecor/detail/ExtItems.java b/1.12/src/main/java/wile/engineersdecor/detail/ExtItems.java new file mode 100644 index 0000000..0e6ac5e --- /dev/null +++ b/1.12/src/main/java/wile/engineersdecor/detail/ExtItems.java @@ -0,0 +1,21 @@ +/* + * @file ExtItems.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2019 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Object holder based item references. + */ +package wile.engineersdecor.detail; + +import net.minecraft.item.Item; +import net.minecraftforge.fml.common.registry.GameRegistry; + +public class ExtItems +{ + @GameRegistry.ObjectHolder("immersiveengineering:metal_device1") + public static final Item IE_EXTERNAL_HEATER = null; + + public static final void onPostInit() + {} +} diff --git a/1.12/src/main/java/wile/engineersdecor/detail/ModAuxiliaries.java b/1.12/src/main/java/wile/engineersdecor/detail/ModAuxiliaries.java index 3bea0b2..9728bd2 100644 --- a/1.12/src/main/java/wile/engineersdecor/detail/ModAuxiliaries.java +++ b/1.12/src/main/java/wile/engineersdecor/detail/ModAuxiliaries.java @@ -8,15 +8,15 @@ */ package wile.engineersdecor.detail; -import net.minecraft.util.EnumFacing; import wile.engineersdecor.ModEngineersDecor; -import net.minecraft.item.ItemStack; -import net.minecraft.client.util.ITooltipFlag; import net.minecraft.world.World; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumFacing; import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.TextFormatting; -import net.minecraftforge.fml.relauncher.Side; import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import org.lwjgl.input.Keyboard; diff --git a/1.12/src/main/java/wile/engineersdecor/detail/ModConfig.java b/1.12/src/main/java/wile/engineersdecor/detail/ModConfig.java index d11e160..670114e 100644 --- a/1.12/src/main/java/wile/engineersdecor/detail/ModConfig.java +++ b/1.12/src/main/java/wile/engineersdecor/detail/ModConfig.java @@ -9,15 +9,15 @@ */ package wile.engineersdecor.detail; -import net.minecraft.block.Block; import wile.engineersdecor.ModEngineersDecor; +import wile.engineersdecor.blocks.*; import net.minecraftforge.common.config.Config; import net.minecraftforge.common.config.ConfigManager; +import net.minecraft.block.Block; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.client.event.ConfigChangedEvent; -import wile.engineersdecor.blocks.*; import javax.annotation.Nullable; @@ -165,6 +165,17 @@ public class ModConfig @Config.RangeInt(min=50, max=250) public int furnace_fuel_efficiency_percent = 100; + @Config.Comment({ + "Defines the energy consumption (per tick) for speeding up the smelting process. " + + "If IE is installed, an external heater has to be inserted into an auxiliary slot " + + "of the lab furnace. The power source needs to be able to provide at least 4 times " + + "this consumption (fixed threshold value). The value can be changed on-the-fly for tuning. " + + "The default value corresponds to the IE heater consumption." + }) + @Config.Name("Furnace: Boost energy") + @Config.RangeInt(min=16, max=256) + public int furnace_boost_energy_consumption = 24; + @Config.Comment({ "Defines, in percent, how high the probability is that a mob sits on a chair " + "when colliding with it. Can be changed on-the-fly for tuning." @@ -234,11 +245,12 @@ public class ModConfig public static final void apply() { - BlockDecorFurnace.BTileEntity.on_config(tweaks.furnace_smelting_speed_percent, tweaks.furnace_fuel_efficiency_percent); + BlockDecorFurnace.BTileEntity.on_config(tweaks.furnace_smelting_speed_percent, tweaks.furnace_fuel_efficiency_percent, tweaks.furnace_boost_energy_consumption); ModRecipes.furnaceRecipeOverrideReset(); if(tweaks.furnace_smelts_nuggets) ModRecipes.furnaceRecipeOverrideSmeltsOresToNuggets(); BlockDecorChair.on_config(optout.without_chair_sitting, optout.without_mob_chair_sitting, tweaks.chair_mob_sitting_probability_percent, tweaks.chair_mob_standup_probability_percent); BlockDecorLadder.on_config(optout.without_ladder_speed_boost); + BlockDecorCraftingTable.on_config(!zmisc.with_experimental); } } diff --git a/1.12/src/main/java/wile/engineersdecor/detail/Networking.java b/1.12/src/main/java/wile/engineersdecor/detail/Networking.java new file mode 100644 index 0000000..ac9f478 --- /dev/null +++ b/1.12/src/main/java/wile/engineersdecor/detail/Networking.java @@ -0,0 +1,119 @@ +/* + * @file Networking.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2019 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Main client/server message handling. + */ +package wile.engineersdecor.detail; + +import wile.engineersdecor.ModEngineersDecor; +import net.minecraft.client.Minecraft; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.fml.common.network.ByteBufUtils; +import net.minecraftforge.fml.common.network.NetworkRegistry; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper; +import net.minecraftforge.fml.relauncher.Side; +import io.netty.buffer.ByteBuf; + + +public class Networking +{ + private static SimpleNetworkWrapper snw = null; + + public static void init() + { + if(snw != null) return; + int discr = -1; + snw = NetworkRegistry.INSTANCE.newSimpleChannel(ModEngineersDecor.MODID); + snw.registerMessage(PacketTileNotify.ServerHandler.class, PacketTileNotify.class, ++discr, Side.SERVER); + snw.registerMessage(PacketTileNotify.ClientHandler.class, PacketTileNotify.class, ++discr, Side.CLIENT); + } + + public interface IPacketReceiver + { + default void onServerPacketReceived(NBTTagCompound nbt) {} + default void onClientPacketReceived(EntityPlayer player, NBTTagCompound nbt) {} + } + + //-------------------------------------------------------------------------------------------------------------------- + // Tile entity notifications + //-------------------------------------------------------------------------------------------------------------------- + + public static class PacketTileNotify implements IMessage + { + NBTTagCompound nbt = null; + BlockPos pos = BlockPos.ORIGIN; + + public static void sendToServer(TileEntity te, NBTTagCompound nbt) + { if((te != null) && (nbt!=null)) snw.sendToServer(new PacketTileNotify(te, nbt)); } + + public static void sendToPlayer(EntityPlayer player, TileEntity te, NBTTagCompound nbt) + { if((player instanceof EntityPlayerMP) && (te != null) && (nbt!=null)) snw.sendTo(new PacketTileNotify(te, nbt), (EntityPlayerMP)player); } + + public PacketTileNotify(TileEntity te, NBTTagCompound nbt) + { this.nbt=nbt; pos=te.getPos(); } + + public PacketTileNotify() + {} + + @Override + public void fromBytes(ByteBuf buf) + { pos=BlockPos.fromLong(buf.readLong()); nbt= ByteBufUtils.readTag(buf); } + + @Override + public void toBytes(ByteBuf buf) + { buf.writeLong(pos.toLong()); ByteBufUtils.writeTag(buf, nbt); } + + public static class ServerHandler implements IMessageHandler + { + @Override + public IMessage onMessage(PacketTileNotify pkt, MessageContext ctx) + { + EntityPlayer player = ctx.getServerHandler().player; + WorldServer world = ctx.getServerHandler().player.getServerWorld(); + world.addScheduledTask(() -> { + try { + if(!world.isBlockLoaded(pkt.pos)) return; + TileEntity te = world.getTileEntity(pkt.pos); + if(!(te instanceof IPacketReceiver)) return; + ((IPacketReceiver)te).onClientPacketReceived(player, pkt.nbt); + } catch(Throwable ex) { + ModEngineersDecor.logger.error("Failed to process TE notify packet: " + ex.getMessage()); + } + }); + return null; + } + } + + public static class ClientHandler implements IMessageHandler + { + @Override + public IMessage onMessage(PacketTileNotify pkt, MessageContext ctx) + { + Minecraft.getMinecraft().addScheduledTask(() -> { + try { + final World world = ModEngineersDecor.proxy.getWorlClientSide(); + if(!(world instanceof World)) return; + TileEntity te = world.getTileEntity(pkt.pos); + if(!(te instanceof IPacketReceiver)) return; + ((IPacketReceiver) te).onServerPacketReceived(pkt.nbt); + } catch(Throwable ex) { + ModEngineersDecor.logger.error("Failed to process TE notify packet: " + ex.getMessage()); + } + }); + return null; + } + } + } +} diff --git a/1.12/src/main/java/wile/engineersdecor/detail/RecipeCondModSpecific.java b/1.12/src/main/java/wile/engineersdecor/detail/RecipeCondModSpecific.java index cde4bbe..30b8404 100644 --- a/1.12/src/main/java/wile/engineersdecor/detail/RecipeCondModSpecific.java +++ b/1.12/src/main/java/wile/engineersdecor/detail/RecipeCondModSpecific.java @@ -19,7 +19,6 @@ import net.minecraftforge.common.crafting.IConditionFactory; import net.minecraftforge.common.crafting.JsonContext; import net.minecraftforge.registries.IForgeRegistry; import net.minecraftforge.fml.common.registry.ForgeRegistries; - import com.google.gson.*; import java.util.function.BooleanSupplier; diff --git a/1.12/src/main/java/wile/engineersdecor/detail/ServerProxy.java b/1.12/src/main/java/wile/engineersdecor/detail/ServerProxy.java index 3007c27..52394d1 100644 --- a/1.12/src/main/java/wile/engineersdecor/detail/ServerProxy.java +++ b/1.12/src/main/java/wile/engineersdecor/detail/ServerProxy.java @@ -9,18 +9,6 @@ package wile.engineersdecor.detail; import wile.engineersdecor.ModEngineersDecor; -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -import net.minecraftforge.fml.common.event.FMLInitializationEvent; -import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; public class ServerProxy implements ModEngineersDecor.IProxy -{ - public void preInit(FMLPreInitializationEvent e) - {} - - public void init(FMLInitializationEvent e) - {} - - public void postInit(FMLPostInitializationEvent e) - {} -} +{} diff --git a/1.12/src/main/resources/assets/engineersdecor/lang/en_us.lang b/1.12/src/main/resources/assets/engineersdecor/lang/en_us.lang index 51a39db..813ced5 100644 --- a/1.12/src/main/resources/assets/engineersdecor/lang/en_us.lang +++ b/1.12/src/main/resources/assets/engineersdecor/lang/en_us.lang @@ -65,17 +65,22 @@ tile.engineersdecor.treated_wood_crafting_table.name=Treated wood crafting table tile.engineersdecor.treated_wood_crafting_table.help=§6Robust and weather-proof. Eight storage slots. Keeps inventory. tile.engineersdecor.iron_inset_light.name=Inset light tile.engineersdecor.iron_inset_light.help=§6Small glowstone light source, sunk into the floor, ceiling or wall.§r\n\ - Useful to light up places where electrical light installations are problematic.\ - Light level like a torch. + Useful to light up places where electrical light installations are problematic.\ + Light level like a torch. tile.engineersdecor.treated_wood_window.name=Treated wood window tile.engineersdecor.treated_wood_window.help=§6Wood framed tripple glazed window. Well insulating.§r Does not connect to adjacent blocks like glass panes. tile.engineersdecor.treated_wood_windowsill.name=Treated wood window sill tile.engineersdecor.treated_wood_windowsill.help=§6Simple window decoration. -tile.engineersdecor.small_lab_furnace.name=Small laboratry furnace -tile.engineersdecor.small_lab_furnace.help=§6Small metal cased lab kiln.§r Solid fuel consuming, updraught. Slightly hotter and better isolated than a cobblestone furnace, therefore more efficient. Two stack internal hopper fifos for input, output, and fuel. tile.engineersdecor.steel_framed_window.name=Steel framed window tile.engineersdecor.steel_framed_window.help=§6Steel framed tripple glazed window. Well insulating. §r Does not connect to adjacent blocks like glass panes. #----------------------------------------------------------------------------------------------------------- +tile.engineersdecor.small_lab_furnace.name=Small laboratry furnace +tile.engineersdecor.small_lab_furnace.help=§6Small metal cased lab kiln.§r Solid fuel consuming, updraught. \ + Slightly hotter and better isolated than a cobblestone furnace, therefore more efficient. \ + Two auxiliary slots e.g. for storage. Two stack internal hopper fifos for input, output, \ + and fuel. Place an external heater into a aux slot and connect power for electrical \ + smelting speed boost. +#----------------------------------------------------------------------------------------------------------- tile.engineersdecor.iron_sheet_roof.name=Iron sheet metal roof (experimental) tile.engineersdecor.iron_sheet_roof.help=§6Well, I just can't get that model right in a way that I could like it. Gimme some time. #----------------------------------------------------------------------------------------------------------- diff --git a/1.12/src/main/resources/assets/engineersdecor/lang/ru_ru.lang b/1.12/src/main/resources/assets/engineersdecor/lang/ru_ru.lang index 36bcfb9..8b12817 100644 --- a/1.12/src/main/resources/assets/engineersdecor/lang/ru_ru.lang +++ b/1.12/src/main/resources/assets/engineersdecor/lang/ru_ru.lang @@ -53,9 +53,9 @@ tile.engineersdecor.treated_wood_pole.help=§6Надёжный столб с д Может быть полезен в качестве альтернативы электро-столбам, если требуется особая специальная длина, \ или как опора для конструкций. tile.engineersdecor.treated_wood_pole_head.name=Прямой обработанный деревянный столб верхняя часть/основание -#tile.engineersdecor.treated_wood_pole_head.help=§6Деревянная часть, подходящая как набалдашник или основание прямых столбов. +#tile.engineersdecor.treated_wood_pole_head.help=§6Wooden part fitting as foot or head of straight poles. tile.engineersdecor.treated_wood_pole_support.name=Прямой обработанный деревянный столб -#tile.engineersdecor.treated_wood_pole_support.help=§6Усиленная деревянная опорная часть, подходящая как основание или набалдашник прямых опор. +#tile.engineersdecor.treated_wood_pole_support.help=§6Heavy duty wooden support part fitting as foot or head of straight poles. #----------------------------------------------------------------------------------------------------------- tile.engineersdecor.treated_wood_table.name=Стол из обработанного дерева tile.engineersdecor.treated_wood_table.help=§6Прочный деревянный стол с четырьмя ножками .§r Для использования в помещении и на улице. @@ -71,10 +71,11 @@ tile.engineersdecor.treated_wood_window.name=Обработанное дерев tile.engineersdecor.treated_wood_window.help=§6Деревянный каркас окна с тройным остеклением. Ну и шумоизоляция. tile.engineersdecor.treated_wood_windowsill.name=Обработанный деревянный подоконник tile.engineersdecor.treated_wood_windowsill.help=§6Простое оформление окон. +tile.engineersdecor.steel_framed_window.name=Окно со стальной рамой +#tile.engineersdecor.steel_framed_window.help=§6Steel framed tripple glazed window. Well insulating. §r Does not connect to adjacent blocks like glass panes. +#----------------------------------------------------------------------------------------------------------- tile.engineersdecor.small_lab_furnace.name=Компактная лабораторная печь tile.engineersdecor.small_lab_furnace.help=§6Лабораторная печь в металлическом корпусе.§r Подача твёрдого топлива - сверху. Немного горячее чем каменная, поэтому быстрее. Два внутренних слота для ввода, выхода и топлива. -tile.engineersdecor.steel_framed_window.name=Окно со стальной рамой -#tile.engineersdecor.steel_framed_window.help=§6Стальной стеклопакет с тройной прослойкой. Хорошо изолирует. §r Не соединяется со смежными блоками, такими как стеклянные панели. #----------------------------------------------------------------------------------------------------------- tile.engineersdecor.iron_sheet_roof.name=Кровля из листового металла tile.engineersdecor.iron_sheet_roof.help=§6Ну, это кровля. diff --git a/1.12/src/main/resources/assets/engineersdecor/textures/blocks/glass/window_glass_texture-orig.png b/1.12/src/main/resources/assets/engineersdecor/textures/blocks/glass/window_glass_texture-orig.png new file mode 100644 index 0000000000000000000000000000000000000000..4281eafc0e1115875982ef40232aa5e0b0df27d5 GIT binary patch literal 560 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