diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 6c0c2900a..32c5cea0b 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -14,6 +14,7 @@ import com.simibubi.create.modules.IModule; import com.simibubi.create.modules.contraptions.CasingBlock; import com.simibubi.create.modules.contraptions.components.actors.DrillBlock; import com.simibubi.create.modules.contraptions.components.actors.HarvesterBlock; +import com.simibubi.create.modules.contraptions.components.actors.PloughBlock; import com.simibubi.create.modules.contraptions.components.actors.PortableStorageInterfaceBlock; import com.simibubi.create.modules.contraptions.components.clock.CuckooClockBlock; import com.simibubi.create.modules.contraptions.components.contraptions.bearing.ClockworkBearingBlock; @@ -86,9 +87,6 @@ import com.simibubi.create.modules.palettes.HorizontalCTGlassBlock; import com.simibubi.create.modules.palettes.LayeredCTBlock; import com.simibubi.create.modules.palettes.ScoriaBlock; import com.simibubi.create.modules.palettes.VerticalCTGlassBlock; -import com.simibubi.create.modules.schematics.block.CreativeCrateBlock; -import com.simibubi.create.modules.schematics.block.SchematicTableBlock; -import com.simibubi.create.modules.schematics.block.SchematicannonBlock; import com.tterrag.registrate.builders.BlockBuilder; import com.tterrag.registrate.builders.ItemBuilder; import com.tterrag.registrate.providers.ProviderType; @@ -172,9 +170,10 @@ public enum AllBlocks implements NonNullSupplier { ROTATION_CHASSIS(RadialChassisBlock::new), DRILL(DrillBlock::new), SAW(SawBlock::new), - HARVESTER(HarvesterBlock::new), DEPLOYER(DeployerBlock::new), PORTABLE_STORAGE_INTERFACE(PortableStorageInterfaceBlock::new), + HARVESTER(HarvesterBlock::new), + PLOUGH(PloughBlock::new), ANALOG_LEVER(AnalogLeverBlock::new), ANDESITE_CASING(() -> new CasingBlock("andesite_casing")), diff --git a/src/main/java/com/simibubi/create/AllBlocksNew.java b/src/main/java/com/simibubi/create/AllBlocksNew.java index f08bbe800..1c46ab971 100644 --- a/src/main/java/com/simibubi/create/AllBlocksNew.java +++ b/src/main/java/com/simibubi/create/AllBlocksNew.java @@ -5,8 +5,6 @@ import com.simibubi.create.modules.schematics.block.SchematicTableBlock; import com.simibubi.create.modules.schematics.block.SchematicannonBlock; import com.tterrag.registrate.util.RegistryEntry; -import net.minecraftforge.client.model.generators.ModelFile.UncheckedModelFile; - public class AllBlocksNew { private static final CreateRegistrate REGISTRATE = Create.registrate(); diff --git a/src/main/java/com/simibubi/create/AllEntities.java b/src/main/java/com/simibubi/create/AllEntities.java index a32e96ac9..23d7e223b 100644 --- a/src/main/java/com/simibubi/create/AllEntities.java +++ b/src/main/java/com/simibubi/create/AllEntities.java @@ -5,6 +5,8 @@ import java.util.function.Function; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity; import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntityRenderer; +import com.simibubi.create.modules.contraptions.components.contraptions.glue.SuperGlueEntity; +import com.simibubi.create.modules.contraptions.components.contraptions.glue.SuperGlueRenderer; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityClassification; @@ -23,6 +25,8 @@ public enum AllEntities { ContraptionEntity::build), STATIONARY_CONTRAPTION(ContraptionEntity::new, EntityClassification.MISC, 30, 40, false, ContraptionEntity::build), + SUPER_GLUE(SuperGlueEntity::new, EntityClassification.MISC, 30, Integer.MAX_VALUE, false, SuperGlueEntity::build), + ; private IFactory factory; @@ -63,8 +67,8 @@ public enum AllEntities { @SuppressWarnings("unchecked") // TODO 1.15 this generic stuff is incompatible with the enum system - need strong types @OnlyIn(value = Dist.CLIENT) public static void registerRenderers() { -// RenderingRegistry.registerEntityRenderingHandler(CardboardBoxEntity.class, CardboardBoxEntityRenderer::new); RenderingRegistry.registerEntityRenderingHandler((EntityType) CONTRAPTION.type, ContraptionEntityRenderer::new); + RenderingRegistry.registerEntityRenderingHandler((EntityType) SUPER_GLUE.type, SuperGlueRenderer::new); } } diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index 528e027a2..b61642f0d 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -16,6 +16,8 @@ import com.simibubi.create.foundation.utility.data.ITaggable; import com.simibubi.create.modules.IModule; import com.simibubi.create.modules.contraptions.GogglesItem; import com.simibubi.create.modules.contraptions.WrenchItem; +import com.simibubi.create.modules.contraptions.components.contraptions.glue.SuperGlueItem; +import com.simibubi.create.modules.contraptions.components.contraptions.mounted.MinecartContraptionItem; import com.simibubi.create.modules.contraptions.relays.belt.item.BeltConnectorItem; import com.simibubi.create.modules.contraptions.relays.gearbox.VerticalGearboxItem; import com.simibubi.create.modules.curiosities.ChromaticCompoundCubeItem; @@ -38,6 +40,7 @@ import com.simibubi.create.modules.schematics.item.SchematicItem; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.color.ItemColors; import net.minecraft.client.renderer.tileentity.ItemStackTileEntityRenderer; +import net.minecraft.entity.item.minecart.AbstractMinecartEntity.Type; import net.minecraft.item.Item; import net.minecraft.item.Item.Properties; import net.minecraft.item.ItemStack; @@ -75,8 +78,8 @@ public enum AllItems { ZINC_INGOT((TaggedItem) new TaggedItem().withForgeTags("ingots/zinc")), BRASS_INGOT((TaggedItem) new TaggedItem().withForgeTags("ingots/brass")), - SAND_PAPER(SandPaperItem::new), - RED_SAND_PAPER(SandPaperItem::new), + FLOUR, + DOUGH, OBSIDIAN_DUST, ROSE_QUARTZ, POLISHED_ROSE_QUARTZ, @@ -86,23 +89,20 @@ public enum AllItems { ELECTRON_TUBE, INTEGRATED_CIRCUIT, - __SCHEMATICS__(module()), - EMPTY_BLUEPRINT(Item::new, stackSize(1)), - BLUEPRINT_AND_QUILL(SchematicAndQuillItem::new, stackSize(1)), - BLUEPRINT(SchematicItem::new), - __CONTRAPTIONS__(module()), BELT_CONNECTOR(BeltConnectorItem::new), VERTICAL_GEARBOX(VerticalGearboxItem::new), - FLOUR, - DOUGH, PROPELLER, WHISK, BRASS_HAND, SLOT_COVER, - ZINC_HANDLE, + SUPER_GLUE(SuperGlueItem::new), + SAND_PAPER(SandPaperItem::new), + RED_SAND_PAPER(SandPaperItem::new), WRENCH(WrenchItem::new), GOGGLES(GogglesItem::new), + MINECART_CONTRAPTION(p -> new MinecartContraptionItem(Type.RIDEABLE, p)), + FURNACE_MINECART_CONTRAPTION(p -> new MinecartContraptionItem(Type.FURNACE, p)), __LOGISTICS__(module()), FILTER(FilterItem::new), @@ -114,6 +114,7 @@ public enum AllItems { TERRAIN_ZAPPER(TerrainzapperItem::new), DEFORESTER(DeforesterItem::new), SYMMETRY_WAND(SymmetryWandItem::new), + ZINC_HANDLE, BLAZING_PICKAXE(p -> new BlazingToolItem(1, -2.8F, p, PICKAXE)), BLAZING_SHOVEL(p -> new BlazingToolItem(1.5F, -3.0F, p, SHOVEL)), @@ -129,6 +130,11 @@ public enum AllItems { SHADOW_STEEL_MATTOCK(p -> new ShadowSteelToolItem(2.5F, -1.5F, p, SHOVEL, AXE, HOE)), SHADOW_STEEL_SWORD(p -> new SwordItem(AllToolTiers.SHADOW_STEEL, 3, -2.0F, p)), + __SCHEMATICS__(module()), + EMPTY_BLUEPRINT(Item::new, stackSize(1)), + BLUEPRINT_AND_QUILL(SchematicAndQuillItem::new, stackSize(1)), + BLUEPRINT(SchematicItem::new), + ; private static class CategoryTracker { @@ -197,7 +203,8 @@ public enum AllItems { continue; entry.item = entry.taggedItem.getItemSupplier().apply(new Properties()); - entry.item = entry.taggedItem.getItemSupplier().apply(entry.specialProperties.apply(defaultProperties(entry))); + entry.item = + entry.taggedItem.getItemSupplier().apply(entry.specialProperties.apply(defaultProperties(entry))); entry.item.setRegistryName(Create.ID, Lang.asId(entry.name())); registry.register(entry.item); } @@ -224,11 +231,11 @@ public enum AllItems { private Set tagSetItem = new HashSet<>(); private Function itemSupplier; - public TaggedItem(){ + public TaggedItem() { this(Item::new); } - public TaggedItem(Function itemSupplierIn){ + public TaggedItem(Function itemSupplierIn) { this.itemSupplier = itemSupplierIn; } diff --git a/src/main/java/com/simibubi/create/AllPackets.java b/src/main/java/com/simibubi/create/AllPackets.java index a7ad8772e..45c5adb12 100644 --- a/src/main/java/com/simibubi/create/AllPackets.java +++ b/src/main/java/com/simibubi/create/AllPackets.java @@ -13,6 +13,7 @@ import com.simibubi.create.foundation.packet.SimplePacketBase; import com.simibubi.create.foundation.utility.ServerSpeedProvider; import com.simibubi.create.modules.contraptions.components.contraptions.CancelPlayerFallPacket; import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionStallPacket; +import com.simibubi.create.modules.contraptions.components.contraptions.glue.GlueEffectPacket; import com.simibubi.create.modules.contraptions.relays.advanced.sequencer.ConfigureSequencedGearshiftPacket; import com.simibubi.create.modules.curiosities.symmetry.SymmetryEffectPacket; import com.simibubi.create.modules.curiosities.zapper.ZapperBeamPacket; @@ -51,6 +52,7 @@ public enum AllPackets { CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new), CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new), TOOL_HARVEST(AbstractToolItem.HarvestPacket.class, AbstractToolItem.HarvestPacket::new), + GLUE_EFFECT(GlueEffectPacket.class, GlueEffectPacket::new), ; diff --git a/src/main/java/com/simibubi/create/AllSpecialTextures.java b/src/main/java/com/simibubi/create/AllSpecialTextures.java index 67aa34421..bba4fc2a7 100644 --- a/src/main/java/com/simibubi/create/AllSpecialTextures.java +++ b/src/main/java/com/simibubi/create/AllSpecialTextures.java @@ -8,6 +8,9 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber; @EventBusSubscriber(value = Dist.CLIENT) public enum AllSpecialTextures { + BLANK("blank.png"), + CHECKERED("checkerboard.png"), + HIGHLIGHT_CHECKERED("highlighted_checkerboard.png"), SELECTION("selection.png"), ; diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index af21d93db..d2df8cd2f 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -16,6 +16,7 @@ import com.simibubi.create.modules.contraptions.components.contraptions.bearing. import com.simibubi.create.modules.contraptions.components.contraptions.bearing.ClockworkBearingTileEntity; import com.simibubi.create.modules.contraptions.components.contraptions.bearing.MechanicalBearingTileEntity; import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity; +import com.simibubi.create.modules.contraptions.components.contraptions.mounted.CartAssemblerTileEntity; import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonTileEntity; import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonTileEntityRenderer; import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyRenderer; @@ -148,6 +149,7 @@ public enum AllTileEntities { SPEED_GAUGE(SpeedGaugeTileEntity::new, AllBlocks.SPEED_GAUGE), STRESS_GAUGE(StressGaugeTileEntity::new, AllBlocks.STRESS_GAUGE), ANALOG_LEVER(AnalogLeverTileEntity::new, AllBlocks.ANALOG_LEVER), + CART_ASSEMBLER(CartAssemblerTileEntity::new, AllBlocks.CART_ASSEMBLER), // Logistics REDSTONE_BRIDGE(RedstoneLinkTileEntity::new, AllBlocks.REDSTONE_BRIDGE), diff --git a/src/main/java/com/simibubi/create/ClientEvents.java b/src/main/java/com/simibubi/create/ClientEvents.java index bf352d7c2..ecef9536e 100644 --- a/src/main/java/com/simibubi/create/ClientEvents.java +++ b/src/main/java/com/simibubi/create/ClientEvents.java @@ -80,8 +80,6 @@ public class ClientEvents { IRenderTypeBuffer.Impl buffer = Minecraft.getInstance().getBufferBuilders().getEntityVertexConsumers(); CreateClient.schematicHandler.render(ms, buffer, 0xF000F0, OverlayTexture.DEFAULT_UV); - CreateClient.schematicAndQuillHandler.render(ms, buffer); - CreateClient.schematicHologram.render(ms, buffer); KineticDebugger.renderSourceOutline(ms, buffer); ChassisRangeDisplay.renderOutlines(event.getPartialTicks(), ms, buffer); TerrainZapperRenderHandler.render(ms, buffer); diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index 1c4c73eb3..795d5a420 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -16,7 +16,6 @@ import com.simibubi.create.modules.contraptions.components.contraptions.Contrapt import com.simibubi.create.modules.schematics.ClientSchematicLoader; import com.simibubi.create.modules.schematics.client.SchematicAndQuillHandler; import com.simibubi.create.modules.schematics.client.SchematicHandler; -import com.simibubi.create.modules.schematics.client.SchematicHologram; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; @@ -41,10 +40,8 @@ public class CreateClient { public static ClientSchematicLoader schematicSender; public static SchematicHandler schematicHandler; - public static SchematicHologram schematicHologram; public static SchematicAndQuillHandler schematicAndQuillHandler; public static SuperByteBufferCache bufferCache; - public static int renderTicks; public static void addListeners(IEventBus modEventBus) { DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { @@ -59,7 +56,6 @@ public class CreateClient { public static void clientInit(FMLClientSetupEvent event) { schematicSender = new ClientSchematicLoader(); schematicHandler = new SchematicHandler(); - schematicHologram = new SchematicHologram(); schematicAndQuillHandler = new SchematicAndQuillHandler(); bufferCache = new SuperByteBufferCache(); @@ -82,7 +78,6 @@ public class CreateClient { schematicSender.tick(); schematicAndQuillHandler.tick(); schematicHandler.tick(); - schematicHologram.tick(); ChassisRangeDisplay.clientTick(); } diff --git a/src/main/java/com/simibubi/create/ScreenResources.java b/src/main/java/com/simibubi/create/ScreenResources.java index 307b26599..19f7f780a 100644 --- a/src/main/java/com/simibubi/create/ScreenResources.java +++ b/src/main/java/com/simibubi/create/ScreenResources.java @@ -41,7 +41,7 @@ public enum ScreenResources { FILTER("filter.png", 200, 100), ATTRIBUTE_FILTER("filter.png", 0, 100, 200, 86), - + SEQUENCER("sequencer.png", 156, 128), SEQUENCER_INSTRUCTION("sequencer.png", 14, 47, 131, 18), SEQUENCER_WAIT("sequencer.png", 14, 65, 131, 18), @@ -79,6 +79,7 @@ public enum ScreenResources { // JEI JEI_SLOT("jei/widgets.png", 18, 18), + JEI_CHANCE_SLOT("jei/widgets.png", 20, 156, 18, 18), JEI_CATALYST_SLOT("jei/widgets.png", 0, 156, 18, 18), JEI_ARROW("jei/widgets.png", 19, 10, 42, 10), JEI_LONG_ARROW("jei/widgets.png", 19, 0, 71, 10), @@ -132,6 +133,9 @@ public enum ScreenResources { I_MOVE_PLACE(9, 1), I_MOVE_PLACE_RETURNED(10, 1), I_MOVE_NEVER_PLACE(11, 1), + I_CART_ROTATE(12, 1), + I_CART_ROTATE_PAUSED(13, 1), + I_CART_ROTATE_LOCKED(14, 1), I_DONT_REPLACE(0, 2), I_REPLACE_SOLID(1, 2), diff --git a/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java b/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java index 4bbf9f277..ff99bd785 100644 --- a/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java +++ b/src/main/java/com/simibubi/create/compat/jei/CreateJEI.java @@ -1,7 +1,6 @@ package com.simibubi.create.compat.jei; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; import com.google.common.base.Predicate; @@ -28,13 +27,11 @@ import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCraftingRecipe; import com.simibubi.create.modules.contraptions.components.mixer.MixingRecipe; import com.simibubi.create.modules.contraptions.components.press.MechanicalPressTileEntity; -import com.simibubi.create.modules.contraptions.processing.ProcessingOutput; import com.simibubi.create.modules.logistics.block.inventories.FlexcrateScreen; import com.simibubi.create.modules.schematics.block.SchematicannonScreen; import mezz.jei.api.IModPlugin; import mezz.jei.api.JeiPlugin; -import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.registration.IGuiHandlerRegistration; import mezz.jei.api.registration.IRecipeCatalystRegistration; import mezz.jei.api.registration.IRecipeCategoryRegistration; @@ -226,28 +223,4 @@ public class CreateJEI implements IModPlugin { return byType; } - public static void addStochasticTooltip(IGuiItemStackGroup itemStacks, List results) { - itemStacks.addTooltipCallback((slotIndex, input, ingredient, tooltip) -> { - if (input) - return; - ProcessingOutput output = results.get(slotIndex - 1); - if (output.getChance() != 1) - tooltip.add(1, TextFormatting.GOLD - + Lang.translate("recipe.processing.chance", (int) (output.getChance() * 100))); - }); - } - - public static void addCatalystTooltip(IGuiItemStackGroup itemStacks, Map catalystIndices) { - itemStacks.addTooltipCallback((slotIndex, input, ingredient, tooltip) -> { - if (!input) - return; - if (!catalystIndices.containsKey(slotIndex)) - return; - Float chance = catalystIndices.get(slotIndex); - tooltip.add(1, TextFormatting.YELLOW + Lang.translate("recipe.processing.catalyst")); - tooltip.add(2, TextFormatting.GOLD - + Lang.translate("recipe.processing.chanceToReturn", (int) (chance.floatValue() * 100))); - }); - } - } diff --git a/src/main/java/com/simibubi/create/compat/jei/category/BlastingViaFanCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/BlastingViaFanCategory.java index 1205eda1f..09639ad45 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/BlastingViaFanCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/BlastingViaFanCategory.java @@ -2,38 +2,18 @@ package com.simibubi.create.compat.jei.category; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllItems; -import com.simibubi.create.Create; -import com.simibubi.create.compat.jei.DoubleItemIcon; import com.simibubi.create.foundation.gui.ScreenElementRenderer; -import com.simibubi.create.foundation.utility.Lang; -import mezz.jei.api.gui.drawable.IDrawable; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.FlowingFluidBlock; -import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.crafting.AbstractCookingRecipe; -import net.minecraft.util.ResourceLocation; public class BlastingViaFanCategory extends ProcessingViaFanCategory { - private static ResourceLocation ID = new ResourceLocation(Create.ID, "blasting_via_fan"); - private IDrawable icon; - public BlastingViaFanCategory() { - icon = new DoubleItemIcon(() -> new ItemStack(AllItems.PROPELLER.get()), - () -> new ItemStack(Items.LAVA_BUCKET)); - } - - @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return ID; + super("blasting_via_fan", doubleItemIcon(AllItems.PROPELLER.get(), Items.LAVA_BUCKET)); } @Override @@ -41,11 +21,6 @@ public class BlastingViaFanCategory extends ProcessingViaFanCategory { +public class BlockCuttingCategory extends CreateRecipeCategory { - private AnimatedSaw saw; - private static ResourceLocation ID = new ResourceLocation(Create.ID, "block_cutting"); - private IDrawable icon; - private IDrawable background = new EmptyBackground(177, 70); + private AnimatedSaw saw = new AnimatedSaw(); public BlockCuttingCategory() { - icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.SAW.get()), - () -> new ItemStack(Items.STONE_BRICK_STAIRS)); - saw = new AnimatedSaw(); - } - - @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return ID; + super("block_cutting", doubleItemIcon(AllBlocks.SAW.get(), Items.STONE_BRICK_STAIRS), emptyBackground(177, 70)); } @Override @@ -55,16 +34,6 @@ public class BlockCuttingCategory implements IRecipeCategory { - - private static ResourceLocation ID = new ResourceLocation(Create.ID, "blockzapper_upgrade"); - private IDrawable icon; +public class BlockzapperUpgradeCategory extends CreateRecipeCategory { public BlockzapperUpgradeCategory() { - icon = new DoubleItemIcon(() -> new ItemStack(AllItems.PLACEMENT_HANDGUN.get()), - () -> ItemStack.EMPTY); // replace with uparrow when available - } - - @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return ID; + super("blockzapper_upgrade", itemIcon(AllItems.PLACEMENT_HANDGUN.get()), + new ScreenResourceWrapper(BLOCKZAPPER_UPGRADE_RECIPE)); } @Override @@ -57,16 +38,6 @@ public class BlockzapperUpgradeCategory implements IRecipeCategory> implements IRecipeCategory { + + private ResourceLocation uid; + private String name; + private IDrawable icon; + private IDrawable background; + + public CreateRecipeCategory(String id, IDrawable icon, IDrawable background) { + uid = new ResourceLocation(Create.ID, id); + name = id; + this.background = background; + this.icon = icon; + } + + @Override + public IDrawable getIcon() { + return icon; + } + + @Override + public ResourceLocation getUid() { + return uid; + } + + @Override + public String getTitle() { + return Lang.translate("recipe." + name); + } + + @Override + public IDrawable getBackground() { + return background; + } + + protected static ScreenResources getRenderedSlot(IRecipe recipe, int index) { + ScreenResources jeiSlot = ScreenResources.JEI_SLOT; + if (!(recipe instanceof ProcessingRecipe)) + return jeiSlot; + ProcessingRecipe processingRecipe = (ProcessingRecipe) recipe; + List rollableResults = processingRecipe.getRollableResults(); + if (rollableResults.size() <= index) + return jeiSlot; + if (processingRecipe.getRollableResults().get(index).getChance() == 1) + return jeiSlot; + return ScreenResources.JEI_CHANCE_SLOT; + } + + protected static IDrawable emptyBackground(int width, int height) { + return new EmptyBackground(width, height); + } + + protected static IDrawable doubleItemIcon(IItemProvider item1, IItemProvider item2) { + return new DoubleItemIcon(() -> new ItemStack(item1), () -> new ItemStack(item2)); + } + + protected static IDrawable itemIcon(IItemProvider item) { + return new DoubleItemIcon(() -> new ItemStack(item), () -> ItemStack.EMPTY); + } + + protected static void addStochasticTooltip(IGuiItemStackGroup itemStacks, List results) { + itemStacks.addTooltipCallback((slotIndex, input, ingredient, tooltip) -> { + if (input) + return; + ProcessingOutput output = results.get(slotIndex - 1); + if (output.getChance() != 1) + tooltip.add(1, TextFormatting.GOLD + + Lang.translate("recipe.processing.chance", (int) (output.getChance() * 100))); + }); + } + + protected static void addCatalystTooltip(IGuiItemStackGroup itemStacks, Map catalystIndices) { + itemStacks.addTooltipCallback((slotIndex, input, ingredient, tooltip) -> { + if (!input) + return; + if (!catalystIndices.containsKey(slotIndex)) + return; + Float chance = catalystIndices.get(slotIndex); + tooltip.add(1, TextFormatting.YELLOW + Lang.translate("recipe.processing.catalyst")); + tooltip.add(2, TextFormatting.GOLD + + Lang.translate("recipe.processing.chanceToReturn", (int) (chance.floatValue() * 100))); + }); + } + +} diff --git a/src/main/java/com/simibubi/create/compat/jei/category/CrushingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/CrushingCategory.java index 2b4bdc07a..0b2fb2238 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/CrushingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/CrushingCategory.java @@ -5,45 +5,23 @@ import java.util.List; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.Create; import com.simibubi.create.ScreenResources; -import com.simibubi.create.compat.jei.CreateJEI; -import com.simibubi.create.compat.jei.DoubleItemIcon; -import com.simibubi.create.compat.jei.EmptyBackground; import com.simibubi.create.compat.jei.category.animations.AnimatedCrushingWheels; -import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.modules.contraptions.components.crusher.AbstractCrushingRecipe; import com.simibubi.create.modules.contraptions.processing.ProcessingOutput; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.category.IRecipeCategory; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; -public class CrushingCategory implements IRecipeCategory { +public class CrushingCategory extends CreateRecipeCategory { - private static ResourceLocation ID = new ResourceLocation(Create.ID, "crushing"); private AnimatedCrushingWheels crushingWheels = new AnimatedCrushingWheels(); - private IDrawable icon; - private IDrawable background = new EmptyBackground(177, 100); public CrushingCategory() { - icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.CRUSHING_WHEEL.get()), - () -> new ItemStack(AllItems.CRUSHED_GOLD.get())); - } - - @Override - public IDrawable getBackground() { - return background; - } - - @Override - public ResourceLocation getUid() { - return ID; + super("crushing", doubleItemIcon(AllBlocks.CRUSHING_WHEEL.get(), AllItems.CRUSHED_GOLD.get()), + emptyBackground(177, 100)); } @Override @@ -51,16 +29,6 @@ public class CrushingCategory implements IRecipeCategory return AbstractCrushingRecipe.class; } - @Override - public String getTitle() { - return Lang.translate("recipe.crushing"); - } - - @Override - public IDrawable getIcon() { - return icon; - } - @Override public void setIngredients(AbstractCrushingRecipe recipe, IIngredients ingredients) { ingredients.setInputIngredients(recipe.getIngredients()); @@ -81,7 +49,7 @@ public class CrushingCategory implements IRecipeCategory itemStacks.set(outputIndex + 1, results.get(outputIndex).getStack()); } - CreateJEI.addStochasticTooltip(itemStacks, results); + addStochasticTooltip(itemStacks, results); } @Override @@ -93,7 +61,7 @@ public class CrushingCategory implements IRecipeCategory int size = results.size(); int offset = -size * 19 / 2; for (int outputIndex = 0; outputIndex < results.size(); outputIndex++) - ScreenResources.JEI_SLOT.draw(getBackground().getWidth() / 2 + offset + 19 * outputIndex, 78); + getRenderedSlot(recipe, outputIndex).draw(getBackground().getWidth() / 2 + offset + 19 * outputIndex, 78); crushingWheels.draw(92, 49); } diff --git a/src/main/java/com/simibubi/create/compat/jei/category/MechanicalCraftingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/MechanicalCraftingCategory.java index 9ee140650..9d6406833 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/MechanicalCraftingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/MechanicalCraftingCategory.java @@ -3,65 +3,39 @@ package com.simibubi.create.compat.jei.category; import java.util.Arrays; import com.simibubi.create.AllBlocks; -import com.simibubi.create.Create; import com.simibubi.create.ScreenResources; -import com.simibubi.create.compat.jei.DoubleItemIcon; -import com.simibubi.create.compat.jei.EmptyBackground; import com.simibubi.create.compat.jei.category.animations.AnimatedCrafter; import com.simibubi.create.foundation.utility.Lang; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.category.IRecipeCategory; -import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; import net.minecraft.item.crafting.ShapedRecipe; import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; -public class MechanicalCraftingCategory implements IRecipeCategory { +public class MechanicalCraftingCategory extends CreateRecipeCategory { private AnimatedCrafter crafter; - private ResourceLocation id; - private IDrawable icon; - private IDrawable background; private boolean large; public MechanicalCraftingCategory(boolean large) { + super("mechanical_crafting" + (large ? "_large" : ""), itemIcon(AllBlocks.MECHANICAL_CRAFTER.get()), + emptyBackground(large ? 177 : 177, large ? 235 : 81)); this.large = large; - icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.MECHANICAL_CRAFTER.get()), () -> ItemStack.EMPTY); crafter = new AnimatedCrafter(large); - id = new ResourceLocation(Create.ID, "mechanical_crafting" + (large ? "_large" : "")); - background = new EmptyBackground(large ? 177 : 177, large ? 235 : 81); } public static boolean isSmall(ShapedRecipe recipe) { return Math.max((recipe).getWidth(), (recipe).getHeight()) <= 4; } - @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return id; - } - @Override public String getTitle() { return Lang.translate("recipe.mechanical_crafting"); } - @Override - public IDrawable getBackground() { - return background; - } - @Override public void setIngredients(ShapedRecipe recipe, IIngredients ingredients) { ingredients.setInputIngredients(recipe.getIngredients()); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/MillingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/MillingCategory.java index 25a555411..86e0b9b23 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/MillingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/MillingCategory.java @@ -5,45 +5,22 @@ import java.util.List; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; -import com.simibubi.create.Create; import com.simibubi.create.ScreenResources; -import com.simibubi.create.compat.jei.CreateJEI; -import com.simibubi.create.compat.jei.DoubleItemIcon; -import com.simibubi.create.compat.jei.EmptyBackground; import com.simibubi.create.compat.jei.category.animations.AnimatedMillstone; -import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.modules.contraptions.components.crusher.AbstractCrushingRecipe; import com.simibubi.create.modules.contraptions.processing.ProcessingOutput; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.category.IRecipeCategory; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; -public class MillingCategory implements IRecipeCategory { +public class MillingCategory extends CreateRecipeCategory { - private static ResourceLocation ID = new ResourceLocation(Create.ID, "milling"); private AnimatedMillstone millstone = new AnimatedMillstone(); - private IDrawable icon; - private IDrawable background = new EmptyBackground(177, 53); public MillingCategory() { - icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.MILLSTONE.get()), - () -> new ItemStack(AllItems.FLOUR.get())); - } - - @Override - public IDrawable getBackground() { - return background; - } - - @Override - public ResourceLocation getUid() { - return ID; + super("milling", doubleItemIcon(AllBlocks.MILLSTONE.get(), AllItems.FLOUR.get()), emptyBackground(177, 53)); } @Override @@ -51,16 +28,6 @@ public class MillingCategory implements IRecipeCategory return AbstractCrushingRecipe.class; } - @Override - public String getTitle() { - return Lang.translate("recipe.milling"); - } - - @Override - public IDrawable getIcon() { - return icon; - } - @Override public void setIngredients(AbstractCrushingRecipe recipe, IIngredients ingredients) { ingredients.setInputIngredients(recipe.getIngredients()); @@ -83,7 +50,7 @@ public class MillingCategory implements IRecipeCategory itemStacks.set(outputIndex + 1, results.get(outputIndex).getStack()); } - CreateJEI.addStochasticTooltip(itemStacks, results); + addStochasticTooltip(itemStacks, results); } @Override @@ -95,17 +62,19 @@ public class MillingCategory implements IRecipeCategory ScreenResources.JEI_ARROW.draw(85, 32); ScreenResources.JEI_DOWN_ARROW.draw(43, 4); - if (size > 1) { - for (int i = 0; i < size; i++) { - int xOffset = i % 2 == 0 ? 0 : 19; - int yOffset = (i / 2) * -19; - ScreenResources.JEI_SLOT.draw(133 + xOffset, 27 + yOffset); - } - } else { - ScreenResources.JEI_SLOT.draw(139, 27); + millstone.draw(57, 27); + + if (size == 1) { + getRenderedSlot(recipe, 0).draw(139, 27); + return; + } + + for (int i = 0; i < size; i++) { + int xOffset = i % 2 == 0 ? 0 : 19; + int yOffset = (i / 2) * -19; + getRenderedSlot(recipe, i).draw(133 + xOffset, 27 + yOffset); } - millstone.draw(57, 27); } } diff --git a/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java index 00342dcb7..65e165a19 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/MixingCategory.java @@ -10,59 +10,32 @@ import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.AllBlocks; -import com.simibubi.create.Create; import com.simibubi.create.ScreenResources; -import com.simibubi.create.compat.jei.CreateJEI; -import com.simibubi.create.compat.jei.DoubleItemIcon; -import com.simibubi.create.compat.jei.EmptyBackground; import com.simibubi.create.compat.jei.category.animations.AnimatedMixer; import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.modules.contraptions.components.mixer.MixingRecipe; import com.simibubi.create.modules.contraptions.processing.ProcessingIngredient; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.category.IRecipeCategory; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; -public class MixingCategory implements IRecipeCategory { +public class MixingCategory extends CreateRecipeCategory { - private AnimatedMixer mixer; - private static ResourceLocation ID = new ResourceLocation(Create.ID, "mixing"); - private IDrawable icon; - private IDrawable background = new EmptyBackground(177, 70); + private AnimatedMixer mixer = new AnimatedMixer(); public MixingCategory() { - icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.MECHANICAL_MIXER.get()), - () -> new ItemStack(AllBlocks.BASIN.get())); - mixer = new AnimatedMixer(); + super("mixing", doubleItemIcon(AllBlocks.MECHANICAL_MIXER.get(), AllBlocks.BASIN.get()), + emptyBackground(177, 70)); } @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return ID; - } - - @Override - public String getTitle() { - return Lang.translate("recipe.mixing"); - } - - @Override - public IDrawable getBackground() { - return background; + public Class getRecipeClass() { + return MixingRecipe.class; } @Override @@ -77,7 +50,7 @@ public class MixingCategory implements IRecipeCategory { NonNullList recipeIngredients = recipe.getIngredients(); List> actualIngredients = ItemHelper.condenseIngredients(recipeIngredients); - + Map catalystIndices = new HashMap<>(9); for (int i = 0; i < actualIngredients.size(); i++) { for (ProcessingIngredient processingIngredient : recipe.getRollableIngredients()) { @@ -107,13 +80,11 @@ public class MixingCategory implements IRecipeCategory { itemStacks.init(i, false, 141, 50); itemStacks.set(i, recipe.getRecipeOutput().getStack()); - CreateJEI.addCatalystTooltip(itemStacks, catalystIndices); + addCatalystTooltip(itemStacks, catalystIndices); } @Override public void draw(MixingRecipe recipe, double mouseX, double mouseY) { - // this might actually be pretty bad with big ingredients. ^ its a draw method - List> actualIngredients = ItemHelper.condenseIngredients(recipe.getIngredients()); int size = actualIngredients.size(); @@ -135,9 +106,4 @@ public class MixingCategory implements IRecipeCategory { mixer.draw(getBackground().getWidth() / 2 + 20, 8); } - @Override - public Class getRecipeClass() { - return MixingRecipe.class; - } - } diff --git a/src/main/java/com/simibubi/create/compat/jei/category/MysteriousItemConversionCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/MysteriousItemConversionCategory.java index 85277b79f..5dca137a5 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/MysteriousItemConversionCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/MysteriousItemConversionCategory.java @@ -5,29 +5,16 @@ import java.util.Arrays; import java.util.List; import com.simibubi.create.AllItems; -import com.simibubi.create.Create; import com.simibubi.create.ScreenResources; import com.simibubi.create.compat.jei.ConversionRecipe; -import com.simibubi.create.compat.jei.CreateJEI; -import com.simibubi.create.compat.jei.DoubleItemIcon; -import com.simibubi.create.compat.jei.EmptyBackground; -import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.modules.contraptions.processing.ProcessingOutput; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.category.IRecipeCategory; -import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; -public class MysteriousItemConversionCategory implements IRecipeCategory { - - private static ResourceLocation ID = new ResourceLocation(Create.ID, "mystery_conversion"); - private IDrawable icon; - private IDrawable background = new EmptyBackground(177, 50); +public class MysteriousItemConversionCategory extends CreateRecipeCategory { public static List getRecipes() { List recipes = new ArrayList<>(); @@ -37,17 +24,7 @@ public class MysteriousItemConversionCategory implements IRecipeCategory AllItems.CHROMATIC_COMPOUND.asStack(), () -> ItemStack.EMPTY); - } - - @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return ID; + super("mystery_conversion", itemIcon(AllItems.CHROMATIC_COMPOUND.get()), emptyBackground(177, 50)); } @Override @@ -55,16 +32,6 @@ public class MysteriousItemConversionCategory implements IRecipeCategory results = recipe.getRollableResults(); - itemStacks.init(0, true, 26, 16); itemStacks.set(0, Arrays.asList(recipe.getIngredients().get(0).getMatchingStacks())); itemStacks.init(1, false, 131, 16); itemStacks.set(1, results.get(0).getStack()); - - CreateJEI.addStochasticTooltip(itemStacks, results); } @Override diff --git a/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java index c7c0f7bad..90b1d180f 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/PackingCategory.java @@ -3,47 +3,25 @@ package com.simibubi.create.compat.jei.category; import java.util.Arrays; import com.simibubi.create.AllBlocks; -import com.simibubi.create.Create; import com.simibubi.create.ScreenResources; -import com.simibubi.create.compat.jei.DoubleItemIcon; -import com.simibubi.create.compat.jei.EmptyBackground; import com.simibubi.create.compat.jei.category.animations.AnimatedPress; -import com.simibubi.create.foundation.utility.Lang; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.category.IRecipeCategory; -import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.ICraftingRecipe; import net.minecraft.item.crafting.IRecipe; import net.minecraft.item.crafting.Ingredient; import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; -public class PackingCategory implements IRecipeCategory> { +public class PackingCategory extends CreateRecipeCategory> { - private AnimatedPress press; - private static ResourceLocation ID = new ResourceLocation(Create.ID, "packing"); - private IDrawable icon; - private IDrawable background = new EmptyBackground(177, 70); + private AnimatedPress press = new AnimatedPress(true); public PackingCategory() { - icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.MECHANICAL_PRESS.get()), - () -> new ItemStack(AllBlocks.BASIN.get())); - press = new AnimatedPress(true); - } - - @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return ID; + super("packing", doubleItemIcon(AllBlocks.MECHANICAL_PRESS.get(), AllBlocks.BASIN.get()), + emptyBackground(177, 70)); } @Override @@ -51,16 +29,6 @@ public class PackingCategory implements IRecipeCategory> { return ICraftingRecipe.class; } - @Override - public String getTitle() { - return Lang.translate("recipe.packing"); - } - - @Override - public IDrawable getBackground() { - return background; - } - @Override public void setIngredients(IRecipe recipe, IIngredients ingredients) { ingredients.setInputIngredients(recipe.getIngredients()); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java index 3eae7a0ce..c3d222e2f 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/PolishingCategory.java @@ -5,66 +5,35 @@ import java.util.List; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllItems; -import com.simibubi.create.Create; import com.simibubi.create.ScreenResources; -import com.simibubi.create.compat.jei.CreateJEI; -import com.simibubi.create.compat.jei.DoubleItemIcon; -import com.simibubi.create.compat.jei.EmptyBackground; -import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.modules.contraptions.processing.ProcessingOutput; import com.simibubi.create.modules.curiosities.tools.SandPaperPolishingRecipe; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.category.IRecipeCategory; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.ItemRenderer; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.NonNullList; -import net.minecraft.util.ResourceLocation; -public class PolishingCategory implements IRecipeCategory { +public class PolishingCategory extends CreateRecipeCategory { - private static ResourceLocation ID = new ResourceLocation(Create.ID, "sandpaper_polishing"); - private IDrawable icon; - private IDrawable background = new EmptyBackground(177, 55); private ItemStack renderedSandpaper; public PolishingCategory() { - icon = new DoubleItemIcon(() -> AllItems.SAND_PAPER.asStack(), () -> ItemStack.EMPTY); + super("sandpaper_polishing", itemIcon(AllItems.SAND_PAPER.get()), emptyBackground(177, 55)); renderedSandpaper = AllItems.SAND_PAPER.asStack(); } - @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return ID; - } - @Override public Class getRecipeClass() { return SandPaperPolishingRecipe.class; } - @Override - public String getTitle() { - return Lang.translate("recipe.sandpaper_polishing"); - } - - @Override - public IDrawable getBackground() { - return background; - } - @Override public void setIngredients(SandPaperPolishingRecipe recipe, IIngredients ingredients) { ingredients.setInputIngredients(recipe.getIngredients()); @@ -81,13 +50,13 @@ public class PolishingCategory implements IRecipeCategory { +public class PressingCategory extends CreateRecipeCategory { - private AnimatedPress press; - private static ResourceLocation ID = new ResourceLocation(Create.ID, "pressing"); - private IDrawable icon; - private IDrawable background = new EmptyBackground(177, 70); + private AnimatedPress press = new AnimatedPress(false); public PressingCategory() { - icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.MECHANICAL_PRESS.get()), - () -> new ItemStack(AllItems.IRON_SHEET.get())); - press = new AnimatedPress(false); - } - - @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return ID; + super("pressing", doubleItemIcon(AllBlocks.MECHANICAL_PRESS.get(), AllItems.IRON_SHEET.get()), + emptyBackground(177, 70)); } @Override @@ -52,16 +29,6 @@ public class PressingCategory implements IRecipeCategory { return PressingRecipe.class; } - @Override - public String getTitle() { - return Lang.translate("recipe.pressing"); - } - - @Override - public IDrawable getBackground() { - return background; - } - @Override public void setIngredients(PressingRecipe recipe, IIngredients ingredients) { ingredients.setInputIngredients(recipe.getIngredients()); @@ -79,16 +46,16 @@ public class PressingCategory implements IRecipeCategory { itemStacks.init(outputIndex + 1, false, 131 + 19 * outputIndex, 50); itemStacks.set(outputIndex + 1, results.get(outputIndex).getStack()); } - - CreateJEI.addStochasticTooltip(itemStacks, results); + + addStochasticTooltip(itemStacks, results); } @Override public void draw(PressingRecipe recipe, double mouseX, double mouseY) { ScreenResources.JEI_SLOT.draw(26, 50); - ScreenResources.JEI_SLOT.draw(131, 50); + getRenderedSlot(recipe, 0).draw(131, 50); if (recipe.getRollableResults().size() > 1) - ScreenResources.JEI_SLOT.draw(131 + 19, 50); + getRenderedSlot(recipe, 1).draw(131 + 19, 50); ScreenResources.JEI_SHADOW.draw(61, 41); ScreenResources.JEI_LONG_ARROW.draw(52, 54); press.draw(getBackground().getWidth() / 2, 8); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java index 6c4465c97..5ac987bfa 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/ProcessingViaFanCategory.java @@ -6,7 +6,6 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; import com.simibubi.create.ScreenResources; -import com.simibubi.create.compat.jei.EmptyBackground; import com.simibubi.create.compat.jei.category.animations.AnimatedKinetics; import com.simibubi.create.foundation.gui.ScreenElementRenderer; @@ -15,22 +14,18 @@ import mezz.jei.api.gui.IRecipeLayout; import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.category.IRecipeCategory; import net.minecraft.block.BlockState; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.item.crafting.IRecipe; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.util.Direction; -public abstract class ProcessingViaFanCategory> implements IRecipeCategory { +public abstract class ProcessingViaFanCategory> extends CreateRecipeCategory { - private IDrawable background = new EmptyBackground(177, 70); - - @Override - public IDrawable getBackground() { - return background; + public ProcessingViaFanCategory(String name, IDrawable icon) { + super(name, icon, emptyBackground(177, 70)); } - + @Override public void setIngredients(T recipe, IIngredients ingredients) { ingredients.setInputIngredients(recipe.getIngredients()); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/SawingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/SawingCategory.java index 7a42a14ae..b0a17e4c2 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/SawingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/SawingCategory.java @@ -4,46 +4,23 @@ import java.util.Arrays; import java.util.List; import com.simibubi.create.AllBlocks; -import com.simibubi.create.Create; import com.simibubi.create.ScreenResources; -import com.simibubi.create.compat.jei.CreateJEI; -import com.simibubi.create.compat.jei.DoubleItemIcon; -import com.simibubi.create.compat.jei.EmptyBackground; import com.simibubi.create.compat.jei.category.animations.AnimatedSaw; -import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.modules.contraptions.components.saw.CuttingRecipe; import com.simibubi.create.modules.contraptions.processing.ProcessingOutput; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.ingredients.IIngredients; -import mezz.jei.api.recipe.category.IRecipeCategory; -import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.util.ResourceLocation; -public class SawingCategory implements IRecipeCategory { +public class SawingCategory extends CreateRecipeCategory { - private AnimatedSaw saw; - private static ResourceLocation ID = new ResourceLocation(Create.ID, "sawing"); - private IDrawable icon; - private IDrawable background = new EmptyBackground(177, 70); + private AnimatedSaw saw = new AnimatedSaw(); public SawingCategory() { - icon = new DoubleItemIcon(() -> new ItemStack(AllBlocks.SAW.get()), () -> new ItemStack(Items.OAK_LOG)); - saw = new AnimatedSaw(); - } - - @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return ID; + super("sawing", doubleItemIcon(AllBlocks.SAW.get(), Items.OAK_LOG), emptyBackground(177, 70)); } @Override @@ -51,16 +28,6 @@ public class SawingCategory implements IRecipeCategory { return CuttingRecipe.class; } - @Override - public String getTitle() { - return Lang.translate("recipe.sawing"); - } - - @Override - public IDrawable getBackground() { - return background; - } - @Override public void setIngredients(CuttingRecipe recipe, IIngredients ingredients) { ingredients.setInputIngredients(recipe.getIngredients()); @@ -81,8 +48,8 @@ public class SawingCategory implements IRecipeCategory { itemStacks.init(outputIndex + 1, false, 117 + xOffset, 47 + yOffset); itemStacks.set(outputIndex + 1, results.get(outputIndex).getStack()); } - - CreateJEI.addStochasticTooltip(itemStacks, results); + + addStochasticTooltip(itemStacks, results); } @Override @@ -92,7 +59,7 @@ public class SawingCategory implements IRecipeCategory { for (int i = 0; i < size; i++) { int xOffset = i % 2 == 0 ? 0 : 19; int yOffset = (i / 2) * -19; - ScreenResources.JEI_SLOT.draw(117 + xOffset, 47 + yOffset); + getRenderedSlot(recipe, i).draw(117 + xOffset, 47 + yOffset); } ScreenResources.JEI_DOWN_ARROW.draw(70, 6); ScreenResources.JEI_SHADOW.draw(58, 55); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/SmokingViaFanCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/SmokingViaFanCategory.java index 1444881d9..1ddd16611 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/SmokingViaFanCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/SmokingViaFanCategory.java @@ -1,36 +1,16 @@ package com.simibubi.create.compat.jei.category; import com.simibubi.create.AllItems; -import com.simibubi.create.Create; -import com.simibubi.create.compat.jei.DoubleItemIcon; import com.simibubi.create.foundation.gui.ScreenElementRenderer; -import com.simibubi.create.foundation.utility.Lang; -import mezz.jei.api.gui.drawable.IDrawable; import net.minecraft.block.Blocks; -import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.crafting.SmokingRecipe; -import net.minecraft.util.ResourceLocation; public class SmokingViaFanCategory extends ProcessingViaFanCategory { - private static ResourceLocation ID = new ResourceLocation(Create.ID, "smoking_via_fan"); - private IDrawable icon; - public SmokingViaFanCategory() { - icon = new DoubleItemIcon(() -> new ItemStack(AllItems.PROPELLER.get()), - () -> new ItemStack(Items.BLAZE_POWDER)); - } - - @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return ID; + super("smoking_via_fan", doubleItemIcon(AllItems.PROPELLER.get(), Items.BLAZE_POWDER)); } @Override @@ -38,11 +18,6 @@ public class SmokingViaFanCategory extends ProcessingViaFanCategory Blocks.FIRE.getDefaultState()); diff --git a/src/main/java/com/simibubi/create/compat/jei/category/SplashingCategory.java b/src/main/java/com/simibubi/create/compat/jei/category/SplashingCategory.java index 7e3c559ae..9e2ed7923 100644 --- a/src/main/java/com/simibubi/create/compat/jei/category/SplashingCategory.java +++ b/src/main/java/com/simibubi/create/compat/jei/category/SplashingCategory.java @@ -5,52 +5,24 @@ import java.util.List; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllItems; -import com.simibubi.create.Create; import com.simibubi.create.ScreenResources; -import com.simibubi.create.compat.jei.CreateJEI; -import com.simibubi.create.compat.jei.DoubleItemIcon; -import com.simibubi.create.compat.jei.EmptyBackground; import com.simibubi.create.foundation.gui.ScreenElementRenderer; -import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.modules.contraptions.components.fan.SplashingRecipe; import com.simibubi.create.modules.contraptions.processing.ProcessingOutput; import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.gui.IRecipeLayout; -import mezz.jei.api.gui.drawable.IDrawable; import mezz.jei.api.gui.ingredient.IGuiItemStackGroup; import mezz.jei.api.ingredients.IIngredients; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.FlowingFluidBlock; -import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.util.ResourceLocation; public class SplashingCategory extends ProcessingViaFanCategory { - private static ResourceLocation ID = new ResourceLocation(Create.ID, "splashing"); - private IDrawable icon; - private IDrawable background = new EmptyBackground(177, 70); - public SplashingCategory() { - icon = new DoubleItemIcon(() -> new ItemStack(AllItems.PROPELLER.get()), - () -> new ItemStack(Items.WATER_BUCKET)); - } - - @Override - public IDrawable getBackground() { - return background; - } - - @Override - public IDrawable getIcon() { - return icon; - } - - @Override - public ResourceLocation getUid() { - return ID; + super("splashing", doubleItemIcon(AllItems.PROPELLER.get(), Items.WATER_BUCKET)); } @Override @@ -58,11 +30,6 @@ public class SplashingCategory extends ProcessingViaFanCategory return SplashingRecipe.class; } - @Override - public String getTitle() { - return Lang.translate("recipe.splashing"); - } - @Override public void setIngredients(SplashingRecipe recipe, IIngredients ingredients) { ingredients.setInputIngredients(recipe.getIngredients()); @@ -85,7 +52,7 @@ public class SplashingCategory extends ProcessingViaFanCategory itemStacks.set(outputIndex + 1, results.get(outputIndex).getStack()); } - CreateJEI.addStochasticTooltip(itemStacks, results); + addStochasticTooltip(itemStacks, results); } @Override @@ -97,14 +64,15 @@ public class SplashingCategory extends ProcessingViaFanCategory ScreenResources.JEI_SHADOW.draw(66, 39); ScreenResources.JEI_LONG_ARROW.draw(53, 51); - if (size > 1) { - for (int i = 0; i < size; i++) { - int xOffset = i % 2 == 0 ? 0 : 19; - int yOffset = (i / 2) * -19; - ScreenResources.JEI_SLOT.draw(133 + xOffset, 47 + yOffset); - } - } else { - ScreenResources.JEI_SLOT.draw(139, 47); + if (size == 1) { + getRenderedSlot(recipe, 0).draw(139, 47); + return; + } + + for (int i = 0; i < size; i++) { + int xOffset = i % 2 == 0 ? 0 : 19; + int yOffset = (i / 2) * -19; + getRenderedSlot(recipe, i).draw(133 + xOffset, 47 + yOffset); } } diff --git a/src/main/java/com/simibubi/create/config/CClient.java b/src/main/java/com/simibubi/create/config/CClient.java index 718a2b33d..9d8a451aa 100644 --- a/src/main/java/com/simibubi/create/config/CClient.java +++ b/src/main/java/com/simibubi/create/config/CClient.java @@ -12,6 +12,8 @@ public class CClient extends ConfigBase { public ConfigFloat fanParticleDensity = f(.5f, 0, 1, "fanParticleDensity"); public ConfigBool rainbowDebug = b(true, "enableRainbowDebug", "Show colourful debug information while the F3-Menu is open."); + public ConfigBool showHiddenSuperGlue = + b(false, "showHiddenSuperGlue", "Show indications for hidden glue between blocks while holding the item."); @Override public String getName() { diff --git a/src/main/java/com/simibubi/create/config/CDamageControl.java b/src/main/java/com/simibubi/create/config/CDamageControl.java index e62192518..5d542d203 100644 --- a/src/main/java/com/simibubi/create/config/CDamageControl.java +++ b/src/main/java/com/simibubi/create/config/CDamageControl.java @@ -5,9 +5,9 @@ public class CDamageControl extends ConfigBase { public ConfigBool freezeCrushing = b(false, "freezeCrushing", Comments.freezeCrushing); public ConfigBool freezeExtractors = b(false, "freezeExtractors", Comments.freezeExtractors); public ConfigBool freezeInWorldProcessing = b(false, "freezeInWorldProcessing", Comments.freezeInWorldProcessing); - public ConfigBool freezeRotationPropagator = b(false, "freezeRotationPropagator", Comments.freezeRotationPropagator); - public ConfigBool freezeBearingConstructs = b(false, "freezeBearingConstructs", Comments.freezeBearingConstructs); - public ConfigBool freezePistonConstructs = b(false, "freezePistonConstructs", Comments.freezePistonConstructs); + public ConfigBool freezeRotationPropagator = + b(false, "freezeRotationPropagator", Comments.freezeRotationPropagator); + public ConfigBool freezeContraptions = b(false, "freezeContraptions", Comments.freezeContraptions); @Override public String getName() { @@ -20,8 +20,7 @@ public class CDamageControl extends ConfigBase { static String freezeInWorldProcessing = "In case Encased Fans tried smelting your hardware."; static String freezeRotationPropagator = "Pauses rotation logic altogether - Use if crash mentions RotationPropagators."; - static String freezeBearingConstructs = "In case Mechanical Bearings turned against you."; - static String freezePistonConstructs = "In case Mechanical Pistons pushed it too far."; + static String freezeContraptions = "In case Moving contraptions pushed it too far."; } } diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/ValueBoxRenderer.java b/src/main/java/com/simibubi/create/foundation/behaviour/ValueBoxRenderer.java index 9be26177d..56c8ae779 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/ValueBoxRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/ValueBoxRenderer.java @@ -75,6 +75,8 @@ public class ValueBoxRenderer { } box.render(highlighted); + RenderSystem.disableBlend(); + RenderSystem.disableAlphaTest(); } public static void renderText(ValueBox box, FontRenderer font, String text) { diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/base/PosBoundSmartTileEntity.java b/src/main/java/com/simibubi/create/foundation/behaviour/base/PosBoundSmartTileEntity.java new file mode 100644 index 000000000..4bd838015 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/behaviour/base/PosBoundSmartTileEntity.java @@ -0,0 +1,59 @@ +package com.simibubi.create.foundation.behaviour.base; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.math.BlockPos; + +public abstract class PosBoundSmartTileEntity extends SmartTileEntity { + + private boolean newPositionVisited; + + public PosBoundSmartTileEntity(TileEntityType tileEntityTypeIn) { + super(tileEntityTypeIn); + newPositionVisited = true; + } + + @Override + public void initialize() { + if (!world.isRemote && newPositionVisited) { + newPositionVisited = false; + initInNewPosition(); + } + super.initialize(); + } + + @Override + public void read(CompoundNBT compound) { + long positionInTag = new BlockPos(compound.getInt("x"), compound.getInt("y"), compound.getInt("z")).toLong(); + long positionKey = compound.getLong("BoundPosition"); + + newPositionVisited = false; + if (!hasWorld() || !world.isRemote) { + if (positionInTag != positionKey) { + removePositionDependentData(compound); + newPositionVisited = true; + } + } + + super.read(compound); + } + + /** + * Server-only. When this TE realizes, that it's reading its tag in a different + * position, it should remove all position dependent information here. + * + * @param nbt + */ + protected void removePositionDependentData(CompoundNBT nbt) { + + } + + /** + * Server-only. When a TE has been created or moved, it will call this before the + * regular init. + */ + protected void initInNewPosition() { + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/base/SmartTileEntity.java b/src/main/java/com/simibubi/create/foundation/behaviour/base/SmartTileEntity.java index fd761ff30..5ce414b0e 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/base/SmartTileEntity.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/base/SmartTileEntity.java @@ -86,8 +86,9 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka list.forEach(b -> behaviours.put(b.getType(), b)); } - forEachBehaviour(tb -> tb.readNBT(compound)); super.read(compound); + forEachBehaviour(tb -> tb.readNBT(compound)); + if (world != null && world.isRemote) updateClient(compound); } @@ -106,7 +107,7 @@ public abstract class SmartTileEntity extends SyncedTileEntity implements ITicka public void lazyTick() { } - + protected void forEachBehaviour(Consumer action) { behaviours.values().forEach(tb -> { if (!tb.isPaused()) diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringBehaviour.java b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringBehaviour.java index 82fa386e5..901ff7c8e 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringBehaviour.java @@ -39,8 +39,7 @@ public class FilteringBehaviour extends TileEntityBehaviour { filter = ItemStack.EMPTY; slotPositioning = slot; showCount = false; - callback = stack -> { - }; + callback = stack -> {}; textShift = Vec3d.ZERO; count = 0; ticksUntilScrollPacket = -1; @@ -114,11 +113,7 @@ public class FilteringBehaviour extends TileEntityBehaviour { public void setFilter(ItemStack stack) { filter = stack.copy(); callback.accept(filter); - - if (filter.getItem() instanceof FilterItem) - count = 0; - else - count = stack.getCount(); + count = (filter.getItem() instanceof FilterItem) ? 0 : Math.min(stack.getCount(), stack.getMaxStackSize()); forceClientState = true; tileEntity.markDirty(); diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringHandler.java b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringHandler.java index 1fa219809..215f5355e 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringHandler.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/filtering/FilteringHandler.java @@ -87,12 +87,14 @@ public class FilteringHandler { return false; if (!filtering.testHit(objectMouseOver.getHitVec())) return false; - if (filtering.getFilter().isEmpty()) + ItemStack filterItem = filtering.getFilter(); + if (filterItem.isEmpty()) return false; filtering.ticksUntilScrollPacket = 10; - filtering.scrollableValue = (int) MathHelper - .clamp(filtering.scrollableValue + delta * (AllKeys.ctrlDown() ? 16 : 1), 0, 64); + int maxAmount = (filterItem.getItem() instanceof FilterItem) ? 64 : filterItem.getMaxStackSize(); + filtering.scrollableValue = + (int) MathHelper.clamp(filtering.scrollableValue + delta * (AllKeys.ctrlDown() ? 16 : 1), 0, maxAmount); return true; } diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/linked/LinkBehaviour.java b/src/main/java/com/simibubi/create/foundation/behaviour/linked/LinkBehaviour.java index 1a3310a6c..10677554e 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/linked/LinkBehaviour.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/linked/LinkBehaviour.java @@ -34,6 +34,7 @@ public class LinkBehaviour extends TileEntityBehaviour { ValueBoxTransform secondSlot; Vec3d textShift; + public boolean newPosition; private Mode mode; private Supplier transmission; private Consumer signalCallback; @@ -45,6 +46,7 @@ public class LinkBehaviour extends TileEntityBehaviour { firstSlot = slots.getLeft(); secondSlot = slots.getRight(); textShift = Vec3d.ZERO; + newPosition = true; } public static LinkBehaviour receiver(SmartTileEntity te, Pair slots, @@ -84,6 +86,8 @@ public class LinkBehaviour extends TileEntityBehaviour { } public void updateReceiver(boolean networkPowered) { + if (!newPosition) + return; signalCallback.accept(networkPowered); } @@ -97,6 +101,7 @@ public class LinkBehaviour extends TileEntityBehaviour { if (tileEntity.getWorld().isRemote) return; getHandler().addToNetwork(this); + newPosition = true; } public Pair getNetworkKey() { @@ -116,10 +121,15 @@ public class LinkBehaviour extends TileEntityBehaviour { super.writeNBT(compound); compound.put("FrequencyFirst", frequencyFirst.getStack().write(new CompoundNBT())); compound.put("FrequencyLast", frequencyLast.getStack().write(new CompoundNBT())); + compound.putLong("LastKnownPosition", tileEntity.getPos().toLong()); } @Override public void readNBT(CompoundNBT compound) { + long positionInTag = tileEntity.getPos().toLong(); + long positionKey = compound.getLong("LastKnownPosition"); + newPosition = positionInTag != positionKey; + super.readNBT(compound); frequencyFirst = new Frequency(ItemStack.read(compound.getCompound("FrequencyFirst"))); frequencyLast = new Frequency(ItemStack.read(compound.getCompound("FrequencyLast"))); diff --git a/src/main/java/com/simibubi/create/foundation/behaviour/scrollvalue/ScrollValueRenderer.java b/src/main/java/com/simibubi/create/foundation/behaviour/scrollvalue/ScrollValueRenderer.java index e8f5af13e..a98ed0e44 100644 --- a/src/main/java/com/simibubi/create/foundation/behaviour/scrollvalue/ScrollValueRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/behaviour/scrollvalue/ScrollValueRenderer.java @@ -1,5 +1,7 @@ package com.simibubi.create.foundation.behaviour.scrollvalue; +import com.mojang.blaze3d.platform.GlStateManager.DestFactor; +import com.mojang.blaze3d.platform.GlStateManager.SourceFactor; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; @@ -60,7 +62,10 @@ public class ScrollValueRenderer { } } else render(world, pos, face, behaviour, highlight); + TessellatorHelper.cleanUpAfterDrawing(); + RenderSystem.enableAlphaTest(); + RenderSystem.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA); } protected static void render(ClientWorld world, BlockPos pos, Direction face, ScrollValueBehaviour behaviour, diff --git a/src/main/java/com/simibubi/create/foundation/block/render/WrappedBakedModel.java b/src/main/java/com/simibubi/create/foundation/block/render/WrappedBakedModel.java index b2f38b2e9..8a2f84f63 100644 --- a/src/main/java/com/simibubi/create/foundation/block/render/WrappedBakedModel.java +++ b/src/main/java/com/simibubi/create/foundation/block/render/WrappedBakedModel.java @@ -3,12 +3,9 @@ package com.simibubi.create.foundation.block.render; import java.util.List; import java.util.Random; -import org.apache.commons.lang3.tuple.Pair; - import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.block.BlockState; -import net.minecraft.client.renderer.Matrix4f; import net.minecraft.client.renderer.model.BakedQuad; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; diff --git a/src/main/java/com/simibubi/create/foundation/gui/ScreenElementRenderer.java b/src/main/java/com/simibubi/create/foundation/gui/ScreenElementRenderer.java index 374cd726e..43cdbbeee 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/ScreenElementRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/gui/ScreenElementRenderer.java @@ -2,8 +2,6 @@ package com.simibubi.create.foundation.gui; import java.util.function.Supplier; -import org.lwjgl.opengl.GL11; - import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.platform.GlStateManager.DestFactor; import com.mojang.blaze3d.platform.GlStateManager.SourceFactor; @@ -16,15 +14,13 @@ import net.minecraft.block.Blocks; import net.minecraft.block.FireBlock; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BlockRendererDispatcher; -import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderTypeLookup; -import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.model.IBakedModel; +import net.minecraft.client.renderer.texture.AtlasTexture; import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -79,7 +75,7 @@ public class ScreenElementRenderer { boolean stateMode = transformsAndModel == null; boolean fire = false; - if (stateMode) { + if (transformsAndModel == null) { blockToRender = transformsAndState.get(); fire = (blockToRender.getBlock() instanceof FireBlock); modelToRender = blockRenderer.getModelForState(blockToRender); @@ -92,7 +88,8 @@ public class ScreenElementRenderer { RenderType renderType = RenderTypeLookup.getEntityBlockLayer(blockToRender); IVertexBuilder vb = buffer.getBuffer(renderType); MatrixStack ms = new MatrixStack(); - + mc.getTextureManager().bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE); + RenderSystem.pushMatrix(); if (fire) { blockRenderer.renderBlock(blockToRender, ms, buffer, 0xF000F0, OverlayTexture.DEFAULT_UV, @@ -111,7 +108,7 @@ public class ScreenElementRenderer { } RenderSystem.popMatrix(); - if (stateMode && !blockToRender.getFluidState().isEmpty()) { + if (blockToRender != null && !blockToRender.getFluidState().isEmpty()) { RenderHelper.disableStandardItemLighting(); RenderSystem.translatef(0, -300, 0); blockRenderer.renderFluid(new BlockPos(0, 300, 0), mc.world, vb, blockToRender.getFluidState()); diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingAngle.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingAngle.java new file mode 100644 index 000000000..3dc30905e --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingAngle.java @@ -0,0 +1,12 @@ +package com.simibubi.create.foundation.gui.widgets; + +import com.simibubi.create.foundation.utility.AngleHelper; + +public class InterpolatedChasingAngle extends InterpolatedChasingValue { + + @Override + protected float getCurrentDiff() { + return AngleHelper.getShortestAngleDiff(value, getTarget()); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingValue.java b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingValue.java index e18b5f6d4..92a3efe88 100644 --- a/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingValue.java +++ b/src/main/java/com/simibubi/create/foundation/gui/widgets/InterpolatedChasingValue.java @@ -7,11 +7,15 @@ public class InterpolatedChasingValue extends InterpolatedValue { float eps = 1 / 4096f; public void tick() { - float diff = target - value; + float diff = getCurrentDiff(); if (Math.abs(diff) < eps) return; set(value + (diff) * speed); } + + protected float getCurrentDiff() { + return getTarget() - value; + } public InterpolatedChasingValue withSpeed(float speed) { this.speed = speed; @@ -22,5 +26,15 @@ public class InterpolatedChasingValue extends InterpolatedValue { this.target = target; return this; } + + public InterpolatedChasingValue start(float value) { + lastValue = this.value = value; + target(value); + return this; + } + + public float getTarget() { + return target; + } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/AngleHelper.java b/src/main/java/com/simibubi/create/foundation/utility/AngleHelper.java index 058c23c1e..580c4d3cb 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/AngleHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/AngleHelper.java @@ -19,16 +19,16 @@ public class AngleHelper { public static float rad(float angle) { return (float) (angle / 180 * Math.PI); } - + public static float deg(float angle) { return (float) (angle * 180 / Math.PI); } - - public static float angleLerp(float pct, float current, float target) { + + public static float angleLerp(float pct, float current, float target) { return current + getShortestAngleDiff(current, target) * pct; } - public static float getShortestAngleDiff(double current, double target) { + public static float getShortestAngleDiff(double current, double target) { current = current % 360; target = target % 360; return (float) (((((target - current) % 360) + 540) % 360) - 180); diff --git a/src/main/java/com/simibubi/create/foundation/utility/DirectionHelper.java b/src/main/java/com/simibubi/create/foundation/utility/DirectionHelper.java index 6737e216a..e9bd8eea0 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/DirectionHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/DirectionHelper.java @@ -1,6 +1,11 @@ package com.simibubi.create.foundation.utility; -import static net.minecraft.util.Direction.*; +import static net.minecraft.util.Direction.DOWN; +import static net.minecraft.util.Direction.EAST; +import static net.minecraft.util.Direction.NORTH; +import static net.minecraft.util.Direction.SOUTH; +import static net.minecraft.util.Direction.UP; +import static net.minecraft.util.Direction.WEST; import net.minecraft.util.Direction; diff --git a/src/main/java/com/simibubi/create/foundation/utility/GlHelper.java b/src/main/java/com/simibubi/create/foundation/utility/GlHelper.java index 0f2562c53..b354555cd 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/GlHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/GlHelper.java @@ -1,5 +1,7 @@ package com.simibubi.create.foundation.utility; +import org.lwjgl.opengl.GL11; + import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.util.math.Vec3d; @@ -20,4 +22,14 @@ public class GlHelper { RenderSystem.popMatrix(); } + public static void enableTextureRepeat() { + RenderSystem.texParameter(GL11.GL_TEXTURE_2D, 10242, GL11.GL_REPEAT); + RenderSystem.texParameter(GL11.GL_TEXTURE_2D, 10243, GL11.GL_REPEAT); + } + + public static void disableTextureRepeat() { + RenderSystem.texParameter(GL11.GL_TEXTURE_2D, 10242, GL11.GL_CLAMP); + RenderSystem.texParameter(GL11.GL_TEXTURE_2D, 10243, GL11.GL_CLAMP); + } + } diff --git a/src/main/java/com/simibubi/create/foundation/utility/IndependentShadowRenderer.java b/src/main/java/com/simibubi/create/foundation/utility/IndependentShadowRenderer.java index df906964c..5f112388f 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/IndependentShadowRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/utility/IndependentShadowRenderer.java @@ -9,7 +9,6 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.entity.MobEntity; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; diff --git a/src/main/java/com/simibubi/create/foundation/utility/Iterate.java b/src/main/java/com/simibubi/create/foundation/utility/Iterate.java index da562aa42..86a15ee16 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/Iterate.java +++ b/src/main/java/com/simibubi/create/foundation/utility/Iterate.java @@ -10,6 +10,7 @@ import net.minecraft.util.math.BlockPos; public class Iterate { public static final boolean[] trueAndFalse = { true, false }; + public static final int[] zeroAndOne = { 1, -1 }; public static final int[] positiveAndNegative = { 1, -1 }; public static final Direction[] directions = Direction.values(); public static final Direction[] horizontalDirections = getHorizontals(); diff --git a/src/main/java/com/simibubi/create/foundation/utility/RayTraceWorld.java b/src/main/java/com/simibubi/create/foundation/utility/RayTraceWorld.java new file mode 100644 index 000000000..858da32eb --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/RayTraceWorld.java @@ -0,0 +1,37 @@ +package com.simibubi.create.foundation.utility; + +import java.util.function.BiFunction; + +import net.minecraft.block.BlockState; +import net.minecraft.fluid.IFluidState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorld; + +public class RayTraceWorld implements IBlockReader { + + private IWorld template; + private BiFunction stateGetter; + + public RayTraceWorld(IWorld template, BiFunction stateGetter) { + this.template = template; + this.stateGetter = stateGetter; + } + + @Override + public TileEntity getTileEntity(BlockPos pos) { + return template.getTileEntity(pos); + } + + @Override + public BlockState getBlockState(BlockPos pos) { + return stateGetter.apply(pos, template.getBlockState(pos)); + } + + @Override + public IFluidState getFluidState(BlockPos pos) { + return template.getFluidState(pos); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/RaycastHelper.java b/src/main/java/com/simibubi/create/foundation/utility/RaycastHelper.java index b856b79e3..803674f9a 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/RaycastHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/RaycastHelper.java @@ -22,13 +22,14 @@ public class RaycastHelper { return worldIn.rayTraceBlocks(context); } - public static PredicateTraceResult rayTraceUntil(PlayerEntity playerIn, double range, Predicate predicate) { + public static PredicateTraceResult rayTraceUntil(PlayerEntity playerIn, double range, + Predicate predicate) { Vec3d origin = getTraceOrigin(playerIn); Vec3d target = getTraceTarget(playerIn, range, origin); return rayTraceUntil(origin, target, predicate); } - private static Vec3d getTraceTarget(PlayerEntity playerIn, double range, Vec3d origin) { + public static Vec3d getTraceTarget(PlayerEntity playerIn, double range, Vec3d origin) { float f = playerIn.rotationPitch; float f1 = playerIn.rotationYaw; float f2 = MathHelper.cos(-f1 * 0.017453292F - (float) Math.PI); @@ -42,7 +43,7 @@ public class RaycastHelper { return vec3d1; } - private static Vec3d getTraceOrigin(PlayerEntity playerIn) { + public static Vec3d getTraceOrigin(PlayerEntity playerIn) { double d0 = playerIn.getX(); double d1 = playerIn.getY() + (double) playerIn.getEyeHeight(); double d2 = playerIn.getZ(); @@ -50,7 +51,7 @@ public class RaycastHelper { return vec3d; } - private static PredicateTraceResult rayTraceUntil(Vec3d start, Vec3d end, Predicate predicate) { + public static PredicateTraceResult rayTraceUntil(Vec3d start, Vec3d end, Predicate predicate) { if (Double.isNaN(start.x) || Double.isNaN(start.y) || Double.isNaN(start.z)) return null; if (Double.isNaN(end.x) || Double.isNaN(end.y) || Double.isNaN(end.z)) @@ -174,7 +175,7 @@ public class RaycastHelper { this.pos = pos; this.facing = facing; } - + public PredicateTraceResult() { // missed, no result } @@ -186,7 +187,7 @@ public class RaycastHelper { public BlockPos getPos() { return pos; } - + public boolean missed() { return this.pos == null; } diff --git a/src/main/java/com/simibubi/create/foundation/utility/SuperByteBuffer.java b/src/main/java/com/simibubi/create/foundation/utility/SuperByteBuffer.java index f2100d5a9..b0abacbe0 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/SuperByteBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/utility/SuperByteBuffer.java @@ -10,10 +10,10 @@ import com.simibubi.create.foundation.block.render.SpriteShiftEntry; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.BufferBuilder.DrawState; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.Matrix4f; import net.minecraft.client.renderer.Vector4f; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; diff --git a/src/main/java/com/simibubi/create/foundation/utility/TessellatorHelper.java b/src/main/java/com/simibubi/create/foundation/utility/TessellatorHelper.java index 0bf54a2ba..f0ab64546 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/TessellatorHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/TessellatorHelper.java @@ -27,9 +27,7 @@ public class TessellatorHelper { RenderSystem.pushMatrix(); RenderSystem.pushLightingAttributes(); RenderSystem.enableBlend(); - RenderSystem.enableAlphaTest(); RenderSystem.color4f(1, 1, 1, 1); - ActiveRenderInfo renderInfo = mc.gameRenderer.getActiveRenderInfo(); Vec3d view = renderInfo.getProjectedView(); RenderSystem.translated(-view.x, -view.y, -view.z); @@ -83,10 +81,9 @@ public class TessellatorHelper { } public static void cleanUpAfterDrawing() { - RenderSystem.disableAlphaTest(); - RenderSystem.disableBlend(); RenderSystem.popAttributes(); RenderSystem.popMatrix(); + RenderSystem.disableBlend(); } public static void drawString(String str, float x, float y, float z, boolean scalesUp, boolean hasDepth) { diff --git a/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java b/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java index 7635aa7bc..5849c8625 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java +++ b/src/main/java/com/simibubi/create/foundation/utility/TreeCutter.java @@ -1,6 +1,7 @@ package com.simibubi.create.foundation.utility; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -8,8 +9,16 @@ import java.util.Set; import com.google.common.base.Predicates; +import net.minecraft.block.BambooBlock; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.block.CactusBlock; +import net.minecraft.block.ChorusFlowerBlock; +import net.minecraft.block.ChorusPlantBlock; +import net.minecraft.block.KelpBlock; +import net.minecraft.block.KelpTopBlock; import net.minecraft.block.LeavesBlock; +import net.minecraft.block.SugarCaneBlock; import net.minecraft.tags.BlockTags; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; @@ -40,6 +49,41 @@ public class TreeCutter { Set visited = new HashSet<>(); List frontier = new LinkedList<>(); + // Bamboo, Sugar Cane, Cactus + BlockState stateAbove = reader.getBlockState(pos.up()); + if (isVerticalPlant(stateAbove)) { + logs.add(pos.up()); + for (int i = 1; i < 256; i++) { + BlockPos current = pos.up(i); + if (!isVerticalPlant(reader.getBlockState(current))) + break; + logs.add(current); + } + Collections.reverse(logs); + return new Tree(logs, leaves); + } + + // Chorus + if (isChorus(stateAbove)) { + frontier.add(pos.up()); + while (!frontier.isEmpty()) { + BlockPos current = frontier.remove(0); + visited.add(current); + logs.add(current); + for (Direction direction : Iterate.directions) { + BlockPos offset = current.offset(direction); + if (visited.contains(offset)) + continue; + if (!isChorus(reader.getBlockState(offset))) + continue; + frontier.add(offset); + } + } + Collections.reverse(logs); + return new Tree(logs, leaves); + } + + // Regular Tree if (!validateCut(reader, pos)) return null; @@ -94,6 +138,25 @@ public class TreeCutter { return new Tree(logs, leaves); } + public static boolean isChorus(BlockState stateAbove) { + return stateAbove.getBlock() instanceof ChorusPlantBlock || stateAbove.getBlock() instanceof ChorusFlowerBlock; + } + + public static boolean isVerticalPlant(BlockState stateAbove) { + Block block = stateAbove.getBlock(); + if (block instanceof BambooBlock) + return true; + if (block instanceof CactusBlock) + return true; + if (block instanceof SugarCaneBlock) + return true; + if (block instanceof KelpBlock) + return true; + if (block instanceof KelpTopBlock) + return true; + return false; + } + /** * Checks whether a tree was fully cut by seeing whether the layer above the cut * is not supported by any more logs. diff --git a/src/main/java/com/simibubi/create/foundation/utility/WrappedWorld.java b/src/main/java/com/simibubi/create/foundation/utility/WrappedWorld.java index 89029ea96..c4142811d 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/WrappedWorld.java +++ b/src/main/java/com/simibubi/create/foundation/utility/WrappedWorld.java @@ -2,6 +2,7 @@ package com.simibubi.create.foundation.utility; import java.util.Collections; import java.util.List; +import java.util.function.Predicate; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -11,6 +12,7 @@ import net.minecraft.fluid.Fluid; import net.minecraft.item.crafting.RecipeManager; import net.minecraft.scoreboard.Scoreboard; import net.minecraft.tags.NetworkTagManager; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.BlockPos; @@ -34,6 +36,26 @@ public class WrappedWorld extends World { return world; } + @Override + public BlockState getBlockState(BlockPos pos) { + return world.getBlockState(pos); + } + + @Override + public boolean hasBlockState(BlockPos p_217375_1_, Predicate p_217375_2_) { + return world.hasBlockState(p_217375_1_, p_217375_2_); + } + + @Override + public TileEntity getTileEntity(BlockPos pos) { + return world.getTileEntity(pos); + } + + @Override + public boolean setBlockState(BlockPos pos, BlockState newState, int flags) { + return world.setBlockState(pos, newState, flags); + } + @Override public int getLight(BlockPos pos) { return 15; @@ -55,8 +77,7 @@ public class WrappedWorld extends World { } @Override - public void playEvent(PlayerEntity player, int type, BlockPos pos, int data) { - } + public void playEvent(PlayerEntity player, int type, BlockPos pos, int data) {} @Override public List getPlayers() { @@ -65,13 +86,11 @@ public class WrappedWorld extends World { @Override public void playSound(PlayerEntity player, double x, double y, double z, SoundEvent soundIn, SoundCategory category, - float volume, float pitch) { - } + float volume, float pitch) {} @Override public void playMovingSound(PlayerEntity p_217384_1_, Entity p_217384_2_, SoundEvent p_217384_3_, - SoundCategory p_217384_4_, float p_217384_5_, float p_217384_6_) { - } + SoundCategory p_217384_4_, float p_217384_5_, float p_217384_6_) {} @Override public Entity getEntityByID(int id) { @@ -90,8 +109,7 @@ public class WrappedWorld extends World { } @Override - public void registerMapData(MapData mapDataIn) { - } + public void registerMapData(MapData mapDataIn) {} @Override public int getNextMapId() { @@ -99,8 +117,7 @@ public class WrappedWorld extends World { } @Override - public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) { - } + public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress) {} @Override public Scoreboard getScoreboard() { diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/AABBOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/AABBOutline.java new file mode 100644 index 000000000..e07f0cb79 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/AABBOutline.java @@ -0,0 +1,102 @@ +package com.simibubi.create.foundation.utility.outliner; + +import com.mojang.blaze3d.vertex.IVertexBuilder; +import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.foundation.utility.ColorHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.Vec3d; + +public class AABBOutline extends Outline { + + protected AxisAlignedBB bb; + protected AllSpecialTextures faceTexture; + protected AllSpecialTextures highlightedTexture; + protected Direction highlightedFace; + public boolean disableCull = false; + + public AABBOutline(AxisAlignedBB bb) { + this.bb = bb; + } + + @Override + public void render(BufferBuilder buffer) { + Vec3d color = ColorHelper.getRGB(0xFFFFFF); + float alpha = 1f; + renderBB(bb, buffer, color, alpha, !disableCull); + } + + public void setTextures(AllSpecialTextures faceTexture, AllSpecialTextures highlightTexture) { + this.faceTexture = faceTexture; + this.highlightedTexture = highlightTexture; + } + + public void highlightFace(Direction face) { + this.highlightedFace = face; + } + + public void renderBB(AxisAlignedBB bb, IVertexBuilder builder, Vec3d color, float alpha, boolean doCulling) { + Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView(); + boolean inside = bb.contains(projectedView); + bb = bb.grow(inside ? -1 / 128d : 1 / 128d); + + Vec3d xyz = new Vec3d(bb.minX, bb.minY, bb.minZ); + Vec3d Xyz = new Vec3d(bb.maxX, bb.minY, bb.minZ); + Vec3d xYz = new Vec3d(bb.minX, bb.maxY, bb.minZ); + Vec3d XYz = new Vec3d(bb.maxX, bb.maxY, bb.minZ); + Vec3d xyZ = new Vec3d(bb.minX, bb.minY, bb.maxZ); + Vec3d XyZ = new Vec3d(bb.maxX, bb.minY, bb.maxZ); + Vec3d xYZ = new Vec3d(bb.minX, bb.maxY, bb.maxZ); + Vec3d XYZ = new Vec3d(bb.maxX, bb.maxY, bb.maxZ); + + renderFace(Direction.NORTH, xYz, XYz, Xyz, xyz, builder); + renderFace(Direction.SOUTH, XYZ, xYZ, xyZ, XyZ, builder); + renderFace(Direction.EAST, XYz, XYZ, XyZ, Xyz, builder); + renderFace(Direction.WEST, xYZ, xYz, xyz, xyZ, builder); + renderFace(Direction.UP, xYZ, XYZ, XYz, xYz, builder); + renderFace(Direction.DOWN, xyz, Xyz, XyZ, xyZ, builder); + + Vec3d start = xyz; + AllSpecialTextures.BLANK.bind(); + renderAACuboidLine(start, Xyz, color, alpha, builder); + renderAACuboidLine(start, xYz, color, alpha, builder); + renderAACuboidLine(start, xyZ, color, alpha, builder); + + start = XyZ; + renderAACuboidLine(start, xyZ, color, alpha, builder); + renderAACuboidLine(start, XYZ, color, alpha, builder); + renderAACuboidLine(start, Xyz, color, alpha, builder); + + start = XYz; + renderAACuboidLine(start, xYz, color, alpha, builder); + renderAACuboidLine(start, Xyz, color, alpha, builder); + renderAACuboidLine(start, XYZ, color, alpha, builder); + + start = xYZ; + renderAACuboidLine(start, XYZ, color, alpha, builder); + renderAACuboidLine(start, xyZ, color, alpha, builder); + renderAACuboidLine(start, xYz, color, alpha, builder); + + } + + protected void renderFace(Direction direction, Vec3d p1, Vec3d p2, Vec3d p3, Vec3d p4, IVertexBuilder builder) { + if (direction == highlightedFace && highlightedTexture != null) + highlightedTexture.bind(); + else if (faceTexture != null) + faceTexture.bind(); + else + return; + + Vec3d uDiff = p2.subtract(p1); + Vec3d vDiff = p4.subtract(p1); + Axis axis = direction.getAxis(); + float maxU = (float) Math.abs(axis == Axis.X ? uDiff.z : uDiff.x); + float maxV = (float) Math.abs(axis == Axis.Y ? vDiff.z : vDiff.y); + putQuadUV(p1, p2, p3, p4, 0, 0, maxU, maxV, new Vec3d(1, 1, 1), 1, builder); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java new file mode 100644 index 000000000..93ec30de6 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/BlockClusterOutline.java @@ -0,0 +1,140 @@ +package com.simibubi.create.foundation.utility.outliner; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.foundation.utility.ColorHelper; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Direction.AxisDirection; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public class BlockClusterOutline extends Outline { + + private Cluster cluster; + private float alpha; + + public BlockClusterOutline(Iterable selection) { + cluster = new Cluster(); + selection.forEach(cluster::include); + alpha = .5f; + } + + @Override + public void render(BufferBuilder buffer) { + Vec3d color = ColorHelper.getRGB(0xDDDDDD); + AllSpecialTextures.SELECTION.bind(); + + for (MergeEntry face : cluster.visibleFaces.keySet()) { + AxisDirection axisDirection = cluster.visibleFaces.get(face); + Direction direction = Direction.getFacingFromAxis(axisDirection, face.axis); + BlockPos pos = face.pos; + if (axisDirection == AxisDirection.POSITIVE) + pos = pos.offset(direction.getOpposite()); + renderFace(pos, direction, color, alpha * .25f, 1 / 64d, buffer); + } + + AllSpecialTextures.BLANK.bind(); + + for (MergeEntry edge : cluster.visibleEdges) { + lineWidth = 1 / 16f * alpha; + Vec3d start = new Vec3d(edge.pos); + Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, edge.axis); + renderAACuboidLine(start, new Vec3d(edge.pos.offset(direction)), color, 1, buffer); + } + + } + + public void setAlpha(float alpha) { + this.alpha = alpha; + } + + private static class Cluster { + + Map visibleFaces; + Set visibleEdges; + + public Cluster() { + visibleEdges = new HashSet<>(); + visibleFaces = new HashMap<>(); + } + + public void include(BlockPos pos) { + + // 6 FACES + for (Axis axis : Axis.values()) { + Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis); + for (int offset : new int[] { 0, 1 }) { + MergeEntry entry = new MergeEntry(axis, pos.offset(direction, offset)); + if (visibleFaces.remove(entry) == null) + visibleFaces.put(entry, offset == 0 ? AxisDirection.NEGATIVE : AxisDirection.POSITIVE); + } + } + + // 12 EDGES + for (Axis axis : Axis.values()) { + for (Axis axis2 : Axis.values()) { + if (axis == axis2) + continue; + for (Axis axis3 : Axis.values()) { + if (axis == axis3) + continue; + if (axis2 == axis3) + continue; + + Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis2); + Direction direction2 = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis3); + + for (int offset : new int[] { 0, 1 }) { + BlockPos entryPos = pos.offset(direction, offset); + for (int offset2 : new int[] { 0, 1 }) { + entryPos = entryPos.offset(direction2, offset2); + MergeEntry entry = new MergeEntry(axis, entryPos); + if (!visibleEdges.remove(entry)) + visibleEdges.add(entry); + } + } + } + + break; + } + } + + } + + } + + private static class MergeEntry { + + Axis axis; + BlockPos pos; + + public MergeEntry(Axis axis, BlockPos pos) { + this.axis = axis; + this.pos = pos; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof MergeEntry)) + return false; + + MergeEntry other = (MergeEntry) o; + return this.axis == other.axis && this.pos.equals(other.pos); + } + + @Override + public int hashCode() { + return this.pos.hashCode() * 31 + axis.ordinal(); + } + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java new file mode 100644 index 000000000..750bca759 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/ChasingAABBOutline.java @@ -0,0 +1,46 @@ +package com.simibubi.create.foundation.utility.outliner; + +import com.simibubi.create.foundation.utility.ColorHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +public class ChasingAABBOutline extends AABBOutline { + + AxisAlignedBB targetBB; + AxisAlignedBB prevBB; + + public ChasingAABBOutline(AxisAlignedBB bb) { + super(bb); + prevBB = bb.grow(0); + targetBB = bb.grow(0); + } + + public void target(AxisAlignedBB target) { + targetBB = target; + } + + public void tick() { + prevBB = bb; + bb = interpolateBBs(bb, targetBB, .5f); + } + + @Override + public void render(BufferBuilder buffer) { + Vec3d color = ColorHelper.getRGB(0xFFFFFF); + float alpha = 1f; + renderBB(interpolateBBs(prevBB, bb, Minecraft.getInstance().getRenderPartialTicks()), buffer, color, alpha, + true); + } + + private static AxisAlignedBB interpolateBBs(AxisAlignedBB current, AxisAlignedBB target, float pt) { + return new AxisAlignedBB(MathHelper.lerp(pt, current.minX, target.minX), + MathHelper.lerp(pt, current.minY, target.minY), MathHelper.lerp(pt, current.minZ, target.minZ), + MathHelper.lerp(pt, current.maxX, target.maxX), MathHelper.lerp(pt, current.maxY, target.maxY), + MathHelper.lerp(pt, current.maxZ, target.maxZ)); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java new file mode 100644 index 000000000..8237582a6 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/Outline.java @@ -0,0 +1,97 @@ +package com.simibubi.create.foundation.utility.outliner; + +import com.mojang.blaze3d.vertex.IVertexBuilder; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; + +public abstract class Outline { + + protected float lineWidth = 1 / 32f; + + public abstract void render(BufferBuilder buffer); + + public void renderAACuboidLine(Vec3d start, Vec3d end, Vec3d rgb, float alpha, IVertexBuilder builder) { + Vec3d diff = end.subtract(start); + if (diff.x + diff.y + diff.z < 0) { + Vec3d temp = start; + start = end; + end = temp; + diff = diff.scale(-1); + } + + Vec3d extension = diff.normalize().scale(lineWidth / 2); + Vec3d plane = VecHelper.planeByNormal(diff); + Axis axis = Direction.getFacingFromVector(diff.x, diff.y, diff.z).getAxis(); + + start = start.subtract(extension); + end = end.add(extension); + plane = plane.scale(lineWidth / 2); + Vec3d a1 = plane.add(start); + Vec3d b1 = plane.add(end); + plane = VecHelper.rotate(plane, -90, axis); + Vec3d a2 = plane.add(start); + Vec3d b2 = plane.add(end); + plane = VecHelper.rotate(plane, -90, axis); + Vec3d a3 = plane.add(start); + Vec3d b3 = plane.add(end); + plane = VecHelper.rotate(plane, -90, axis); + Vec3d a4 = plane.add(start); + Vec3d b4 = plane.add(end); + + putQuad(b4, b3, b2, b1, rgb, alpha, builder); + putQuad(a1, a2, a3, a4, rgb, alpha, builder); + + putQuad(a1, b1, b2, a2, rgb, alpha, builder); + putQuad(a2, b2, b3, a3, rgb, alpha, builder); + putQuad(a3, b3, b4, a4, rgb, alpha, builder); + putQuad(a4, b4, b1, a1, rgb, alpha, builder); + } + + protected void renderFace(BlockPos pos, Direction face, Vec3d rgb, float alpha, double scaleOffset, + IVertexBuilder builder) { + Vec3d center = VecHelper.getCenterOf(pos); + Vec3d offset = new Vec3d(face.getDirectionVec()); + Vec3d plane = VecHelper.planeByNormal(offset); + Axis axis = face.getAxis(); + + offset = offset.scale(1 / 2f + scaleOffset); + plane = plane.scale(1 / 2f).add(offset); + + int deg = face.getAxisDirection().getOffset() * 90; + Vec3d a1 = plane.add(center); + plane = VecHelper.rotate(plane, deg, axis); + Vec3d a2 = plane.add(center); + plane = VecHelper.rotate(plane, deg, axis); + Vec3d a3 = plane.add(center); + plane = VecHelper.rotate(plane, deg, axis); + Vec3d a4 = plane.add(center); + + putQuad(a1, a2, a3, a4, rgb, alpha, builder); + } + + public void putQuad(Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4, Vec3d rgb, float alpha, IVertexBuilder builder) { + putQuadUV(v1, v2, v3, v4, 0, 0, 1, 1, rgb, alpha, builder); + } + + public void putQuadUV(Vec3d v1, Vec3d v2, Vec3d v3, Vec3d v4, float minU, float minV, float maxU, float maxV, + Vec3d rgb, float alpha, IVertexBuilder builder) { + putVertex(v1, rgb, minU, minV, alpha, builder); + putVertex(v2, rgb, maxU, minV, alpha, builder); + putVertex(v3, rgb, maxU, maxV, alpha, builder); + putVertex(v4, rgb, minU, maxV, alpha, builder); + } + + protected void putVertex(Vec3d pos, Vec3d rgb, float u, float v, float alpha, IVertexBuilder builder) { + int i = 15 << 20 | 15 << 4; + int j = i >> 16 & '\uffff'; + int k = i & '\uffff'; + builder.vertex(pos.x, pos.y, pos.z).texture(u, v).color((float) rgb.x, (float) rgb.y, (float) rgb.z, alpha) + .light(j, k).endVertex(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/outliner/OutlineParticle.java b/src/main/java/com/simibubi/create/foundation/utility/outliner/OutlineParticle.java new file mode 100644 index 000000000..024284a3f --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/outliner/OutlineParticle.java @@ -0,0 +1,55 @@ +package com.simibubi.create.foundation.utility.outliner; + +import com.mojang.blaze3d.vertex.IVertexBuilder; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.particle.IParticleRenderType; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.renderer.ActiveRenderInfo; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class OutlineParticle extends Particle { + + protected O outline; + + protected OutlineParticle(O outline, World worldIn, double xCoordIn, double yCoordIn, double zCoordIn) { + super(worldIn, xCoordIn, yCoordIn, zCoordIn); + this.outline = outline; + this.maxAge = 1024; + } + + public static OutlineParticle create(O outline) { + Minecraft mc = Minecraft.getInstance(); + ClientPlayerEntity player = mc.player; + OutlineParticle effect = + new OutlineParticle<>(outline, mc.world, player.getX(), player.getY(), player.getZ()); + mc.particles.addEffect(effect); + return effect; + } + + public void remove() { + isExpired = true; + } + + @Override + public void buildGeometry(IVertexBuilder builder, ActiveRenderInfo renderInfo, float p_225606_3_) { + Vec3d view = renderInfo.getProjectedView(); +// GlStateManager.translated(-view.x, -view.y, -view.z); +// TODO +// GlStateManager.enableBlend(); +// getOutline().render(buffer); +// GlStateManager.disableBlend(); + } + + @Override + public IParticleRenderType getRenderType() { + return IParticleRenderType.CUSTOM; + } + + public O getOutline() { + return outline; + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/render/StructureRenderer.java b/src/main/java/com/simibubi/create/foundation/utility/render/StructureRenderer.java new file mode 100644 index 000000000..dd26d6b16 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/utility/render/StructureRenderer.java @@ -0,0 +1,111 @@ +package com.simibubi.create.foundation.utility.render; + +import java.util.Iterator; + +import org.lwjgl.opengl.GL13; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.Create; +import com.simibubi.create.config.AllConfigs; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.WrappedWorld; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; +import net.minecraft.crash.ReportedException; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class StructureRenderer { + + protected static LightingWorld lightingWorld; + + public static void renderTileEntities(World world, Vec3d position, Vec3d rotation, + Iterable customRenderTEs, MatrixStack ms, IRenderTypeBuffer buffer) { + float pt = Minecraft.getInstance().getRenderPartialTicks(); + + if (lightingWorld == null) + lightingWorld = new LightingWorld(world); + lightingWorld.setWorld(world); + lightingWorld.setTransform(position, rotation); + + for (Iterator iterator = customRenderTEs.iterator(); iterator.hasNext();) { + TileEntity tileEntity = iterator.next(); + if (TileEntityRendererDispatcher.instance.getRenderer(tileEntity) == null) { + iterator.remove(); + continue; + } + + try { + + BlockPos pos = tileEntity.getPos(); + if (!tileEntity.hasFastRenderer()) { + RenderHelper.enable(); + int i = WorldRenderer.getLightmapCoordinates(lightingWorld, pos); + int j = LightTexture.getBlockLightCoordinates(i); + int k = LightTexture.getSkyLightCoordinates(i); + RenderSystem.glMultiTexCoord2f(GL13.GL_TEXTURE1, (float) j, (float) k); + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + } + + RenderSystem.disableCull(); + World prevTileWorld = tileEntity.getWorld(); + tileEntity.setLocation(lightingWorld, pos); + TileEntityRendererDispatcher.instance.render(tileEntity, pt, ms, buffer); + tileEntity.setLocation(prevTileWorld, pos); + RenderSystem.enableCull(); + + } catch (ReportedException e) { + if (AllConfigs.CLIENT.explainRenderErrors.get()) { + Create.logger.error("TileEntity " + tileEntity.getType().getRegistryName().toString() + + " didn't want to render while moved.\n", e); + } else { + Create.logger.error("TileEntity " + tileEntity.getType().getRegistryName().toString() + + " didn't want to render while moved.\n"); + } + iterator.remove(); + continue; + } + } + } + + private static class LightingWorld extends WrappedWorld { + + private Vec3d offset; + private Vec3d rotation; + + public LightingWorld(World world) { + super(world); + } + + void setWorld(World world) { + this.world = world; + } + + void setTransform(Vec3d offset, Vec3d rotation) { + this.offset = offset; + this.rotation = rotation; + } + + @Override + public int getBaseLightLevel(BlockPos pos, int minLight) { + return super.getBaseLightLevel(transformPos(pos), minLight); + } + + private BlockPos transformPos(BlockPos pos) { + Vec3d vec = VecHelper.getCenterOf(pos); + vec = VecHelper.rotate(vec, rotation.x, rotation.y, rotation.z); + vec = vec.add(offset).subtract(VecHelper.getCenterOf(BlockPos.ZERO)); + return new BlockPos(vec); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/world/OreFeature.java b/src/main/java/com/simibubi/create/foundation/world/OreFeature.java index 6150b6a81..fac3d0757 100644 --- a/src/main/java/com/simibubi/create/foundation/world/OreFeature.java +++ b/src/main/java/com/simibubi/create/foundation/world/OreFeature.java @@ -1,9 +1,6 @@ package com.simibubi.create.foundation.world; import java.util.Optional; -import java.util.function.Supplier; - -import javax.annotation.Nonnull; import org.apache.commons.lang3.tuple.Pair; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/WrenchItemRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/WrenchItemRenderer.java index ee4e86e91..5aa3b2276 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/WrenchItemRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/WrenchItemRenderer.java @@ -1,7 +1,6 @@ package com.simibubi.create.modules.contraptions; import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.client.Minecraft; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/base/KineticBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/base/KineticBlock.java index 0b5932aae..31a669183 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/base/KineticBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/base/KineticBlock.java @@ -1,7 +1,6 @@ package com.simibubi.create.modules.contraptions.base; import com.simibubi.create.foundation.item.ItemDescription.Palette; -import com.simibubi.create.modules.contraptions.RotationPropagator; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -45,7 +44,10 @@ public abstract class KineticBlock extends Block implements IRotate { return tool == ToolType.AXE || tool == ToolType.PICKAXE; } - // IRotate + @Override + public void onBlockAdded(BlockState state, World worldIn, BlockPos pos, BlockState oldState, boolean isMoving) { + // onBlockAdded is useless for init, as sometimes the TE gets re-instantiated + } @Override public boolean hasShaftTowards(IWorldReader world, BlockPos pos, BlockState state, Direction face) { @@ -57,8 +59,6 @@ public abstract class KineticBlock extends Block implements IRotate { return false; } - // Block - @Override public boolean hasTileEntity(BlockState state) { return true; @@ -72,8 +72,8 @@ public abstract class KineticBlock extends Block implements IRotate { @Override public abstract TileEntity createTileEntity(BlockState state, IBlockReader world); - @SuppressWarnings("deprecation") @Override + @SuppressWarnings("deprecation") public void updateNeighbors(BlockState stateIn, IWorld worldIn, BlockPos pos, int flags) { super.updateNeighbors(stateIn, worldIn, pos, flags); if (worldIn.isRemote()) @@ -83,8 +83,11 @@ public abstract class KineticBlock extends Block implements IRotate { if (!(tileEntity instanceof KineticTileEntity)) return; + // Remove previous information when block is added KineticTileEntity kte = (KineticTileEntity) tileEntity; - RotationPropagator.handleAdded(worldIn.getWorld(), pos, kte); + kte.warnOfMovement(); + kte.clearKineticInformation(); + kte.updateSpeed = true; } // @Override // TODO 1.15 register layer diff --git a/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java index de3df92b2..21b8f0e60 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/base/KineticTileEntity.java @@ -41,12 +41,14 @@ public abstract class KineticTileEntity extends SmartTileEntity public @Nullable Long network; public @Nullable BlockPos source; public boolean networkDirty; + public boolean updateSpeed; protected KineticEffectHandler effects; protected float speed; protected float capacity; protected float stress; protected boolean overStressed; + protected boolean wasMoved; private int flickerTally; private int networkSize; @@ -57,6 +59,7 @@ public abstract class KineticTileEntity extends SmartTileEntity public KineticTileEntity(TileEntityType typeIn) { super(typeIn); effects = new KineticEffectHandler(this); + updateSpeed = true; } @Override @@ -73,6 +76,9 @@ public abstract class KineticTileEntity extends SmartTileEntity @Override public void tick() { + if (!world.isRemote && needsSpeedUpdate()) + attachKinetics(); + super.tick(); effects.tick(); @@ -179,6 +185,9 @@ public abstract class KineticTileEntity extends SmartTileEntity public CompoundNBT write(CompoundNBT compound) { compound.putFloat("Speed", speed); + if (needsSpeedUpdate()) + compound.putBoolean("NeedsSpeedUpdate", true); + if (hasSource()) compound.put("Source", NBTUtil.writeBlockPos(source)); @@ -188,7 +197,7 @@ public abstract class KineticTileEntity extends SmartTileEntity networkTag.putFloat("Stress", stress); networkTag.putFloat("Capacity", capacity); networkTag.putInt("Size", networkSize); - + if (lastStressApplied != 0) networkTag.putFloat("AddedStress", lastStressApplied); if (lastCapacityProvided != 0) @@ -200,16 +209,21 @@ public abstract class KineticTileEntity extends SmartTileEntity return super.write(compound); } + public boolean needsSpeedUpdate() { + return updateSpeed; + } + @Override public void read(CompoundNBT compound) { + clearKineticInformation(); + + // DO NOT READ kinetic information when placed after movement + if (wasMoved) { + super.read(compound); + return; + } + speed = compound.getFloat("Speed"); - source = null; - network = null; - overStressed = false; - stress = 0; - capacity = 0; - lastStressApplied = 0; - lastCapacityProvided = 0; if (compound.contains("Source")) source = NBTUtil.readBlockPos(compound.getCompound("Source")); @@ -313,6 +327,7 @@ public abstract class KineticTileEntity extends SmartTileEntity } public void attachKinetics() { + updateSpeed = false; RotationPropagator.handleAdded(world, pos, this); } @@ -414,6 +429,21 @@ public abstract class KineticTileEntity extends SmartTileEntity } + public void clearKineticInformation() { + speed = 0; + source = null; + network = null; + overStressed = false; + stress = 0; + capacity = 0; + lastStressApplied = 0; + lastCapacityProvided = 0; + } + + public void warnOfMovement() { + wasMoved = true; + } + public int getFlickerScore() { return flickerTally; } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/AttachedActorBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/AttachedActorBlock.java new file mode 100644 index 000000000..c738f69b1 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/AttachedActorBlock.java @@ -0,0 +1,60 @@ +package com.simibubi.create.modules.contraptions.components.actors; + +import com.simibubi.create.foundation.utility.AllShapes; +import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.HorizontalBlock; +import net.minecraft.item.BlockItemUseContext; +import net.minecraft.state.StateContainer.Builder; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.shapes.ISelectionContext; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorldReader; + +public abstract class AttachedActorBlock extends HorizontalBlock implements IPortableBlock { + + public AttachedActorBlock() { + super(Properties.from(Blocks.IRON_BLOCK)); + } + + @Override + public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { + Direction direction = state.get(HORIZONTAL_FACING); + return AllShapes.HARVESTER_BASE.get(direction); + } + + @Override + protected void fillStateContainer(Builder builder) { + builder.add(HORIZONTAL_FACING); + super.fillStateContainer(builder); + } + + @Override + public boolean isValidPosition(BlockState state, IWorldReader worldIn, BlockPos pos) { + Direction direction = state.get(HORIZONTAL_FACING); + BlockPos offset = pos.offset(direction.getOpposite()); + return Block.hasSolidSide(worldIn.getBlockState(offset), worldIn, offset, direction); + } + + @Override + public BlockState getStateForPlacement(BlockItemUseContext context) { + Direction facing; + if (context.getFace().getAxis().isVertical()) + facing = context.getPlacementHorizontalFacing().getOpposite(); + else { + BlockState blockState = + context.getWorld().getBlockState(context.getPos().offset(context.getFace().getOpposite())); + if (blockState.getBlock() instanceof AttachedActorBlock) + facing = blockState.get(HORIZONTAL_FACING); + else + facing = context.getFace(); + } + return getDefaultState().with(HORIZONTAL_FACING, facing); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/BlockBreakingMovementBehaviour.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/BlockBreakingMovementBehaviour.java index c7c2ef8af..cfaa5a87f 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/BlockBreakingMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/BlockBreakingMovementBehaviour.java @@ -6,9 +6,11 @@ import com.simibubi.create.modules.contraptions.components.contraptions.Movement import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext; import net.minecraft.block.BlockState; +import net.minecraft.block.FallingBlock; import net.minecraft.entity.Entity; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.NBTUtil; import net.minecraft.util.DamageSource; @@ -32,30 +34,10 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { World world = context.world; BlockState stateVisited = world.getBlockState(pos); + if (!stateVisited.isNormalCube(world, pos)) + damageEntities(context, pos, world); if (world.isRemote) return; - if (stateVisited.getCollisionShape(world, pos).isEmpty()) { - DamageSource damageSource = getDamageSource(); - if (damageSource == null) - return; - for (Entity entity : world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(pos))) { - - if (entity instanceof ItemEntity) - return; - if (entity instanceof ContraptionEntity) - return; - if (entity instanceof AbstractMinecartEntity) - for (Entity passenger : entity.getRecursivePassengers()) - if (passenger instanceof ContraptionEntity - && ((ContraptionEntity) passenger).getContraption() == context.contraption) - return; - - float damage = (float) MathHelper.clamp(Math.abs(context.relativeMotion.length() * 10) + 1, 5, 20); - entity.attackEntityFrom(damageSource, damage); - entity.setMotion(entity.getMotion().add(context.relativeMotion.scale(3))); - } - return; - } if (!canBreak(world, pos, stateVisited)) return; @@ -63,10 +45,44 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { context.stall = true; } + public void damageEntities(MovementContext context, BlockPos pos, World world) { + DamageSource damageSource = getDamageSource(); + if (damageSource == null && !throwsEntities()) + return; + Entities: for (Entity entity : world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(pos))) { + if (entity instanceof ItemEntity) + continue; + if (entity instanceof ContraptionEntity) + continue; + if (entity instanceof AbstractMinecartEntity) + for (Entity passenger : entity.getRecursivePassengers()) + if (passenger instanceof ContraptionEntity + && ((ContraptionEntity) passenger).getContraption() == context.contraption) + continue Entities; + + float damage = (float) MathHelper.clamp(Math.abs(context.relativeMotion.length() * 10) + 1, 5, 20); + if (damageSource != null && !world.isRemote) + entity.attackEntityFrom(damageSource, damage); + if (throwsEntities() && (world.isRemote == (entity instanceof PlayerEntity))) { + Vec3d motionBoost = context.motion.add(0, context.motion.length() / 4f, 0); + int maxBoost = 4; + if (motionBoost.length() > maxBoost) { + motionBoost = motionBoost.subtract(motionBoost.normalize().scale(motionBoost.length() - maxBoost)); + } + entity.setMotion(entity.getMotion().add(motionBoost)); + entity.velocityChanged = true; + } + } + } + protected DamageSource getDamageSource() { return null; } + protected boolean throwsEntities() { + return getDamageSource() != null; + } + @Override public void stopMoving(MovementContext context) { CompoundNBT data = context.data; @@ -89,6 +105,27 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { @Override public void tick(MovementContext context) { + tickBreaker(context); + + CompoundNBT data = context.data; + if (!data.contains("WaitingTicks")) + return; + + int waitingTicks = data.getInt("WaitingTicks"); + if (waitingTicks-- > 0) { + data.putInt("WaitingTicks", waitingTicks); + context.stall = true; + return; + } + + BlockPos pos = NBTUtil.readBlockPos(data.getCompound("LastPos")); + data.remove("WaitingTicks"); + data.remove("LastPos"); + context.stall = false; + visitNewPosition(context, pos); + } + + public void tickBreaker(MovementContext context) { CompoundNBT data = context.data; if (context.world.isRemote) return; @@ -128,14 +165,24 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { destroyProgress += MathHelper.clamp((int) (breakSpeed / blockHardness), 1, 10 - destroyProgress); if (destroyProgress >= 10) { - BlockHelper.destroyBlock(context.world, breakingPos, 1f, stack -> this.dropItem(context, stack)); - onBlockBroken(context, breakingPos); - ticksUntilNextProgress = -1; world.sendBlockBreakProgress(id, breakingPos, -1); + + // break falling blocks from top to bottom + BlockPos ogPos = breakingPos; + BlockState stateAbove = world.getBlockState(breakingPos.up()); + while (stateAbove.getBlock() instanceof FallingBlock) { + breakingPos = breakingPos.up(); + stateAbove = world.getBlockState(breakingPos.up()); + } + stateToBreak = world.getBlockState(breakingPos); + + context.stall = false; + BlockHelper.destroyBlock(context.world, breakingPos, 1f, stack -> this.dropItem(context, stack)); + onBlockBroken(context, ogPos, stateToBreak); + ticksUntilNextProgress = -1; data.remove("Progress"); data.remove("TicksUntilNextProgress"); data.remove("BreakingPos"); - context.stall = false; return; } @@ -150,7 +197,15 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { return BlockBreakingKineticTileEntity.isBreakable(state, blockHardness); } - protected void onBlockBroken(MovementContext context, BlockPos pos) { + protected void onBlockBroken(MovementContext context, BlockPos pos, BlockState brokenState) { + // Check for falling blocks + if (!(brokenState.getBlock() instanceof FallingBlock)) + return; + + CompoundNBT data = context.data; + data.putInt("WaitingTicks", 10); + data.put("LastPos", NBTUtil.writeBlockPos(pos)); + context.stall = true; } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/DrillMovementBehaviour.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/DrillMovementBehaviour.java index 9fdc5a399..be4ff48b1 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/DrillMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/DrillMovementBehaviour.java @@ -4,8 +4,11 @@ import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext; +import net.minecraft.block.BlockState; import net.minecraft.util.DamageSource; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -27,10 +30,15 @@ public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour { public SuperByteBuffer renderInContraption(MovementContext context) { return DrillTileEntityRenderer.renderInContraption(context); } - + @Override protected DamageSource getDamageSource() { return DrillBlock.damageSourceDrill; } + @Override + public boolean canBreak(World world, BlockPos breakingPos, BlockState state) { + return super.canBreak(world, breakingPos, state) && !state.getCollisionShape(world, breakingPos).isEmpty(); + } + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterBlock.java index 65a7f0473..9680be1f3 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterBlock.java @@ -1,33 +1,16 @@ package com.simibubi.create.modules.contraptions.components.actors; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.foundation.utility.AllShapes; import com.simibubi.create.modules.contraptions.components.contraptions.IPortableBlock; import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour; -import net.minecraft.block.Block; import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.block.HorizontalBlock; -import net.minecraft.block.material.PushReaction; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.state.StateContainer.Builder; import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.shapes.ISelectionContext; -import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; -import net.minecraft.world.IWorldReader; -public class HarvesterBlock extends HorizontalBlock implements IPortableBlock { +public class HarvesterBlock extends AttachedActorBlock implements IPortableBlock { public static MovementBehaviour MOVEMENT = new HarvesterMovementBehaviour(); - public HarvesterBlock() { - super(Properties.from(Blocks.IRON_BLOCK)); - } - @Override public boolean hasTileEntity(BlockState state) { return true; @@ -38,51 +21,11 @@ public class HarvesterBlock extends HorizontalBlock implements IPortableBlock { return new HarvesterTileEntity(); } - @Override - public PushReaction getPushReaction(BlockState state) { - return PushReaction.PUSH_ONLY; - } - - @Override - public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) { - Direction direction = state.get(HORIZONTAL_FACING); - return AllShapes.HARVESTER_BASE.get(direction); - } - - @Override - protected void fillStateContainer(Builder builder) { - builder.add(HORIZONTAL_FACING); - super.fillStateContainer(builder); - } - // @Override // TOOD 1.15 register layer // public BlockRenderLayer getRenderLayer() { // return BlockRenderLayer.CUTOUT; // } - @Override - public boolean isValidPosition(BlockState state, IWorldReader worldIn, BlockPos pos) { - Direction direction = state.get(HORIZONTAL_FACING); - BlockPos offset = pos.offset(direction.getOpposite()); - return Block.hasSolidSide(worldIn.getBlockState(offset), worldIn, offset, direction); - } - - @Override - public BlockState getStateForPlacement(BlockItemUseContext context) { - Direction facing; - if (context.getFace().getAxis().isVertical()) - facing = context.getPlacementHorizontalFacing().getOpposite(); - else { - BlockState blockState = - context.getWorld().getBlockState(context.getPos().offset(context.getFace().getOpposite())); - if (AllBlocks.HARVESTER.typeOf(blockState)) - facing = blockState.get(HORIZONTAL_FACING); - else - facing = context.getFace(); - } - return getDefaultState().with(HORIZONTAL_FACING, facing); - } - @Override public MovementBehaviour getMovementBehaviour() { return MOVEMENT; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterMovementBehaviour.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterMovementBehaviour.java index 2f3bfe2b0..83a8548b4 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/HarvesterMovementBehaviour.java @@ -42,7 +42,7 @@ public class HarvesterMovementBehaviour extends MovementBehaviour { @Override public Vec3d getActiveAreaOffset(MovementContext context) { - return new Vec3d(context.state.get(HORIZONTAL_FACING).getDirectionVec()).scale(.5); + return new Vec3d(context.state.get(HORIZONTAL_FACING).getDirectionVec()).scale(.45); } @Override diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughBlock.java new file mode 100644 index 000000000..9c263de6c --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughBlock.java @@ -0,0 +1,34 @@ +package com.simibubi.create.modules.contraptions.components.actors; + +import java.util.UUID; + +import com.mojang.authlib.GameProfile; +import com.simibubi.create.modules.contraptions.components.contraptions.MovementBehaviour; + +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.util.FakePlayer; + +public class PloughBlock extends AttachedActorBlock { + + public static MovementBehaviour MOVEMENT = new PloughMovementBehaviour(); + + @Override + public MovementBehaviour getMovementBehaviour() { + return MOVEMENT; + } + + /** + * The OnHoeUse event takes a player, so we better not pass null + */ + static class PloughFakePlayer extends FakePlayer { + + public static final GameProfile PLOUGH_PROFILE = + new GameProfile(UUID.fromString("9e2faded-eeee-4ec2-c314-dad129ae971d"), "Plough"); + + public PloughFakePlayer(ServerWorld world) { + super(world, PLOUGH_PROFILE); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughMovementBehaviour.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughMovementBehaviour.java new file mode 100644 index 000000000..12fd4ea93 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/PloughMovementBehaviour.java @@ -0,0 +1,88 @@ +package com.simibubi.create.modules.contraptions.components.actors; + +import static net.minecraft.block.HorizontalBlock.HORIZONTAL_FACING; + +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.modules.contraptions.components.actors.PloughBlock.PloughFakePlayer; +import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext; + +import net.minecraft.block.BlockState; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; +import net.minecraft.item.Items; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.RayTraceContext.BlockMode; +import net.minecraft.util.math.RayTraceContext.FluidMode; +import net.minecraft.util.math.RayTraceResult.Type; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; + +public class PloughMovementBehaviour extends BlockBreakingMovementBehaviour { + + @Override + public boolean isActive(MovementContext context) { + return !VecHelper.isVecPointingTowards(context.relativeMotion, + context.state.get(HORIZONTAL_FACING).getOpposite()); + } + + @Override + public void visitNewPosition(MovementContext context, BlockPos pos) { + super.visitNewPosition(context, pos); + World world = context.world; + if (world.isRemote) + return; + BlockPos below = pos.down(); + if (!world.isBlockPresent(below)) + return; + + Vec3d vec = VecHelper.getCenterOf(pos); + PloughFakePlayer player = getPlayer(context); + + if (player == null) + return; + + BlockRayTraceResult ray = world + .rayTraceBlocks(new RayTraceContext(vec, vec.add(0, -1, 0), BlockMode.OUTLINE, FluidMode.NONE, player)); + if (ray == null || ray.getType() != Type.BLOCK) + return; + + ItemUseContext ctx = new ItemUseContext(player, Hand.MAIN_HAND, ray); + new ItemStack(Items.DIAMOND_HOE).onItemUse(ctx); + } + + @Override + public Vec3d getActiveAreaOffset(MovementContext context) { + return new Vec3d(context.state.get(HORIZONTAL_FACING).getDirectionVec()).scale(.45); + } + + @Override + protected boolean throwsEntities() { + return true; + } + + @Override + public boolean canBreak(World world, BlockPos breakingPos, BlockState state) { + return state.getCollisionShape(world, breakingPos).isEmpty(); + } + + @Override + public void stopMoving(MovementContext context) { + super.stopMoving(context); + if (context.temporaryData instanceof PloughFakePlayer) + ((PloughFakePlayer) context.temporaryData).remove(); + } + + private PloughFakePlayer getPlayer(MovementContext context) { + if (!(context.temporaryData instanceof PloughFakePlayer) && context.world instanceof ServerWorld) { + PloughFakePlayer player = new PloughFakePlayer((ServerWorld) context.world); + player.setHeldItem(Hand.MAIN_HAND, new ItemStack(Items.DIAMOND_HOE)); + context.temporaryData = player; + } + return (PloughFakePlayer) context.temporaryData; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/SawMovementBehaviour.java b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/SawMovementBehaviour.java index 00071f5ea..4c0036de2 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/actors/SawMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/actors/SawMovementBehaviour.java @@ -6,6 +6,7 @@ import com.simibubi.create.foundation.utility.TreeCutter.Tree; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.modules.contraptions.components.contraptions.MovementContext; import com.simibubi.create.modules.contraptions.components.saw.SawBlock; +import com.simibubi.create.modules.contraptions.components.saw.SawTileEntity; import net.minecraft.block.BlockState; import net.minecraft.entity.item.ItemEntity; @@ -31,12 +32,13 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour { @Override public boolean canBreak(World world, BlockPos breakingPos, BlockState state) { - return super.canBreak(world, breakingPos, state) - && (state.isIn(BlockTags.LOGS) || state.isIn(BlockTags.LEAVES)); + return super.canBreak(world, breakingPos, state) && SawTileEntity.isSawable(state); } @Override - protected void onBlockBroken(MovementContext context, BlockPos pos) { + protected void onBlockBroken(MovementContext context, BlockPos pos, BlockState brokenState) { + if (brokenState.isIn(BlockTags.LEAVES)) + return; Tree tree = TreeCutter.cutTree(context.world, pos); if (tree != null) { for (BlockPos log : tree.logs) diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/BlockMovementTraits.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/BlockMovementTraits.java index 844833d8c..b2ed5c4c6 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/BlockMovementTraits.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/BlockMovementTraits.java @@ -1,6 +1,7 @@ package com.simibubi.create.modules.contraptions.components.contraptions; import com.simibubi.create.AllBlocks; +import com.simibubi.create.modules.contraptions.components.actors.AttachedActorBlock; import com.simibubi.create.modules.contraptions.components.actors.HarvesterBlock; import com.simibubi.create.modules.contraptions.components.actors.PortableStorageInterfaceBlock; import com.simibubi.create.modules.contraptions.components.contraptions.bearing.ClockworkBearingBlock; @@ -11,6 +12,8 @@ import com.simibubi.create.modules.contraptions.components.contraptions.chassis. import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock; import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock.PistonState; import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyBlock; +import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyBlock.MagnetBlock; +import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyBlock.RopeBlock; import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyTileEntity; import com.simibubi.create.modules.logistics.block.AttachedLogisticalBlock; import com.simibubi.create.modules.logistics.block.RedstoneLinkBlock; @@ -82,7 +85,7 @@ public class BlockMovementTraits { if (block instanceof PulleyBlock) { TileEntity te = world.getTileEntity(pos); if (te instanceof PulleyTileEntity) - return !((PulleyTileEntity) te).running && ((PulleyTileEntity) te).offset == 0; + return !((PulleyTileEntity) te).running; } if (AllBlocks.BELT.typeOf(blockState)) @@ -126,6 +129,10 @@ public class BlockMovementTraits { return true; if (block instanceof RedstoneLinkBlock) return true; + if (block instanceof RopeBlock) + return true; + if (block instanceof MagnetBlock) + return true; return false; } @@ -169,7 +176,7 @@ public class BlockMovementTraits { return direction == (state.get(BlockStateProperties.HANGING) ? Direction.UP : Direction.DOWN); if (block instanceof AbstractRailBlock) return direction == Direction.DOWN; - if (block instanceof HarvesterBlock) + if (block instanceof AttachedActorBlock) return direction == state.get(HarvesterBlock.HORIZONTAL_FACING).getOpposite(); return false; } @@ -185,8 +192,10 @@ public class BlockMovementTraits { return state.get(BlockStateProperties.FACING) == facing; if (AllBlocks.PORTABLE_STORAGE_INTERFACE.typeOf(state)) return state.get(PortableStorageInterfaceBlock.FACING) == facing; - if (AllBlocks.HARVESTER.typeOf(state)) + if (state.getBlock() instanceof AttachedActorBlock) return state.get(BlockStateProperties.HORIZONTAL_FACING) == facing; + if (AllBlocks.ROPE_PULLEY.typeOf(state)) + return facing == Direction.DOWN; return isBrittle(state); } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ChassisRangeDisplay.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ChassisRangeDisplay.java index 5dc49a3ff..fa722b8a3 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ChassisRangeDisplay.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ChassisRangeDisplay.java @@ -10,18 +10,19 @@ import java.util.Map; import java.util.Set; import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager.DestFactor; import com.mojang.blaze3d.platform.GlStateManager.SourceFactor; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; import com.simibubi.create.foundation.utility.TessellatorHelper; +import com.simibubi.create.foundation.utility.outliner.BlockClusterOutline; +import com.simibubi.create.foundation.utility.outliner.Outline; +import com.simibubi.create.foundation.utility.outliner.OutlineParticle; import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.Tessellator; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; @@ -35,13 +36,15 @@ public class ChassisRangeDisplay { private static GroupEntry lastHoveredGroup = null; private static class Entry { - Set includedPositions; + BlockClusterOutline outline; + OutlineParticle particle; ChassisTileEntity te; int timer; public Entry(ChassisTileEntity te) { this.te = te; - includedPositions = createSelection(te); + outline = new BlockClusterOutline(createSelection(te)); + particle = OutlineParticle.create(outline); timer = DISPLAY_TIME; } @@ -85,14 +88,19 @@ public class ChassisRangeDisplay { World world = Minecraft.getInstance().world; boolean hasWrench = AllItems.WRENCH.typeOf(player.getHeldItemMainhand()); - for (Iterator iterator = entries.keySet().iterator(); iterator.hasNext();) - if (tickEntry(entries.get(iterator.next()), hasWrench)) + for (Iterator iterator = entries.keySet().iterator(); iterator.hasNext();) { + Entry entry = entries.get(iterator.next()); + if (tickEntry(entry, hasWrench)) { + entry.particle.remove(); iterator.remove(); + } + } for (Iterator iterator = groupEntries.iterator(); iterator.hasNext();) { GroupEntry group = iterator.next(); if (tickEntry(group, hasWrench)) { iterator.remove(); + group.particle.remove(); if (group == lastHoveredGroup) lastHoveredGroup = null; } @@ -118,8 +126,11 @@ public class ChassisRangeDisplay { if (ctrl) { GroupEntry existingGroupForPos = getExistingGroupForPos(pos); if (existingGroupForPos != null) { - for (ChassisTileEntity included : existingGroupForPos.includedTEs) - entries.remove(included.getPos()); + for (ChassisTileEntity included : existingGroupForPos.includedTEs) { + Entry removed = entries.remove(included.getPos()); + if (removed != null) + removed.particle.remove(); + } existingGroupForPos.timer = DISPLAY_TIME; return; } @@ -167,13 +178,19 @@ public class ChassisRangeDisplay { public static void display(ChassisTileEntity chassis) { deselect(); if (AllKeys.ctrlDown()) { + groupEntries.forEach(e -> e.particle.remove()); groupEntries.clear(); GroupEntry hoveredGroup = new GroupEntry(chassis); - for (ChassisTileEntity included : hoveredGroup.includedTEs) - entries.remove(included.getPos()); + for (ChassisTileEntity included : hoveredGroup.includedTEs) { + Entry remove = entries.remove(included.getPos()); + if (remove != null) + remove.particle.remove(); + } groupEntries.add(hoveredGroup); } else { - entries.put(chassis.getPos(), new Entry(chassis)); + Entry old = entries.put(chassis.getPos(), new Entry(chassis)); + if (old != null) + old.particle.remove(); } } @@ -196,17 +213,23 @@ public class ChassisRangeDisplay { } public static void renderPositions(Entry entry, float partialTicks) { - TessellatorHelper.begin(); - BlockPos size = new BlockPos(1, 1, 1); +// GlStateManager.pushMatrix(); +// RenderHelper.disableStandardItemLighting(); +// GlStateManager.normal3f(0.0F, 1.0F, 0.0F); +// GlStateManager.color4f(1, 1, 1, 1); +// GlStateManager.enableTexture(); +// GlStateManager.depthMask(false); +// GlStateManager.enableBlend(); +// GlStateManager.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA); +// float timer = entry.timer - partialTicks; - float alpha = timer > 20 ? .5f : timer / 40f; - RenderSystem.color4f(1, .7f, 0, alpha); - Set includedPositions = entry.includedPositions; - GlStateManager.depthMask(false); - for (BlockPos pos : includedPositions) - TessellatorHelper.cube(Tessellator.getInstance().getBuffer(), pos, size, 1 / 16f - 1 / 64f, true, false); - TessellatorHelper.draw(); - GlStateManager.depthMask(true); + float alpha = timer > 20 ? 1 : timer / 20f; + entry.outline.setAlpha(alpha); +// entry.outline.render(Tessellator.getInstance().getBuffer()); +// +// GlStateManager.disableBlend(); +// GlStateManager.depthMask(true); +// GlStateManager.popMatrix(); } private static GroupEntry getExistingGroupForPos(BlockPos pos) { diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/Contraption.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/Contraption.java index 798125a15..0219fabc2 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/Contraption.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/Contraption.java @@ -25,14 +25,19 @@ import com.simibubi.create.foundation.utility.WrappedWorld; import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.components.contraptions.chassis.AbstractChassisBlock; import com.simibubi.create.modules.contraptions.components.contraptions.chassis.ChassisTileEntity; +import com.simibubi.create.modules.contraptions.components.contraptions.glue.SuperGlueEntity; +import com.simibubi.create.modules.contraptions.components.contraptions.glue.SuperGlueHandler; import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock; -import com.simibubi.create.modules.contraptions.components.contraptions.piston.PistonPoleBlock; import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock.PistonState; import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonHeadBlock; +import com.simibubi.create.modules.contraptions.components.contraptions.piston.PistonPoleBlock; +import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyBlock; +import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyBlock.MagnetBlock; +import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyBlock.RopeBlock; +import com.simibubi.create.modules.contraptions.components.contraptions.pulley.PulleyTileEntity; import com.simibubi.create.modules.contraptions.components.saw.SawBlock; import com.simibubi.create.modules.contraptions.redstone.ContactBlock; import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; import com.simibubi.create.modules.logistics.block.inventories.FlexcrateBlock; import net.minecraft.block.AbstractButtonBlock; @@ -54,6 +59,7 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.Direction.AxisDirection; +import net.minecraft.util.Rotation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -71,6 +77,7 @@ public abstract class Contraption { public List> actors; public CombinedInvWrapper inventory; public List customRenderTEs; + public Set> superglue; public AxisAlignedBB bounds; public boolean stalled; @@ -80,13 +87,16 @@ public abstract class Contraption { protected BlockPos anchor; List renderOrder; + protected List glueToRemove; public Contraption() { blocks = new HashMap<>(); storage = new HashMap<>(); actors = new ArrayList<>(); + superglue = new HashSet<>(); renderOrder = new ArrayList<>(); customRenderTEs = new ArrayList<>(); + glueToRemove = new ArrayList<>(); } public Set getColliders(World world, Direction movementDirection) { @@ -118,7 +128,8 @@ public abstract class Contraption { if (bounds == null) bounds = new AxisAlignedBB(BlockPos.ZERO); - frontier.add(pos); + if (!BlockMovementTraits.isBrittle(world.getBlockState(pos))) + frontier.add(pos); if (!addToInitialFrontier(world, pos, forcedDirection, frontier)) return false; for (int limit = 100000; limit > 0; limit--) { @@ -148,6 +159,8 @@ public abstract class Contraption { if (!world.isBlockPresent(pos)) return false; + if (isAnchoringBlockAt(pos)) + return true; if (!BlockMovementTraits.movementNecessary(world, pos)) return true; if (!BlockMovementTraits.movementAllowed(world, pos)) @@ -155,6 +168,7 @@ public abstract class Contraption { BlockState state = world.getBlockState(pos); if (isChassis(state) && !moveChassis(world, pos, forcedDirection, frontier, visited)) return false; + if (AllBlocks.FLEXCRATE.typeOf(state)) FlexcrateBlock.splitCrate(world, pos); if (AllBlocks.BELT.typeOf(state)) { @@ -165,7 +179,27 @@ public abstract class Contraption { if (prevPos != null && !visited.contains(prevPos)) frontier.add(prevPos); } - + + // Pulleys drag their rope and their attached structure + if (state.getBlock() instanceof PulleyBlock) { + int limit = AllConfigs.SERVER.kinetics.maxRopeLength.get(); + BlockPos ropePos = pos; + while (limit-- >= 0) { + ropePos = ropePos.down(); + if (!world.isBlockPresent(ropePos)) + break; + BlockState ropeState = world.getBlockState(ropePos); + Block block = ropeState.getBlock(); + if (!(block instanceof RopeBlock) && !(block instanceof MagnetBlock)) { + if (!visited.contains(ropePos)) + frontier.add(ropePos); + break; + } + add(ropePos, capture(world, ropePos)); + } + } + + // Pistons drag their attaches poles and extension if (state.getBlock() instanceof MechanicalPistonBlock) { int limit = AllConfigs.SERVER.kinetics.maxPistonPoles.get(); Direction direction = state.get(MechanicalPistonBlock.FACING); @@ -189,7 +223,7 @@ public abstract class Contraption { if (limit <= -1) return false; } - + BlockPos searchPos = pos; while (limit-- >= 0) { searchPos = searchPos.offset(direction.getOpposite()); @@ -203,17 +237,21 @@ public abstract class Contraption { } break; } - + if (limit <= -1) return false; } - + + // Doors try to stay whole if (state.getBlock() instanceof DoorBlock) { BlockPos otherPartPos = pos.up(state.get(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? 1 : -1); if (!visited.contains(otherPartPos)) frontier.add(otherPartPos); } + Map superglue = SuperGlueHandler.gatherGlue(world, pos); + + // Slime blocks drag adjacent blocks if possible boolean isSlimeBlock = state.getBlock() instanceof SlimeBlock; for (Direction offset : Direction.values()) { BlockPos offsetPos = pos.offset(offset); @@ -225,14 +263,24 @@ public abstract class Contraption { return false; continue; } - if (!visited.contains(offsetPos) - && (isSlimeBlock || BlockMovementTraits.isBlockAttachedTowards(blockState, offset.getOpposite()))) + + boolean wasVisited = visited.contains(offsetPos); + boolean faceHasGlue = superglue.containsKey(offset); + boolean blockAttachedTowardsFace = + BlockMovementTraits.isBlockAttachedTowards(blockState, offset.getOpposite()); + boolean brittle = BlockMovementTraits.isBrittle(blockState); + + if (!wasVisited && ((isSlimeBlock && !brittle) || blockAttachedTowardsFace || faceHasGlue)) frontier.add(offsetPos); + + if (faceHasGlue) + addGlue(superglue.get(offset)); } add(pos, capture(world, pos)); if (blocks.size() > AllConfigs.SERVER.kinetics.maxBlocksMoved.get()) return false; + return true; } @@ -295,6 +343,14 @@ public abstract class Contraption { return compoundnbt; } + public void addGlue(SuperGlueEntity entity) { + BlockPos pos = entity.getHangingPosition(); + Direction direction = entity.getFacingDirection(); + BlockPos localPos = pos.subtract(anchor); + this.superglue.add(Pair.of(localPos, direction)); + glueToRemove.add(entity); + } + public void add(BlockPos pos, Pair pair) { BlockInfo captured = pair.getKey(); BlockPos localPos = pos.subtract(anchor); @@ -371,6 +427,13 @@ public abstract class Contraption { getActors().add(MutablePair.of(info, context)); }); + superglue.clear(); + nbt.getList("Superglue", 10).forEach(c -> { + CompoundNBT comp = (CompoundNBT) c; + superglue.add(Pair.of(NBTUtil.readBlockPos(comp.getCompound("Pos")), + Direction.byIndex(comp.getByte("Direction")))); + }); + storage.clear(); nbt.getList("Storage", 10).forEach(c -> { CompoundNBT comp = (CompoundNBT) c; @@ -409,6 +472,14 @@ public abstract class Contraption { actorsNBT.add(compound); } + ListNBT superglueNBT = new ListNBT(); + for (Pair glueEntry : superglue) { + CompoundNBT c = new CompoundNBT(); + c.put("Pos", NBTUtil.writeBlockPos(glueEntry.getKey())); + c.putByte("Direction", (byte) glueEntry.getValue().getIndex()); + superglueNBT.add(c); + } + ListNBT storageNBT = new ListNBT(); for (BlockPos pos : storage.keySet()) { CompoundNBT c = new CompoundNBT(); @@ -422,6 +493,7 @@ public abstract class Contraption { nbt.put("Blocks", blocksNBT); nbt.put("Actors", actorsNBT); + nbt.put("Superglue", superglueNBT); nbt.put("Storage", storageNBT); nbt.put("Anchor", NBTUtil.writeBlockPos(anchor)); nbt.putBoolean("Stalled", stalled); @@ -435,11 +507,7 @@ public abstract class Contraption { } public static boolean isFrozen() { - return AllConfigs.SERVER.control.freezePistonConstructs.get(); - } - - public void disassemble(World world, BlockPos offset, Vec3d rotation) { - disassemble(world, offset, rotation, (pos, state) -> false); + return AllConfigs.SERVER.control.freezeContraptions.get(); } public void removeBlocksFromWorld(IWorld world, BlockPos offset) { @@ -448,6 +516,8 @@ public abstract class Contraption { public void removeBlocksFromWorld(IWorld world, BlockPos offset, BiPredicate customRemoval) { storage.values().forEach(MountedStorage::empty); + glueToRemove.forEach(SuperGlueEntity::remove); + for (boolean brittles : Iterate.trueAndFalse) { for (BlockInfo block : blocks.values()) { if (brittles != BlockMovementTraits.isBrittle(block.state)) @@ -465,7 +535,11 @@ public abstract class Contraption { } } - public void disassemble(World world, BlockPos offset, Vec3d rotation, + public void addBlocksToWorld(World world, BlockPos offset, Vec3d rotation) { + addBlocksToWorld(world, offset, rotation, (pos, state) -> false); + } + + public void addBlocksToWorld(World world, BlockPos offset, Vec3d rotation, BiPredicate customPlacement) { stop(world); @@ -497,8 +571,16 @@ public abstract class Contraption { && !blockState.getCollisionShape(world, targetPos).isEmpty()) continue; - world.destroyBlock(targetPos, blockState.getCollisionShape(world, targetPos).isEmpty()); + world.destroyBlock(targetPos, true); world.setBlockState(targetPos, state, 3 | BlockFlags.IS_MOVING); + + boolean verticalRotation = transform.rotationAxis == null || transform.rotationAxis.isHorizontal(); + verticalRotation = verticalRotation && transform.rotation != Rotation.NONE; + if (verticalRotation) { + if (state.getBlock() instanceof RopeBlock || state.getBlock() instanceof MagnetBlock) + world.destroyBlock(targetPos, true); + } + TileEntity tileEntity = world.getTileEntity(targetPos); CompoundNBT tag = block.nbt; if (tileEntity != null && tag != null) { @@ -506,32 +588,34 @@ public abstract class Contraption { tag.putInt("y", targetPos.getY()); tag.putInt("z", targetPos.getZ()); - if (tileEntity instanceof BeltTileEntity) { - tag.remove("Length"); - tag.remove("Index"); - tag.putBoolean("DontClearAttachments", true); + if (verticalRotation && tileEntity instanceof PulleyTileEntity) { + tag.remove("Offset"); + tag.remove("InitialOffset"); } tileEntity.read(tag); - if (tileEntity instanceof KineticTileEntity) { - KineticTileEntity kineticTileEntity = (KineticTileEntity) tileEntity; - kineticTileEntity.source = null; - kineticTileEntity.setSpeed(0); - kineticTileEntity.network = null; - kineticTileEntity.attachKinetics(); - } - if (storage.containsKey(block.pos)) { MountedStorage mountedStorage = storage.get(block.pos); if (mountedStorage.isWorking()) mountedStorage.fill(tileEntity); } } + } + } + for (Pair pair : superglue) { + BlockPos targetPos = transform.apply(pair.getKey()); + Direction targetFacing = transform.transformFacing(pair.getValue()); + + SuperGlueEntity entity = new SuperGlueEntity(world, targetPos, targetFacing); + if (entity.onValidSurface()) { + if (!world.isRemote) + world.addEntity(entity); } } + } public void initActors(World world) { diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntity.java index 1555fdaec..037d4deae 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntity.java @@ -12,16 +12,24 @@ import org.apache.commons.lang3.tuple.MutablePair; import com.google.common.collect.ImmutableSet; import com.simibubi.create.AllEntities; import com.simibubi.create.AllPackets; +import com.simibubi.create.foundation.item.ItemHelper; +import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.modules.contraptions.components.contraptions.bearing.BearingContraption; +import com.simibubi.create.modules.contraptions.components.contraptions.mounted.CartAssemblerTileEntity.CartMovementMode; +import com.simibubi.create.modules.contraptions.components.contraptions.mounted.MountedContraption; import com.simibubi.create.modules.contraptions.components.contraptions.piston.LinearActuatorTileEntity; +import net.minecraft.block.BlockState; import net.minecraft.block.material.PushReaction; import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.item.BoatEntity; -import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.entity.item.minecart.FurnaceMinecartEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.item.crafting.Ingredient; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.NBTUtil; @@ -30,11 +38,14 @@ import net.minecraft.network.PacketBuffer; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; +import net.minecraft.tags.BlockTags; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.DamageSource; import net.minecraft.util.Direction; import net.minecraft.util.ReuseableStream; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.shapes.IBooleanFunction; import net.minecraft.util.math.shapes.ISelectionContext; @@ -42,7 +53,6 @@ import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.util.math.shapes.VoxelShapes; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; -import net.minecraft.world.server.ServerWorld; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; @@ -53,12 +63,14 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD protected Contraption contraption; protected float initialAngle; + protected float forcedAngle; protected BlockPos controllerPos; protected Vec3d motionBeforeStall; protected boolean stationary; final List collidingEntities = new ArrayList<>(); + private static final Ingredient FUEL_ITEMS = Ingredient.fromItems(Items.COAL, Items.CHARCOAL); private static final DataParameter STALLED = EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.BOOLEAN); @@ -78,20 +90,27 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD super(entityTypeIn, worldIn); motionBeforeStall = Vec3d.ZERO; stationary = entityTypeIn == AllEntities.STATIONARY_CONTRAPTION.type; + forcedAngle = -1; } public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle) { ContraptionEntity entity = new ContraptionEntity(AllEntities.CONTRAPTION.type, world); entity.contraption = contraption; entity.initialAngle = initialAngle; - entity.prevYaw = initialAngle; - entity.yaw = initialAngle; - entity.targetYaw = initialAngle; + entity.forceYaw(initialAngle); if (contraption != null) contraption.gatherStoredItems(); return entity; } + public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle, + Direction facing) { + ContraptionEntity entity = createMounted(world, contraption, initialAngle); + entity.forcedAngle = facing.getHorizontalAngle(); + entity.forceYaw(entity.forcedAngle); + return entity; + } + public static ContraptionEntity createStationary(World world, Contraption contraption) { ContraptionEntity entity = new ContraptionEntity(AllEntities.STATIONARY_CONTRAPTION.type, world); entity.contraption = contraption; @@ -156,6 +175,14 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD } public void tickAsPassenger(Entity e) { + boolean rotationLock = false; + boolean pauseWhileRotating = false; + + if (contraption instanceof MountedContraption) { + rotationLock = ((MountedContraption) contraption).rotationMode == CartMovementMode.ROTATION_LOCKED; + pauseWhileRotating = ((MountedContraption) contraption).rotationMode == CartMovementMode.ROTATE_PAUSED; + } + Entity riding = e; while (riding.getRidingEntity() != null) riding = riding.getRidingEntity(); @@ -163,20 +190,28 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD if (riding instanceof BoatEntity) movementVector = getPositionVec().subtract(prevPosX, prevPosY, prevPosZ); Vec3d motion = movementVector.normalize(); + boolean rotating = false; - if (motion.length() > 0) { - targetYaw = yawFromVector(motion); - if (targetYaw < 0) - targetYaw += 360; - if (yaw < 0) - yaw += 360; + if (!rotationLock) { + if (motion.length() > 0) { + targetYaw = yawFromVector(motion); + if (targetYaw < 0) + targetYaw += 360; + if (yaw < 0) + yaw += 360; + } + + prevYaw = yaw; + yaw = angleLerp(0.4f, yaw, targetYaw); + if (Math.abs(AngleHelper.getShortestAngleDiff(yaw, targetYaw)) < 1f) + yaw = targetYaw; + else + rotating = true; } - prevYaw = yaw; - yaw = angleLerp(0.4f, yaw, targetYaw); - boolean wasStalled = isStalled(); - tickActors(movementVector); + if (!rotating || !pauseWhileRotating) + tickActors(movementVector); if (isStalled()) { if (!wasStalled) motionBeforeStall = riding.getMotion(); @@ -188,6 +223,39 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD motionBeforeStall = Vec3d.ZERO; } + if (!isStalled() && (riding instanceof FurnaceMinecartEntity)) { + FurnaceMinecartEntity furnaceCart = (FurnaceMinecartEntity) riding; + CompoundNBT nbt = furnaceCart.serializeNBT(); + int fuel = nbt.getInt("Fuel"); + int fuelBefore = fuel; + double pushX = nbt.getDouble("PushX"); + double pushZ = nbt.getDouble("PushZ"); + + int i = MathHelper.floor(furnaceCart.getX()); + int j = MathHelper.floor(furnaceCart.getY()); + int k = MathHelper.floor(furnaceCart.getZ()); + if (furnaceCart.world.getBlockState(new BlockPos(i, j - 1, k)).isIn(BlockTags.RAILS)) + --j; + + BlockPos blockpos = new BlockPos(i, j, k); + BlockState blockstate = this.world.getBlockState(blockpos); + if (furnaceCart.canUseRail() && blockstate.isIn(BlockTags.RAILS)) + if (fuel > 1) + riding.setMotion(riding.getMotion().normalize().scale(1)); + if (fuel < 5 && contraption != null) { + ItemStack coal = ItemHelper.extract(contraption.inventory, FUEL_ITEMS, 1, false); + if (!coal.isEmpty()) + fuel += 3600; + } + + if (fuel != fuelBefore || pushX != 0 || pushZ != 0) { + nbt.putInt("Fuel", fuel); + nbt.putDouble("PushX", 0); + nbt.putDouble("PushZ", 0); + furnaceCart.deserializeNBT(nbt); + } + } + super.tick(); } @@ -210,12 +278,12 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD Vec3d actorPosition = new Vec3d(blockInfo.pos); actorPosition = actorPosition.add(actor.getActiveAreaOffset(context)); actorPosition = VecHelper.rotate(actorPosition, angleRoll, angleYaw, anglePitch); - actorPosition = actorPosition.add(rotationOffset).add(getPositionVec()); + actorPosition = actorPosition.add(rotationOffset).add(getAnchorVec()); boolean newPosVisited = false; BlockPos gridPosition = new BlockPos(actorPosition); - if (!stalledPreviously) { + if (!context.stall) { Vec3d previousPosition = context.position; if (previousPosition != null) { context.motion = actorPosition.subtract(previousPosition); @@ -245,13 +313,11 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD } } } - } } context.rotation = rotationVec; context.position = actorPosition; - if (actor.isActive(context)) { if (newPosVisited && !context.stall) { actor.visitNewPosition(context, gridPosition); @@ -280,6 +346,12 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD setPosition(x + getX() + x, getY() + y, getZ() + z); } + private Vec3d getAnchorVec() { + if (contraption != null && contraption.getType() == AllContraptionTypes.MOUNTED) + return new Vec3d(getX() - .5, getY(), getZ() - .5); + return getPositionVec(); + } + public void rotateTo(double roll, double yaw, double pitch) { rotate(getShortestAngleDiff(this.roll, roll), getShortestAngleDiff(this.yaw, yaw), getShortestAngleDiff(this.pitch, pitch)); @@ -298,23 +370,13 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD @Override public void setPosition(double x, double y, double z) { - Entity e = getRidingEntity(); - if (e != null && e instanceof AbstractMinecartEntity) { - Entity riding = e; - while (riding.getRidingEntity() != null) - riding = riding.getRidingEntity(); - x = riding.getX() - .5; - z = riding.getZ() - .5; - } - - this.setPos(x, y, z); - - if (this.isAddedToWorld() && !this.world.isRemote && world instanceof ServerWorld) - ((ServerWorld) this.world).chunkCheck(this); // Forge - Process chunk registration after moving. + super.setPosition(x, y, z); if (contraption != null) { AxisAlignedBB cbox = contraption.getBoundingBox(); - if (cbox != null) - this.setBoundingBox(cbox.offset(x, y, z)); + if (cbox != null) { + Vec3d actualVec = getAnchorVec(); + this.setBoundingBox(cbox.offset(actualVec)); + } } } @@ -362,7 +424,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD protected void readAdditional(CompoundNBT compound) { contraption = Contraption.fromNBT(world, compound.getCompound("Contraption")); initialAngle = compound.getFloat("InitialAngle"); - targetYaw = yaw = prevYaw = initialAngle; + forceYaw(compound.contains("ForcedYaw") ? compound.getFloat("ForcedYaw") : initialAngle); dataManager.set(STALLED, compound.getBoolean("Stalled")); ListNBT vecNBT = compound.getList("CachedMotion", 6); if (!vecNBT.isEmpty()) { @@ -375,6 +437,10 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD controllerPos = NBTUtil.readBlockPos(compound.getCompound("Controller")); } + public void forceYaw(float forcedYaw) { + targetYaw = yaw = prevYaw = forcedYaw; + } + public void checkController() { if (controllerPos == null) return; @@ -394,14 +460,18 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD @Override protected void writeAdditional(CompoundNBT compound) { - compound.put("Contraption", getContraption().writeNBT()); - compound.putFloat("InitialAngle", initialAngle); - if (!stationary) + if (contraption != null) + compound.put("Contraption", contraption.writeNBT()); + if (!stationary && motionBeforeStall != null) compound.put("CachedMotion", newDoubleNBTList(motionBeforeStall.x, motionBeforeStall.y, motionBeforeStall.z)); - compound.putBoolean("Stalled", isStalled()); if (controllerPos != null) compound.put("Controller", NBTUtil.writeBlockPos(controllerPos)); + if (forcedAngle != -1) + compound.putFloat("ForcedYaw", forcedAngle); + + compound.putFloat("InitialAngle", initialAngle); + compound.putBoolean("Stalled", isStalled()); } @Override @@ -423,14 +493,14 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD public void disassemble() { if (getContraption() != null) { - BlockPos offset = new BlockPos(getPositionVec().add(.5, .5, .5)); + BlockPos offset = new BlockPos(getAnchorVec().add(.5, .5, .5)); Vec3d rotation = new Vec3d(getRoll(1), getYaw(1), getPitch(1)); - getContraption().disassemble(world, offset, rotation); + getContraption().addBlocksToWorld(world, offset, rotation); preventMovedEntitiesFromGettingStuck(); } remove(); } - + @Override protected void doWaterSplashEffect() { } @@ -532,4 +602,18 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD super.setMotion(vec); } + @Override + public boolean canBeCollidedWith() { + return false; + } + + @Override + public boolean attackEntityFrom(DamageSource source, float amount) { + return false; + } + + public float getInitialAngle() { + return initialAngle; + } + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntityRenderer.java index bb2a0b1fd..9b062e6c1 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntityRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionEntityRenderer.java @@ -1,6 +1,7 @@ package com.simibubi.create.modules.contraptions.components.contraptions; import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.foundation.utility.TessellatorHelper; import com.simibubi.create.foundation.utility.VecHelper; @@ -37,6 +38,8 @@ public class ContraptionEntityRenderer extends EntityRenderer return; if (entity.getContraption() == null) return; + if (entity.getContraption().getType() == AllContraptionTypes.MOUNTED && entity.getRidingEntity() == null) + return; // TODO 1.15 buffered render RenderSystem.pushMatrix(); @@ -78,6 +81,7 @@ public class ContraptionEntityRenderer extends EntityRenderer RenderSystem.translatef((float) cartX, (float) cartY, (float) cartZ); } + GlStateManager.translatef(-.5f, 0, -.5f); } Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionRenderer.java index 4a7bea722..918c8e2bb 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/ContraptionRenderer.java @@ -1,23 +1,17 @@ package com.simibubi.create.modules.contraptions.components.contraptions; -import java.util.Iterator; import java.util.Random; import java.util.function.Consumer; import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL13; import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.systems.RenderSystem; -import com.simibubi.create.Create; import com.simibubi.create.CreateClient; -import com.simibubi.create.config.AllConfigs; import com.simibubi.create.foundation.utility.PlacementSimulationWorld; import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.foundation.utility.SuperByteBufferCache.Compartment; -import com.simibubi.create.foundation.utility.VecHelper; -import com.simibubi.create.foundation.utility.WrappedWorld; +import com.simibubi.create.foundation.utility.render.StructureRenderer; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; @@ -26,15 +20,9 @@ import net.minecraft.client.renderer.BlockModelRenderer; import net.minecraft.client.renderer.BlockRendererDispatcher; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.LightTexture; -import net.minecraft.client.renderer.RenderHelper; -import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.crash.ReportedException; -import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.world.LightType; @@ -46,59 +34,19 @@ public class ContraptionRenderer { public static final Compartment CONTRAPTION = new Compartment<>(); protected static PlacementSimulationWorld renderWorld; - protected static LightingWorld lightingWorld; - public static void render(World world, Contraption c, Consumer transform, MatrixStack ms, BufferBuilder buffer) { - SuperByteBuffer contraptionBuffer = CreateClient.bufferCache.get(CONTRAPTION, c, () -> renderContraption(c, ms)); + public static void render(World world, Contraption c, Consumer transform, MatrixStack ms, + BufferBuilder buffer) { + SuperByteBuffer contraptionBuffer = + CreateClient.bufferCache.get(CONTRAPTION, c, () -> renderContraption(c, ms)); transform.accept(contraptionBuffer); contraptionBuffer.light((lx, ly, lz) -> getLight(world, lx, ly, lz)).renderInto(ms, buffer); renderActors(world, c, transform, ms, buffer); } - public static void renderTEsWithGL(World world, Contraption c, Vec3d position, Vec3d rotation, MatrixStack ms, IRenderTypeBuffer buffer) { - float pt = Minecraft.getInstance().getRenderPartialTicks(); - - if (lightingWorld == null) - lightingWorld = new LightingWorld(world); - lightingWorld.setWorld(world); - lightingWorld.setTransform(position, rotation); - - for (Iterator iterator = c.customRenderTEs.iterator(); iterator.hasNext();) { - TileEntity tileEntity = iterator.next(); - if (TileEntityRendererDispatcher.instance.getRenderer(tileEntity) == null) { - iterator.remove(); - continue; - } - - try { - - BlockPos pos = tileEntity.getPos(); - if (!tileEntity.hasFastRenderer()) { - RenderHelper.enable(); - int i = WorldRenderer.getLightmapCoordinates(lightingWorld, pos); - int j = LightTexture.getBlockLightCoordinates(i); - int k = LightTexture.getSkyLightCoordinates(i); - RenderSystem.glMultiTexCoord2f(GL13.GL_TEXTURE1, (float) j, (float) k); - RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); - } - - World prevTileWorld = tileEntity.getWorld(); - tileEntity.setLocation(lightingWorld, pos); - TileEntityRendererDispatcher.instance.render(tileEntity, pt, ms, buffer); - tileEntity.setLocation(prevTileWorld, pos); - - } catch (ReportedException e) { - if (AllConfigs.CLIENT.explainRenderErrors.get()) { - Create.logger.error("TileEntity " + tileEntity.getType().getRegistryName().toString() - + " didn't want to render while moved.\n", e); - } else { - Create.logger.error("TileEntity " + tileEntity.getType().getRegistryName().toString() - + " didn't want to render while moved.\n"); - } - iterator.remove(); - continue; - } - } + public static void renderTEsWithGL(World world, Contraption c, Vec3d position, Vec3d rotation, MatrixStack ms, + IRenderTypeBuffer buffer) { + StructureRenderer.renderTileEntities(world, position, rotation, c.customRenderTEs, ms, buffer); } private static SuperByteBuffer renderContraption(Contraption c, MatrixStack ms) { @@ -130,8 +78,8 @@ public class ContraptionRenderer { return new SuperByteBuffer(builder); } - private static void renderActors(World world, Contraption c, Consumer transform, - MatrixStack ms, BufferBuilder buffer) { + private static void renderActors(World world, Contraption c, Consumer transform, MatrixStack ms, + BufferBuilder buffer) { for (Pair actor : c.getActors()) { MovementContext context = actor.getRight(); if (context == null) @@ -171,36 +119,4 @@ public class ContraptionRenderer { return ((int) sky) << 20 | ((int) block) << 4; } - private static class LightingWorld extends WrappedWorld { - - private Vec3d offset; - private Vec3d rotation; - - public LightingWorld(World world) { - super(world); - } - - void setWorld(World world) { - this.world = world; - } - - void setTransform(Vec3d offset, Vec3d rotation) { - this.offset = offset; - this.rotation = rotation; - } - - @Override - public int getBaseLightLevel(BlockPos pos, int minLight) { - return super.getBaseLightLevel(transformPos(pos), minLight); - } - - private BlockPos transformPos(BlockPos pos) { - Vec3d vec = VecHelper.getCenterOf(pos); - vec = VecHelper.rotate(vec, rotation.x, rotation.y, rotation.z); - vec = vec.add(offset).subtract(VecHelper.getCenterOf(BlockPos.ZERO)); - return new BlockPos(vec); - } - - } - } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/StructureTransform.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/StructureTransform.java index 62ee9d279..d1c3723d8 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/StructureTransform.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/StructureTransform.java @@ -163,14 +163,14 @@ public class StructureTransform { return state; } - protected Axis transformAxis(Axis axisIn) { + public Axis transformAxis(Axis axisIn) { Direction facing = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axisIn); facing = transformFacing(facing); Axis axis = facing.getAxis(); return axis; } - protected Direction transformFacing(Direction facing) { + public Direction transformFacing(Direction facing) { for (int i = 0; i < rotation.ordinal(); i++) facing = DirectionHelper.rotateAround(facing, rotationAxis); return facing; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/BearingContraption.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/BearingContraption.java index e7d3edc64..d32d89010 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/BearingContraption.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/BearingContraption.java @@ -36,6 +36,11 @@ public class BearingContraption extends Contraption { return construct; } + @Override + protected boolean isAnchoringBlockAt(BlockPos pos) { + return pos.equals(anchor.offset(facing.getOpposite())); + } + @Override public void add(BlockPos pos, Pair capture) { BlockPos localPos = pos.subtract(anchor); @@ -62,7 +67,7 @@ public class BearingContraption extends Contraption { public int getSailBlocks() { return sailBlocks; } - + public Direction getFacing() { return facing; } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/BearingTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/BearingTileEntityRenderer.java index 1956152de..c8252b30b 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/BearingTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/BearingTileEntityRenderer.java @@ -7,7 +7,6 @@ import com.simibubi.create.foundation.utility.SuperByteBuffer; import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; -import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/ClockworkBearingTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/ClockworkBearingTileEntity.java index b8d4fd577..1f73f7449 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/ClockworkBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/ClockworkBearingTileEntity.java @@ -148,6 +148,9 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe } public void assemble() { + if (!(world.getBlockState(pos).getBlock() instanceof ClockworkBearingBlock)) + return; + Direction direction = getBlockState().get(BlockStateProperties.FACING); // Collect Construct @@ -182,7 +185,7 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe } public void disassemble() { - if (!running) + if (!running && hourHand == null && minuteHand == null) return; hourAngle = 0; @@ -205,7 +208,7 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe public void attach(ContraptionEntity contraption) { if (!(contraption.getContraption() instanceof ClockworkContraption)) return; - + ClockworkContraption cc = (ClockworkContraption) contraption.getContraption(); markDirty(); Direction facing = getBlockState().get(BlockStateProperties.FACING); @@ -217,8 +220,10 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe this.minuteHand = contraption; minuteHand.setPosition(anchor.getX(), anchor.getY(), anchor.getZ()); } - if (!world.isRemote) + if (!world.isRemote) { + this.running = true; sendData(); + } } @Override @@ -302,5 +307,5 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe public boolean isRunning() { return running; } - + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/ClockworkContraption.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/ClockworkContraption.java index 25d4687ee..e31759ed6 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/ClockworkContraption.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/ClockworkContraption.java @@ -32,6 +32,11 @@ public class ClockworkContraption extends Contraption { ignoreBlocks.add(anchor.add(blockPos)); } + @Override + protected boolean isAnchoringBlockAt(BlockPos pos) { + return pos.equals(anchor.offset(facing.getOpposite(), offset + 1)); + } + public static Pair assembleClockworkAt(World world, BlockPos pos, Direction direction) { if (isFrozen()) diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/MechanicalBearingTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/MechanicalBearingTileEntity.java index d962824b6..bffbbc4e5 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/MechanicalBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/bearing/MechanicalBearingTileEntity.java @@ -150,6 +150,9 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp } public void assemble() { + if (!(world.getBlockState(pos).getBlock() instanceof MechanicalBearingBlock)) + return; + Direction direction = getBlockState().get(FACING); // Collect Construct @@ -161,6 +164,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp if (contraption.blocks.isEmpty()) return; contraption.removeBlocksFromWorld(world, BlockPos.ZERO); + movedContraption = ContraptionEntity.createStationary(world, contraption).controlledBy(this); BlockPos anchor = pos.offset(direction); movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ()); @@ -172,7 +176,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp sendData(); updateGeneratedRotation(); } - + @Override public void updateGeneratedRotation() { super.updateGeneratedRotation(); @@ -180,7 +184,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp } public void disassemble() { - if (!running) + if (!running && movedContraption == null) return; if (movedContraption != null) movedContraption.disassemble(); @@ -267,8 +271,10 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp markDirty(); BlockPos anchor = pos.offset(blockState.get(FACING)); movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ()); - if (!world.isRemote) + if (!world.isRemote) { + this.running = true; sendData(); + } } @Override @@ -298,7 +304,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp public boolean isAttachedTo(ContraptionEntity contraption) { return movedContraption == contraption; } - + public boolean isRunning() { return running; } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/chassis/ChassisTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/chassis/ChassisTileEntity.java index d19225985..2cf714806 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/chassis/ChassisTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/chassis/ChassisTileEntity.java @@ -167,11 +167,7 @@ public class ChassisTileEntity extends SmartTileEntity { // Ignore replaceable Blocks and Air-like if (!BlockMovementTraits.movementNecessary(world, current)) break; - if (AllBlocks.MECHANICAL_PISTON_HEAD.typeOf(currentState)) - break; - if (AllBlocks.MECHANICAL_PISTON.typeOf(currentState)) - break; - if (AllBlocks.STICKY_MECHANICAL_PISTON.typeOf(currentState)) + if (BlockMovementTraits.isBrittle(currentState)) break; positions.add(current); @@ -212,6 +208,8 @@ public class ChassisTileEntity extends SmartTileEntity { continue; if (!BlockMovementTraits.movementNecessary(world, searchPos)) continue; + if (BlockMovementTraits.isBrittle(searchedState)) + continue; localVisited.add(searchPos); if (!searchPos.equals(pos)) diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/GlueEffectPacket.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/GlueEffectPacket.java new file mode 100644 index 000000000..02dfe0b48 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/GlueEffectPacket.java @@ -0,0 +1,49 @@ +package com.simibubi.create.modules.contraptions.components.contraptions.glue; + +import java.util.function.Supplier; + +import com.simibubi.create.foundation.packet.SimplePacketBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class GlueEffectPacket extends SimplePacketBase { + + private BlockPos pos; + private Direction direction; + private boolean fullBlock; + + public GlueEffectPacket(BlockPos pos, Direction direction, boolean fullBlock) { + this.pos = pos; + this.direction = direction; + this.fullBlock = fullBlock; + } + + public GlueEffectPacket(PacketBuffer buffer) { + pos = buffer.readBlockPos(); + direction = Direction.byIndex(buffer.readByte()); + fullBlock = buffer.readBoolean(); + } + + public void write(PacketBuffer buffer) { + buffer.writeBlockPos(pos); + buffer.writeByte(direction.getIndex()); + buffer.writeBoolean(fullBlock); + } + + public void handle(Supplier context) { + context.get().enqueueWork(() -> DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { + Minecraft mc = Minecraft.getInstance(); + if (!mc.player.getPosition().withinDistance(pos, 100)) + return; + SuperGlueItem.spawnParticles(mc.world, pos, direction, fullBlock); + })); + context.get().setPacketHandled(true); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueEntity.java new file mode 100644 index 000000000..d55e0bd64 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueEntity.java @@ -0,0 +1,369 @@ +package com.simibubi.create.modules.contraptions.components.contraptions.glue; + +import javax.annotation.Nullable; + +import org.apache.commons.lang3.Validate; + +import com.simibubi.create.AllEntities; +import com.simibubi.create.AllItems; +import com.simibubi.create.AllPackets; +import com.simibubi.create.AllSoundEvents; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntitySize; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.MoverType; +import net.minecraft.entity.Pose; +import net.minecraft.entity.effect.LightningBoltEntity; +import net.minecraft.entity.item.ItemEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.IPacket; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.DamageSource; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Hand; +import net.minecraft.util.Mirror; +import net.minecraft.util.Rotation; +import net.minecraft.util.SoundEvents; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; +import net.minecraftforge.fml.network.NetworkHooks; +import net.minecraftforge.fml.network.PacketDistributor; + +public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnData { + + private int validationTimer; + protected BlockPos hangingPosition; + protected Direction facingDirection = Direction.SOUTH; + + public SuperGlueEntity(EntityType type, World world) { + super(type, world); + } + + public SuperGlueEntity(World world, BlockPos pos, Direction direction) { + this(AllEntities.SUPER_GLUE.type, world); + hangingPosition = pos; + facingDirection = direction; + updateFacingWithBoundingBox(); + } + + @Override + protected void registerData() { + } + + public int getWidthPixels() { + return 12; + } + + public int getHeightPixels() { + return 12; + } + + public void onBroken(@Nullable Entity breaker) { + playSound(SoundEvents.ENTITY_SLIME_SQUISH_SMALL, 1.0F, 1.0F); + if (onValidSurface()) { + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + new GlueEffectPacket(getHangingPosition(), getFacingDirection().getOpposite(), false)); + playSound(AllSoundEvents.SLIME_ADDED.get(), 0.5F, 0.5F); + } + } + + public void playPlaceSound() { + playSound(AllSoundEvents.SLIME_ADDED.get(), 0.5F, 0.75F); + } + + protected void updateFacingWithBoundingBox() { + Validate.notNull(getFacingDirection()); + if (getFacingDirection().getAxis().isHorizontal()) { + this.rotationPitch = 0.0F; + this.rotationYaw = getFacingDirection().getHorizontalIndex() * 90; + } else { + this.rotationPitch = -90 * getFacingDirection().getAxisDirection().getOffset(); + this.rotationYaw = 0.0F; + } + + this.prevRotationPitch = this.rotationPitch; + this.prevRotationYaw = this.rotationYaw; + this.updateBoundingBox(); + } + + protected void updateBoundingBox() { + if (this.getFacingDirection() != null) { + double x = hangingPosition.getX() + 0.5 - facingDirection.getXOffset() * 0.5; + double y = hangingPosition.getY() + 0.5 - facingDirection.getYOffset() * 0.5; + double z = hangingPosition.getZ() + 0.5 - facingDirection.getZOffset() * 0.5; + this.setPos(x, y, z); + double d1 = (double) this.getWidthPixels(); + double d2 = (double) this.getHeightPixels(); + double d3 = (double) this.getWidthPixels(); + Axis axis = this.getFacingDirection().getAxis(); + double depth = 2 - 1 / 128f; + + switch (axis) { + case X: + d1 = depth; + break; + case Y: + d2 = depth; + break; + case Z: + d3 = depth; + } + + d1 = d1 / 32.0D; + d2 = d2 / 32.0D; + d3 = d3 / 32.0D; + this.setBoundingBox(new AxisAlignedBB(x - d1, y - d2, z - d3, x + d1, y + d2, z + d3)); + } + } + + @Override + public void tick() { + if (this.validationTimer++ == 10 && !this.world.isRemote) { + this.validationTimer = 0; + if (isAlive() && !this.onValidSurface()) { + remove(); + onBroken(null); + } + } + + } + + public boolean onValidSurface() { + BlockPos pos = hangingPosition; + BlockPos pos2 = hangingPosition.offset(getFacingDirection().getOpposite()); + if (!world.isAreaLoaded(pos, 0) || !world.isAreaLoaded(pos2, 0)) + return true; + if (world.isAirBlock(pos) && world.isAirBlock(pos2)) + return false; + return world.getEntitiesInAABBexcluding(this, getBoundingBox(), e -> e instanceof SuperGlueEntity).isEmpty(); + } + + @Override + public boolean canBeCollidedWith() { + return true; + } + + @Override + public boolean hitByEntity(Entity entity) { + return entity instanceof PlayerEntity + ? attackEntityFrom(DamageSource.causePlayerDamage((PlayerEntity) entity), 0) + : false; + } + + @Override + public Direction getHorizontalFacing() { + return this.getFacingDirection(); + } + + @Override + public boolean attackEntityFrom(DamageSource source, float amount) { + if (this.isInvulnerableTo(source)) + return false; + if (isAlive() && !world.isRemote) { + remove(); + markVelocityChanged(); + onBroken(source.getTrueSource()); + } + + return true; + } + + @Override + public void move(MoverType typeIn, Vec3d pos) { + if (!world.isRemote && isAlive() && pos.lengthSquared() > 0.0D) { + remove(); + onBroken(null); + } + } + + @Override + public void addVelocity(double x, double y, double z) { + if (!world.isRemote && isAlive() && x * x + y * y + z * z > 0.0D) { + remove(); + onBroken(null); + } + } + + @Override + protected float getEyeHeight(Pose poseIn, EntitySize sizeIn) { + return 0.0F; + } + + @Override + public ItemStack getPickedResult(RayTraceResult target) { + return AllItems.SUPER_GLUE.asStack(); + } + + @Override + public void applyEntityCollision(Entity entityIn) { + super.applyEntityCollision(entityIn); + } + + @Override + public boolean processInitialInteract(PlayerEntity player, Hand hand) { + DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { + triggerPlaceBlock(player, hand); + }); + return true; + } + + @OnlyIn(Dist.CLIENT) + private void triggerPlaceBlock(PlayerEntity player, Hand hand) { + if (player instanceof ClientPlayerEntity && player.world instanceof ClientWorld) { + ClientPlayerEntity cPlayer = (ClientPlayerEntity) player; + Minecraft mc = Minecraft.getInstance(); + RayTraceResult ray = + cPlayer.pick(mc.playerController.getBlockReachDistance(), mc.getRenderPartialTicks(), false); + if (ray instanceof BlockRayTraceResult) { + for (Hand handIn : Hand.values()) { + ItemStack itemstack = cPlayer.getHeldItem(handIn); + int countBefore = itemstack.getCount(); + ActionResultType actionResultType = mc.playerController.func_217292_a(cPlayer, + (ClientWorld) cPlayer.world, handIn, (BlockRayTraceResult) ray); + if (actionResultType == ActionResultType.SUCCESS) { + cPlayer.swingArm(handIn); + if (!itemstack.isEmpty() + && (itemstack.getCount() != countBefore || mc.playerController.isInCreativeMode())) + mc.gameRenderer.itemRenderer.resetEquippedProgress(handIn); + return; + } + } + } + } + } + + @Override + public void writeAdditional(CompoundNBT compound) { + compound.putByte("Facing", (byte) this.getFacingDirection().getIndex()); + BlockPos blockpos = this.getHangingPosition(); + compound.putInt("TileX", blockpos.getX()); + compound.putInt("TileY", blockpos.getY()); + compound.putInt("TileZ", blockpos.getZ()); + } + + @Override + public void readAdditional(CompoundNBT compound) { + this.hangingPosition = + new BlockPos(compound.getInt("TileX"), compound.getInt("TileY"), compound.getInt("TileZ")); + this.facingDirection = Direction.byIndex(compound.getByte("Facing")); + updateFacingWithBoundingBox(); + } + + @Override + public ItemEntity entityDropItem(ItemStack stack, float yOffset) { + float xOffset = (float) this.getFacingDirection().getXOffset() * 0.15F; + float zOffset = (float) this.getFacingDirection().getZOffset() * 0.15F; + ItemEntity itementity = + new ItemEntity(this.world, this.getX() + xOffset, this.getY() + yOffset, this.getZ() + zOffset, stack); + itementity.setDefaultPickupDelay(); + this.world.addEntity(itementity); + return itementity; + } + + @Override + protected boolean shouldSetPosAfterLoading() { + return false; + } + + @Override + public void setPosition(double x, double y, double z) { + hangingPosition = new BlockPos(x, y, z); + updateBoundingBox(); + isAirBorne = true; + } + + @Override + public float getRotatedYaw(Rotation transformRotation) { + if (this.getFacingDirection().getAxis() != Direction.Axis.Y) { + switch (transformRotation) { + case CLOCKWISE_180: + this.facingDirection = this.getFacingDirection().getOpposite(); + break; + case COUNTERCLOCKWISE_90: + this.facingDirection = this.getFacingDirection().rotateYCCW(); + break; + case CLOCKWISE_90: + this.facingDirection = this.getFacingDirection().rotateY(); + default: + break; + } + } + + float f = MathHelper.wrapDegrees(this.rotationYaw); + switch (transformRotation) { + case CLOCKWISE_180: + return f + 180.0F; + case COUNTERCLOCKWISE_90: + return f + 90.0F; + case CLOCKWISE_90: + return f + 270.0F; + default: + return f; + } + } + + public BlockPos getHangingPosition() { + return this.hangingPosition; + } + + @Override + public float getMirroredYaw(Mirror transformMirror) { + return this.getRotatedYaw(transformMirror.toRotation(this.getFacingDirection())); + } + + public Direction getAttachedDirection(BlockPos pos) { + return !pos.equals(hangingPosition) ? getFacingDirection() : getFacingDirection().getOpposite(); + } + + @Override + public void onStruckByLightning(LightningBoltEntity lightningBolt) { + } + + @Override + public void recalculateSize() { + } + + public static EntityType.Builder build(EntityType.Builder builder) { + @SuppressWarnings("unchecked") + EntityType.Builder entityBuilder = (EntityType.Builder) builder; + return entityBuilder; + } + + @Override + public IPacket createSpawnPacket() { + return NetworkHooks.getEntitySpawningPacket(this); + } + + @Override + public void writeSpawnData(PacketBuffer buffer) { + CompoundNBT compound = new CompoundNBT(); + writeAdditional(compound); + buffer.writeCompoundTag(compound); + } + + @Override + public void readSpawnData(PacketBuffer additionalData) { + readAdditional(additionalData.readCompoundTag()); + } + + public Direction getFacingDirection() { + return facingDirection; + } +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueHandler.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueHandler.java new file mode 100644 index 000000000..239240eae --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueHandler.java @@ -0,0 +1,105 @@ +package com.simibubi.create.modules.contraptions.components.contraptions.glue; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.simibubi.create.AllItems; +import com.simibubi.create.AllPackets; +import com.simibubi.create.foundation.utility.RayTraceWorld; + +import net.minecraft.block.Blocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.Direction; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.math.RayTraceContext; +import net.minecraft.util.math.RayTraceResult.Type; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.IWorld; +import net.minecraft.world.World; +import net.minecraftforge.event.world.BlockEvent.EntityPlaceEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.network.PacketDistributor; + +@EventBusSubscriber +public class SuperGlueHandler { + + public static Map gatherGlue(IWorld world, BlockPos pos) { + List entities = world.getEntitiesWithinAABB(SuperGlueEntity.class, new AxisAlignedBB(pos)); + Map map = new HashMap<>(); + for (SuperGlueEntity entity : entities) + map.put(entity.getAttachedDirection(pos), entity); + return map; + } + + @SubscribeEvent + public static void glueListensForBlockPlacement(EntityPlaceEvent event) { + IWorld world = event.getWorld(); + Entity entity = event.getEntity(); + BlockPos pos = event.getPos(); + + if (entity == null || world == null || pos == null) + return; + if (event.isCanceled()) + return; + if (world.isRemote()) + return; + + Map gatheredGlue = gatherGlue(world, pos); + for (Direction direction : gatheredGlue.keySet()) + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> entity), + new GlueEffectPacket(pos, direction, true)); + + if (entity instanceof PlayerEntity) + glueInOffHandAppliesOnBlockPlace(event, pos, (PlayerEntity) entity); + } + + public static void glueInOffHandAppliesOnBlockPlace(EntityPlaceEvent event, BlockPos pos, PlayerEntity placer) { + ItemStack itemstack = placer.getHeldItemOffhand(); + if (!AllItems.SUPER_GLUE.typeOf(itemstack)) + return; + + double distance = placer.getAttribute(PlayerEntity.REACH_DISTANCE).getValue(); + Vec3d start = placer.getEyePosition(1); + Vec3d look = placer.getLook(1); + Vec3d end = start.add(look.x * distance, look.y * distance, look.z * distance); + World world = placer.world; + + RayTraceWorld rayTraceWorld = + new RayTraceWorld(world, (p, state) -> p.equals(pos) ? Blocks.AIR.getDefaultState() : state); + BlockRayTraceResult ray = rayTraceWorld.rayTraceBlocks(new RayTraceContext(start, end, + RayTraceContext.BlockMode.OUTLINE, RayTraceContext.FluidMode.NONE, placer)); + + Direction face = ray.getFace(); + if (ray == null || face == null || ray.getType() == Type.MISS) + return; + + if (!ray.getPos().offset(face).equals(pos)) { + event.setCanceled(true); + return; + } + + SuperGlueEntity entity = new SuperGlueEntity(world, ray.getPos(), face.getOpposite()); + CompoundNBT compoundnbt = itemstack.getTag(); + if (compoundnbt != null) + EntityType.applyItemNBT(world, placer, entity, compoundnbt); + + if (entity.onValidSurface()) { + if (!world.isRemote) { + entity.playPlaceSound(); + world.addEntity(entity); + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> entity), + new GlueEffectPacket(ray.getPos(), face, true)); + } + itemstack.damageItem(1, placer, SuperGlueItem::onBroken); + } + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueItem.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueItem.java new file mode 100644 index 000000000..d2668b9be --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueItem.java @@ -0,0 +1,104 @@ +package com.simibubi.create.modules.contraptions.components.contraptions.glue; + +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.entity.EntityType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.particles.ItemParticleData; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class SuperGlueItem extends Item { + + public SuperGlueItem(Properties properties) { + super(properties); + } + + @Override + public boolean isDamageable() { + return true; + } + + @Override + public int getMaxDamage(ItemStack stack) { + return 99; + } + + @Override + public int getItemStackLimit(ItemStack stack) { + return 1; + } + + @Override + public ActionResultType onItemUse(ItemUseContext context) { + BlockPos blockpos = context.getPos(); + Direction direction = context.getFace(); + BlockPos blockpos1 = blockpos.offset(direction); + PlayerEntity playerentity = context.getPlayer(); + ItemStack itemstack = context.getItem(); + + if (playerentity != null && !this.canPlace(playerentity, direction, itemstack, blockpos1)) + return ActionResultType.FAIL; + + World world = context.getWorld(); + SuperGlueEntity entity = new SuperGlueEntity(world, blockpos1, direction); + CompoundNBT compoundnbt = itemstack.getTag(); + if (compoundnbt != null) + EntityType.applyItemNBT(world, playerentity, entity, compoundnbt); + + if (!entity.onValidSurface()) + return ActionResultType.FAIL; + + if (!world.isRemote) { + entity.playPlaceSound(); + world.addEntity(entity); + } + itemstack.damageItem(1, playerentity, SuperGlueItem::onBroken); + + return ActionResultType.SUCCESS; + } + + public static void onBroken(PlayerEntity player) { + + } + + protected boolean canPlace(PlayerEntity entity, Direction facing, ItemStack stack, BlockPos pos) { + return !World.isOutsideBuildHeight(pos) && entity.canPlayerEdit(pos, facing, stack); + } + + @OnlyIn(Dist.CLIENT) + public static void spawnParticles(World world, BlockPos pos, Direction direction, boolean fullBlock) { + Vec3d vec = new Vec3d(direction.getDirectionVec()); + Vec3d plane = VecHelper.planeByNormal(vec); + Vec3d facePos = VecHelper.getCenterOf(pos).add(vec.scale(.5f)); + + float distance = fullBlock ? 1f : .25f + .25f * (world.rand.nextFloat() - .5f); + plane = plane.scale(distance); + ItemStack stack = new ItemStack(Items.SLIME_BALL); + + for (int i = fullBlock ? 40 : 15; i > 0; i--) { + Vec3d offset = VecHelper.rotate(plane, 360 * world.rand.nextFloat(), direction.getAxis()); + Vec3d motion = offset.normalize().scale(1 / 16f); + if (fullBlock) + offset = new Vec3d(MathHelper.clamp(offset.x, -.5, .5), MathHelper.clamp(offset.y, -.5, .5), + MathHelper.clamp(offset.z, -.5, .5)); + Vec3d particlePos = facePos.add(offset); + world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), particlePos.x, particlePos.y, + particlePos.z, motion.x, motion.y, motion.z); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueRenderer.java new file mode 100644 index 000000000..45d7cd36b --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/glue/SuperGlueRenderer.java @@ -0,0 +1,123 @@ +package com.simibubi.create.modules.contraptions.components.contraptions.glue; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.vertex.IVertexBuilder; +import com.simibubi.create.AllItems; +import com.simibubi.create.Create; +import com.simibubi.create.config.AllConfigs; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +@OnlyIn(Dist.CLIENT) +public class SuperGlueRenderer extends EntityRenderer { + + private ResourceLocation regular = new ResourceLocation(Create.ID, "textures/entity/super_glue/slime.png"); + private ResourceLocation ghostly = new ResourceLocation(Create.ID, "textures/entity/super_glue/ghostly.png"); + + private Vec3d[] quad1; + private Vec3d[] quad2; + + public SuperGlueRenderer(EntityRendererManager renderManager) { + super(renderManager); + initQuads(); + } + + @Override + public ResourceLocation getEntityTexture(SuperGlueEntity entity) { + return isVisible(entity) ? regular : ghostly; + } + + @Override // TODO what are these floats for? + public void render(SuperGlueEntity entity, float p_225623_2_, float p_225623_3_, MatrixStack ms, + IRenderTypeBuffer buffer, int light) { + super.render(entity, p_225623_2_, p_225623_3_, ms, buffer, light); + IVertexBuilder builder = buffer.getBuffer(RenderType.getEntityCutout(getEntityTexture(entity))); + + PlayerEntity player = Minecraft.getInstance().player; + boolean visible = isVisible(entity); + boolean holdingGlue = AllItems.SUPER_GLUE.typeOf(player.getHeldItemMainhand()) + || AllItems.SUPER_GLUE.typeOf(player.getHeldItemOffhand()); + holdingGlue = holdingGlue && AllConfigs.CLIENT.showHiddenSuperGlue.get(); + + if (!visible && !holdingGlue) + return; + +// GlStateManager.pushMatrix(); TODO find equivalent +// GlStateManager.translated(x, y, z); +// GlStateManager.rotated(AngleHelper.horizontalAngle(facing), 0, 1, 0); +// GlStateManager.rotated(AngleHelper.verticalAngle(facing), 1, 0, 0); +// if (!visible) { +// GlStateManager.color4f(1, 1, 1, 0.375f); +// GlStateManager.enableBlend(); +// GlStateManager.disableDepthTest(); +// } + + // TODO use quad1 & quad2 to render the glue texture + +// GlStateManager.disableBlend(); +// GlStateManager.enableDepthTest(); +// GlStateManager.color4f(1.0F, 1.0F, 1.0F, 1.0F); +// GlStateManager.popMatrix(); + } + + private boolean isVisible(SuperGlueEntity entity) { + if (!entity.isAlive()) + return false; + BlockPos pos = entity.hangingPosition; + BlockPos pos2 = pos.offset(entity.getFacingDirection().getOpposite()); + return entity.world.isAirBlock(pos) != entity.world.isAirBlock(pos2); + } + + private void initQuads() { + Vec3d diff = new Vec3d(Direction.SOUTH.getDirectionVec()); + Vec3d extension = diff.normalize().scale(1 / 32f - 1 / 128f); + Vec3d plane = VecHelper.planeByNormal(diff); + Axis axis = Direction.getFacingFromVector(diff.x, diff.y, diff.z).getAxis(); + + Vec3d start = Vec3d.ZERO.subtract(extension); + Vec3d end = Vec3d.ZERO.add(extension); + + plane = plane.scale(1 / 2f); + Vec3d a1 = plane.add(start); + Vec3d b1 = plane.add(end); + plane = VecHelper.rotate(plane, -90, axis); + Vec3d a2 = plane.add(start); + Vec3d b2 = plane.add(end); + plane = VecHelper.rotate(plane, -90, axis); + Vec3d a3 = plane.add(start); + Vec3d b3 = plane.add(end); + plane = VecHelper.rotate(plane, -90, axis); + Vec3d a4 = plane.add(start); + Vec3d b4 = plane.add(end); + + quad1 = new Vec3d[] { a1, a2, a3, a4 }; + quad2 = new Vec3d[] { b1, b2, b3, b4 }; + +// PositionTextureVertex v11 = new PositionTextureVertex(a1, 1, 0); +// PositionTextureVertex v12 = new PositionTextureVertex(a2, 1, 1); +// PositionTextureVertex v13 = new PositionTextureVertex(a3, 0, 1); +// PositionTextureVertex v14 = new PositionTextureVertex(a4, 0, 0); +// +// PositionTextureVertex v21 = new PositionTextureVertex(b1, 1, 0); +// PositionTextureVertex v22 = new PositionTextureVertex(b2, 1, 1); +// PositionTextureVertex v23 = new PositionTextureVertex(b3, 0, 1); +// PositionTextureVertex v24 = new PositionTextureVertex(b4, 0, 0); +// +// quad1 = new TexturedQuad(new PositionTextureVertex[] { v14, v11, v12, v13 }, 0, 0, 16, 16, 16, 16); +// quad2 = new TexturedQuad(new PositionTextureVertex[] { v21, v24, v23, v22 }, 0, 0, 16, 16, 16, 16); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/CartAssemblerBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/CartAssemblerBlock.java index 18f1c30ba..c9fa6bad1 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/CartAssemblerBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/CartAssemblerBlock.java @@ -1,10 +1,11 @@ package com.simibubi.create.modules.contraptions.components.contraptions.mounted; import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.block.RenderUtilityBlock; import com.simibubi.create.foundation.utility.AllShapes; -import com.simibubi.create.modules.contraptions.components.contraptions.Contraption; import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity; +import com.simibubi.create.modules.contraptions.components.contraptions.mounted.CartAssemblerTileEntity.CartMovementMode; import net.minecraft.block.AbstractRailBlock; import net.minecraft.block.Block; @@ -12,13 +13,16 @@ import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.material.PushReaction; import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.entity.item.minecart.FurnaceMinecartEntity; import net.minecraft.item.BlockItemUseContext; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.BooleanProperty; import net.minecraft.state.EnumProperty; import net.minecraft.state.IProperty; import net.minecraft.state.StateContainer.Builder; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.RailShape; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; @@ -28,7 +32,7 @@ import net.minecraft.util.math.shapes.VoxelShapes; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; -public class CartAssemblerBlock extends AbstractRailBlock { +public class CartAssemblerBlock extends AbstractRailBlock implements ITE { public static IProperty RAIL_SHAPE = EnumProperty.create("shape", RailShape.class, RailShape.EAST_WEST, RailShape.NORTH_SOUTH); @@ -45,6 +49,16 @@ public class CartAssemblerBlock extends AbstractRailBlock { super.fillStateContainer(builder); } + @Override + public boolean hasTileEntity(BlockState state) { + return true; + } + + @Override + public TileEntity createTileEntity(BlockState state, IBlockReader world) { + return new CartAssemblerTileEntity(); + } + @Override public BlockState getStateForPlacement(BlockItemUseContext context) { boolean alongX = context.getPlacementHorizontalFacing().getAxis() == Axis.X; @@ -60,7 +74,7 @@ public class CartAssemblerBlock extends AbstractRailBlock { @Override public void onMinecartPass(BlockState state, World world, BlockPos pos, AbstractMinecartEntity cart) { - if (!cart.canBeRidden()) + if (!cart.canBeRidden() && !(cart instanceof FurnaceMinecartEntity)) return; if (state.get(POWERED)) disassemble(world, pos, cart); @@ -72,16 +86,28 @@ public class CartAssemblerBlock extends AbstractRailBlock { if (!cart.getPassengers().isEmpty()) return; - Contraption contraption = MountedContraption.assembleMinecart(world, pos); + MountedContraption contraption = MountedContraption.assembleMinecart(world, pos); if (contraption == null) return; if (contraption.blocks.size() == 1) return; - float initialAngle = ContraptionEntity.yawFromVector(cart.getMotion()); + + int yawFromVector = (int) (ContraptionEntity.yawFromVector(cart.getMotion()) + .5d); + yawFromVector = ((yawFromVector + 45) / 90) * 90; + float initialAngle = yawFromVector; + + withTileEntityDo(world, pos, te -> contraption.rotationMode = CartMovementMode.values()[te.movementMode.value]); ContraptionEntity entity = ContraptionEntity.createMounted(world, contraption, initialAngle); entity.setPosition(pos.getX(), pos.getY(), pos.getZ()); world.addEntity(entity); entity.startRiding(cart); + + if (cart instanceof FurnaceMinecartEntity) { + CompoundNBT nbt = cart.serializeNBT(); + nbt.putDouble("PushZ", 0); + nbt.putDouble("PushX", 0); + cart.deserializeNBT(nbt); + } } protected void disassemble(World world, BlockPos pos, AbstractMinecartEntity cart) { @@ -90,6 +116,13 @@ public class CartAssemblerBlock extends AbstractRailBlock { if (!(cart.getPassengers().get(0) instanceof ContraptionEntity)) return; cart.removePassengers(); + + if (cart instanceof FurnaceMinecartEntity) { + CompoundNBT nbt = cart.serializeNBT(); + nbt.putDouble("PushZ", cart.getMotion().x); + nbt.putDouble("PushX", cart.getMotion().z); + cart.deserializeNBT(nbt); + } } @Override @@ -129,7 +162,7 @@ public class CartAssemblerBlock extends AbstractRailBlock { public PushReaction getPushReaction(BlockState state) { return PushReaction.BLOCK; } - + @Override public boolean isNormalCube(BlockState state, IBlockReader worldIn, BlockPos pos) { return false; @@ -142,6 +175,13 @@ public class CartAssemblerBlock extends AbstractRailBlock { builder.add(BlockStateProperties.HORIZONTAL_AXIS); super.fillStateContainer(builder); } + + @Override + public VoxelShape getShape(BlockState p_220053_1_, IBlockReader p_220053_2_, BlockPos p_220053_3_, + ISelectionContext p_220053_4_) { + return VoxelShapes.empty(); + } + } public static BlockState createAnchor(BlockState state) { @@ -149,4 +189,9 @@ public class CartAssemblerBlock extends AbstractRailBlock { return AllBlocks.MINECART_ANCHOR.get().getDefaultState().with(BlockStateProperties.HORIZONTAL_AXIS, axis); } + @Override + public Class getTileEntityClass() { + return CartAssemblerTileEntity.class; + } + } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/CartAssemblerTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/CartAssemblerTileEntity.java new file mode 100644 index 000000000..89ae09aa9 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/CartAssemblerTileEntity.java @@ -0,0 +1,65 @@ +package com.simibubi.create.modules.contraptions.components.contraptions.mounted; + +import java.util.List; + +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.ScreenResources; +import com.simibubi.create.foundation.behaviour.CenteredSideValueBoxTransform; +import com.simibubi.create.foundation.behaviour.ValueBoxTransform; +import com.simibubi.create.foundation.behaviour.base.SmartTileEntity; +import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour; +import com.simibubi.create.foundation.behaviour.scrollvalue.INamedIconOptions; +import com.simibubi.create.foundation.behaviour.scrollvalue.ScrollOptionBehaviour; +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.util.Direction; + +public class CartAssemblerTileEntity extends SmartTileEntity { + + protected ScrollOptionBehaviour movementMode; + + public CartAssemblerTileEntity() { + super(AllTileEntities.CART_ASSEMBLER.type); + } + + @Override + public void addBehaviours(List behaviours) { + movementMode = new ScrollOptionBehaviour<>(CartMovementMode.class, + Lang.translate("contraptions.cart_movement_mode"), this, getMovementModeSlot()); + movementMode.requiresWrench(); + behaviours.add(movementMode); + } + + protected ValueBoxTransform getMovementModeSlot() { + return new CenteredSideValueBoxTransform((state, d) -> d == Direction.UP); + } + + public static enum CartMovementMode implements INamedIconOptions { + + ROTATE(ScreenResources.I_CART_ROTATE), + ROTATE_PAUSED(ScreenResources.I_CART_ROTATE_PAUSED), + ROTATION_LOCKED(ScreenResources.I_CART_ROTATE_LOCKED), + + ; + + private String translationKey; + private ScreenResources icon; + + private CartMovementMode(ScreenResources icon) { + this.icon = icon; + translationKey = "contraptions.cart_movement_mode." + Lang.asId(name()); + } + + @Override + public ScreenResources getIcon() { + return icon; + } + + @Override + public String getTranslationKey() { + return translationKey; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/MinecartContraptionItem.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/MinecartContraptionItem.java new file mode 100644 index 000000000..896c8e9de --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/MinecartContraptionItem.java @@ -0,0 +1,215 @@ +package com.simibubi.create.modules.contraptions.components.contraptions.mounted; + +import java.util.List; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllItems; +import com.simibubi.create.modules.contraptions.components.contraptions.Contraption; +import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity; + +import net.minecraft.block.AbstractRailBlock; +import net.minecraft.block.BlockState; +import net.minecraft.block.DispenserBlock; +import net.minecraft.dispenser.DefaultDispenseItemBehavior; +import net.minecraft.dispenser.IBlockSource; +import net.minecraft.dispenser.IDispenseItemBehavior; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.entity.item.minecart.AbstractMinecartEntity.Type; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUseContext; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.state.properties.RailShape; +import net.minecraft.tags.BlockTags; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.NonNullList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class MinecartContraptionItem extends Item { + + private final AbstractMinecartEntity.Type minecartType; + + public MinecartContraptionItem(Type minecartTypeIn, Properties builder) { + super(builder); + this.minecartType = minecartTypeIn; + DispenserBlock.registerDispenseBehavior(this, DISPENSER_BEHAVIOR); + } + + // Taken and adjusted from MinecartItem + private static final IDispenseItemBehavior DISPENSER_BEHAVIOR = new DefaultDispenseItemBehavior() { + private final DefaultDispenseItemBehavior behaviourDefaultDispenseItem = new DefaultDispenseItemBehavior(); + + @Override + public ItemStack dispenseStack(IBlockSource source, ItemStack stack) { + Direction direction = source.getBlockState().get(DispenserBlock.FACING); + World world = source.getWorld(); + double d0 = source.getX() + (double) direction.getXOffset() * 1.125D; + double d1 = Math.floor(source.getY()) + (double) direction.getYOffset(); + double d2 = source.getZ() + (double) direction.getZOffset() * 1.125D; + BlockPos blockpos = source.getBlockPos().offset(direction); + BlockState blockstate = world.getBlockState(blockpos); + RailShape railshape = blockstate.getBlock() instanceof AbstractRailBlock + ? ((AbstractRailBlock) blockstate.getBlock()).getRailDirection(blockstate, world, blockpos, null) + : RailShape.NORTH_SOUTH; + double d3; + if (blockstate.isIn(BlockTags.RAILS)) { + if (railshape.isAscending()) { + d3 = 0.6D; + } else { + d3 = 0.1D; + } + } else { + if (!blockstate.isAir(world, blockpos) || !world.getBlockState(blockpos.down()).isIn(BlockTags.RAILS)) { + return this.behaviourDefaultDispenseItem.dispense(source, stack); + } + + BlockState blockstate1 = world.getBlockState(blockpos.down()); + RailShape railshape1 = blockstate1.getBlock() instanceof AbstractRailBlock + ? ((AbstractRailBlock) blockstate1.getBlock()).getRailDirection(blockstate1, world, + blockpos.down(), null) + : RailShape.NORTH_SOUTH; + if (direction != Direction.DOWN && railshape1.isAscending()) { + d3 = -0.4D; + } else { + d3 = -0.9D; + } + } + + AbstractMinecartEntity abstractminecartentity = AbstractMinecartEntity.create(world, d0, d1 + d3, d2, + ((MinecartContraptionItem) stack.getItem()).minecartType); + if (stack.hasDisplayName()) + abstractminecartentity.setCustomName(stack.getDisplayName()); + world.addEntity(abstractminecartentity); + addContraptionToMinecart(world, stack, abstractminecartentity, direction); + + stack.shrink(1); + return stack; + } + + @Override + protected void playDispenseSound(IBlockSource source) { + source.getWorld().playEvent(1000, source.getBlockPos(), 0); + } + }; + + // Taken and adjusted from MinecartItem + @Override + public ActionResultType onItemUse(ItemUseContext context) { + World world = context.getWorld(); + BlockPos blockpos = context.getPos(); + BlockState blockstate = world.getBlockState(blockpos); + if (!blockstate.isIn(BlockTags.RAILS)) { + return ActionResultType.FAIL; + } else { + ItemStack itemstack = context.getItem(); + if (!world.isRemote) { + RailShape railshape = blockstate.getBlock() instanceof AbstractRailBlock + ? ((AbstractRailBlock) blockstate.getBlock()).getRailDirection(blockstate, world, blockpos, + null) + : RailShape.NORTH_SOUTH; + double d0 = 0.0D; + if (railshape.isAscending()) { + d0 = 0.5D; + } + + AbstractMinecartEntity abstractminecartentity = AbstractMinecartEntity.create(world, + (double) blockpos.getX() + 0.5D, (double) blockpos.getY() + 0.0625D + d0, + (double) blockpos.getZ() + 0.5D, this.minecartType); + if (itemstack.hasDisplayName()) + abstractminecartentity.setCustomName(itemstack.getDisplayName()); + PlayerEntity player = context.getPlayer(); + world.addEntity(abstractminecartentity); + addContraptionToMinecart(world, itemstack, abstractminecartentity, + player == null ? null : player.getHorizontalFacing()); + } + + itemstack.shrink(1); + return ActionResultType.SUCCESS; + } + } + + public static void addContraptionToMinecart(World world, ItemStack itemstack, AbstractMinecartEntity cart, + @Nullable Direction newFacing) { + CompoundNBT tag = itemstack.getOrCreateTag(); + if (tag.contains("Contraption")) { + CompoundNBT contraptionTag = tag.getCompound("Contraption"); + float initialAngle = contraptionTag.getFloat("InitialAngle"); + Contraption mountedContraption = Contraption.fromNBT(world, contraptionTag); + ContraptionEntity contraption; + + if (newFacing != null) + contraption = ContraptionEntity.createMounted(world, mountedContraption, initialAngle, newFacing); + else + contraption = ContraptionEntity.createMounted(world, mountedContraption, initialAngle); + + contraption.startRiding(cart); + contraption.setPosition(cart.getX(), cart.getY(), cart.getZ()); + world.addEntity(contraption); + } + } + + @Override + public String getTranslationKey(ItemStack stack) { + return "item.create.minecart_contraption"; + } + + @Override + public void fillItemGroup(ItemGroup group, NonNullList items) { + } + + @SubscribeEvent + public static void wrenchCanBeUsedToPickUpMinecartContraptions(PlayerInteractEvent.EntityInteract event) { + Entity entity = event.getTarget(); + PlayerEntity player = event.getPlayer(); + if (player == null || entity == null) + return; + + ItemStack wrench = player.getHeldItem(event.getHand()); + if (!AllItems.WRENCH.typeOf(wrench)) + return; + if (entity instanceof ContraptionEntity) + entity = entity.getRidingEntity(); + if (!(entity instanceof AbstractMinecartEntity)) + return; + AbstractMinecartEntity cart = (AbstractMinecartEntity) entity; + Type type = cart.getMinecartType(); + if (type != Type.RIDEABLE && type != Type.FURNACE) + return; + List passengers = cart.getPassengers(); + if (passengers.isEmpty() || !(passengers.get(0) instanceof ContraptionEntity)) + return; + ContraptionEntity contraption = (ContraptionEntity) passengers.get(0); + + if (!event.getWorld().isRemote) { + player.inventory.placeItemBackInInventory(event.getWorld(), create(type, contraption)); + contraption.remove(); + entity.remove(); + } + + event.setCancellationResult(ActionResultType.SUCCESS); + event.setCanceled(true); + } + + public static ItemStack create(Type type, ContraptionEntity entity) { + ItemStack stack = + (type == Type.RIDEABLE ? AllItems.MINECART_CONTRAPTION : AllItems.FURNACE_MINECART_CONTRAPTION).asStack(); + CompoundNBT tag = entity.getContraption().writeNBT(); + tag.remove("UUID"); + tag.remove("Pos"); + tag.remove("Motion"); + tag.putFloat("InitialAngle", entity.getInitialAngle()); + stack.getOrCreateTag().put("Contraption", tag); + return stack; + } + +} diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/MountedContraption.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/MountedContraption.java index 1dd193592..0c4b56ca0 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/MountedContraption.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/mounted/MountedContraption.java @@ -7,10 +7,14 @@ import java.util.List; import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.AllBlocks; +import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.modules.contraptions.components.contraptions.AllContraptionTypes; +import com.simibubi.create.modules.contraptions.components.contraptions.BlockMovementTraits; import com.simibubi.create.modules.contraptions.components.contraptions.Contraption; +import com.simibubi.create.modules.contraptions.components.contraptions.mounted.CartAssemblerTileEntity.CartMovementMode; import net.minecraft.block.BlockState; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.RailShape; import net.minecraft.tileentity.TileEntity; @@ -25,12 +29,14 @@ import net.minecraft.world.gen.feature.template.Template.BlockInfo; public class MountedContraption extends Contraption { + public CartMovementMode rotationMode; + @Override protected AllContraptionTypes getType() { return AllContraptionTypes.MOUNTED; } - public static Contraption assembleMinecart(World world, BlockPos pos) { + public static MountedContraption assembleMinecart(World world, BlockPos pos) { if (isFrozen()) return null; @@ -38,7 +44,7 @@ public class MountedContraption extends Contraption { if (!state.has(RAIL_SHAPE)) return null; - Contraption contraption = new MountedContraption(); + MountedContraption contraption = new MountedContraption(); if (!contraption.searchMovedStructure(world, pos, null)) return null; @@ -61,8 +67,14 @@ public class MountedContraption extends Contraption { if (!AllBlocks.CART_ASSEMBLER.typeOf(state)) return false; Axis axis = state.get(CartAssemblerBlock.RAIL_SHAPE) == RailShape.EAST_WEST ? Axis.Z : Axis.X; - for (AxisDirection axisDirection : AxisDirection.values()) - frontier.add(pos.offset(Direction.getFacingFromAxis(axisDirection, axis))); + for (AxisDirection axisDirection : AxisDirection.values()) { + Direction facingFromAxis = Direction.getFacingFromAxis(axisDirection, axis); + BlockPos offset = pos.offset(facingFromAxis); + BlockState blockState = world.getBlockState(offset); + if (!BlockMovementTraits.isBrittle(blockState) + || BlockMovementTraits.isBlockAttachedTowards(blockState, facingFromAxis.getOpposite())) + frontier.add(offset); + } return true; } @@ -76,14 +88,27 @@ public class MountedContraption extends Contraption { return pair; } + @Override + public CompoundNBT writeNBT() { + CompoundNBT writeNBT = super.writeNBT(); + writeNBT.putString("RotationMode", NBTHelper.writeEnum(rotationMode)); + return writeNBT; + } + + @Override + public void readNBT(World world, CompoundNBT nbt) { + rotationMode = NBTHelper.readEnum(nbt.getString("RotationMode"), CartMovementMode.class); + super.readNBT(world, nbt); + } + @Override public void removeBlocksFromWorld(IWorld world, BlockPos offset) { super.removeBlocksFromWorld(world, offset, (pos, state) -> pos.equals(anchor)); } @Override - public void disassemble(World world, BlockPos offset, Vec3d rotation) { - super.disassemble(world, offset, rotation, (pos, state) -> AllBlocks.MINECART_ANCHOR.typeOf(state)); + public void addBlocksToWorld(World world, BlockPos offset, Vec3d rotation) { + super.addBlocksToWorld(world, offset, rotation, (pos, state) -> AllBlocks.MINECART_ANCHOR.typeOf(state)); } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/LinearActuatorTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/LinearActuatorTileEntity.java index 4642683f8..394fd07af 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/LinearActuatorTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/LinearActuatorTileEntity.java @@ -293,8 +293,10 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme @Override public void attach(ContraptionEntity contraption) { this.movedContraption = contraption; - if (!world.isRemote) + if (!world.isRemote) { + this.running = true; sendData(); + } } @Override diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/MechanicalPistonTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/MechanicalPistonTileEntity.java index 7dda90f67..b71d5cdc2 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/MechanicalPistonTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/MechanicalPistonTileEntity.java @@ -42,6 +42,9 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity { @Override public void assemble() { + if (!(world.getBlockState(pos).getBlock() instanceof MechanicalPistonBlock)) + return; + Direction direction = getBlockState().get(BlockStateProperties.FACING); // Collect Construct @@ -83,10 +86,11 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity { @Override public void disassemble() { - if (!running) + if (!running && movedContraption == null) return; if (!removed) - getWorld().setBlockState(pos, getBlockState().with(MechanicalPistonBlock.STATE, PistonState.EXTENDED), 3); + getWorld().setBlockState(pos, getBlockState().with(MechanicalPistonBlock.STATE, PistonState.EXTENDED), + 3 | 16); if (movedContraption != null) { applyContraptionPosition(); movedContraption.disassemble(); diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/MechanicalPistonTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/MechanicalPistonTileEntityRenderer.java index ba99c37db..4f7813301 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/MechanicalPistonTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/MechanicalPistonTileEntityRenderer.java @@ -6,7 +6,6 @@ import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.base.KineticTileEntityRenderer; import net.minecraft.block.BlockState; -import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; import net.minecraft.state.properties.BlockStateProperties; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/PistonContraption.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/PistonContraption.java index cb2118760..947321a0d 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/PistonContraption.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/piston/PistonContraption.java @@ -13,9 +13,11 @@ import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.AllBlocks; import com.simibubi.create.config.AllConfigs; import com.simibubi.create.foundation.utility.NBTHelper; +import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.modules.contraptions.components.contraptions.AllContraptionTypes; import com.simibubi.create.modules.contraptions.components.contraptions.BlockMovementTraits; import com.simibubi.create.modules.contraptions.components.contraptions.Contraption; +import com.simibubi.create.modules.contraptions.components.contraptions.glue.SuperGlueEntity; import com.simibubi.create.modules.contraptions.components.contraptions.piston.MechanicalPistonBlock.PistonState; import net.minecraft.block.BlockState; @@ -63,17 +65,24 @@ public class PistonContraption extends Contraption { BlockPos actualStart = pos; BlockState nextBlock = world.getBlockState(actualStart.offset(direction)); int extensionsInFront = 0; - boolean sticky = STICKY_MECHANICAL_PISTON.typeOf(world.getBlockState(pos)); + BlockState blockState = world.getBlockState(pos); + boolean sticky = STICKY_MECHANICAL_PISTON.typeOf(blockState); - if (world.getBlockState(pos).get(MechanicalPistonBlock.STATE) == PistonState.EXTENDED) { + if (!(blockState.getBlock() instanceof MechanicalPistonBlock)) + return false; + + if (blockState.get(MechanicalPistonBlock.STATE) == PistonState.EXTENDED) { while (PISTON_POLE.typeOf(nextBlock) && nextBlock.get(FACING).getAxis() == direction.getAxis() || MECHANICAL_PISTON_HEAD.typeOf(nextBlock) && nextBlock.get(FACING) == direction) { actualStart = actualStart.offset(direction); poles.add(new BlockInfo(actualStart, nextBlock.with(FACING, direction), null)); extensionsInFront++; - nextBlock = world.getBlockState(actualStart.offset(direction)); + if (MECHANICAL_PISTON_HEAD.typeOf(nextBlock)) + break; + + nextBlock = world.getBlockState(actualStart.offset(direction)); if (extensionsInFront > MechanicalPistonBlock.maxAllowedPistonPoles()) return false; } @@ -122,6 +131,11 @@ public class PistonContraption extends Contraption { return true; } + @Override + protected boolean isAnchoringBlockAt(BlockPos pos) { + return pistonExtensionCollisionBox.contains(VecHelper.getCenterOf(pos.subtract(anchor))); + } + @Override protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, List frontier) { frontier.clear(); @@ -138,6 +152,8 @@ public class PistonContraption extends Contraption { if (!BlockMovementTraits.movementNecessary(world, currentPos)) return true; BlockState state = world.getBlockState(currentPos); + if (BlockMovementTraits.isBrittle(state)) + return true; if (AllBlocks.MECHANICAL_PISTON_HEAD.typeOf(state) && state.get(FACING) == direction.getOpposite()) return true; if (!BlockMovementTraits.movementAllowed(world, currentPos)) @@ -146,7 +162,7 @@ public class PistonContraption extends Contraption { if (BlockMovementTraits.notSupportive(state, orientation)) return true; } - return false; // too many + return true; } @Override @@ -155,8 +171,17 @@ public class PistonContraption extends Contraption { } @Override - public void disassemble(World world, BlockPos offset, Vec3d rotation) { - super.disassemble(world, offset, rotation, (pos, state) -> { + public void addGlue(SuperGlueEntity entity) { + BlockPos pos = entity.getHangingPosition(); + Direction direction = entity.getFacingDirection(); + BlockPos localPos = pos.subtract(anchor).offset(orientation, -initialExtensionProgress); + this.superglue.add(Pair.of(localPos, direction)); + glueToRemove.add(entity); + } + + @Override + public void addBlocksToWorld(World world, BlockPos offset, Vec3d rotation) { + super.addBlocksToWorld(world, offset, rotation, (pos, state) -> { BlockPos pistonPos = anchor.offset(orientation, -1); BlockState pistonState = world.getBlockState(pistonPos); TileEntity te = world.getTileEntity(pistonPos); @@ -165,7 +190,7 @@ public class PistonContraption extends Contraption { return true; if (!AllBlocks.PISTON_POLE.typeOf(state) && pistonState.getBlock() instanceof MechanicalPistonBlock) world.setBlockState(pistonPos, pistonState.with(MechanicalPistonBlock.STATE, PistonState.RETRACTED), - 3); + 3 | 16); return true; } return false; @@ -178,7 +203,7 @@ public class PistonContraption extends Contraption { BlockPos pistonPos = anchor.offset(orientation, -1); BlockState blockState = world.getBlockState(pos); if (pos.equals(pistonPos) && blockState.getBlock() instanceof MechanicalPistonBlock) { - world.setBlockState(pos, blockState.with(MechanicalPistonBlock.STATE, PistonState.MOVING), 66); + world.setBlockState(pos, blockState.with(MechanicalPistonBlock.STATE, PistonState.MOVING), 66 | 16); return true; } return false; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/pulley/PulleyBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/pulley/PulleyBlock.java index 8b0fa38e2..9d626101e 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/pulley/PulleyBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/pulley/PulleyBlock.java @@ -1,6 +1,5 @@ package com.simibubi.create.modules.contraptions.components.contraptions.pulley; -import com.simibubi.create.AllBlocks; import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.utility.AllShapes; import com.simibubi.create.modules.contraptions.base.HorizontalAxisKineticBlock; @@ -8,6 +7,7 @@ import com.simibubi.create.modules.contraptions.base.HorizontalAxisKineticBlock; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; +import net.minecraft.block.material.PushReaction; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.state.EnumProperty; import net.minecraft.state.properties.BlockStateProperties; @@ -42,6 +42,17 @@ public class PulleyBlock extends HorizontalAxisKineticBlock implements ITE anchor.getY() + initialOffset + 1) + return false; + return true; + } + @Override public CompoundNBT writeNBT() { CompoundNBT writeNBT = super.writeNBT(); diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/pulley/PulleyTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/pulley/PulleyTileEntity.java index d65f0a5f3..a751277d4 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/pulley/PulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/contraptions/pulley/PulleyTileEntity.java @@ -37,6 +37,8 @@ public class PulleyTileEntity extends LinearActuatorTileEntity { @Override protected void assemble() { + if (!(world.getBlockState(pos).getBlock() instanceof PulleyBlock)) + return; if (speed == 0) return; if (offset >= getExtensionRange() && getSpeed() > 0) @@ -81,7 +83,7 @@ public class PulleyTileEntity extends LinearActuatorTileEntity { @Override public void disassemble() { - if (!running) + if (!running && movedContraption == null) return; offset = getGridOffset(offset); if (movedContraption != null) @@ -137,6 +139,8 @@ public class PulleyTileEntity extends LinearActuatorTileEntity { BlockPos posBelow = pos.down((int) (offset + getMovementSpeed()) + 1); if (!BlockMovementTraits.movementNecessary(world, posBelow)) return; + if (BlockMovementTraits.isBrittle(world.getBlockState(posBelow))) + return; disassemble(); assembleNextTick = true; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/ConnectedInputHandler.java b/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/ConnectedInputHandler.java index 7133fb0fd..672579ef3 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/ConnectedInputHandler.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/ConnectedInputHandler.java @@ -6,6 +6,7 @@ import static com.simibubi.create.modules.contraptions.base.HorizontalKineticBlo import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; @@ -137,8 +138,8 @@ public class ConnectedInputHandler { if (controllerPos1.equals(controllerPos2)) { MechanicalCrafterTileEntity controller = CrafterHelper.getCrafter(world, controllerPos1); - Set positions = controller.input.data.stream().map(l -> controllerPos1.add(l)) - .collect(Collectors.toSet()); + Set positions = + controller.input.data.stream().map(l -> controllerPos1.add(l)).collect(Collectors.toSet()); List frontier = new LinkedList<>(); List splitGroup = new ArrayList<>(); @@ -198,8 +199,7 @@ public class ConnectedInputHandler { crafter1.input.data.forEach(offset -> { BlockPos connectedPos = crafter1.getPos().add(offset); - modifyAndUpdate(world, connectedPos, input -> { - }); + modifyAndUpdate(world, connectedPos, input -> {}); }); crafter2.input.data.forEach(offset -> { @@ -229,7 +229,7 @@ public class ConnectedInputHandler { public static class ConnectedInput { boolean isController; - List data = new ArrayList<>(); + List data = Collections.synchronizedList(new ArrayList<>()); public ConnectedInput() { isController = true; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/MechanicalCrafterTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/MechanicalCrafterTileEntity.java index 0a538eb5b..f9be57d87 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/MechanicalCrafterTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/MechanicalCrafterTileEntity.java @@ -20,6 +20,7 @@ import com.simibubi.create.modules.contraptions.components.crafter.MechanicalCra import com.simibubi.create.modules.contraptions.components.crafter.RecipeGridHandler.GroupedItems; import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; +import net.minecraft.block.BlockState; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; @@ -357,8 +358,10 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity { } public void eject() { - Vec3d ejectPos = VecHelper.getCenterOf(pos) - .add(new Vec3d(getBlockState().get(HORIZONTAL_FACING).getDirectionVec()).scale(.75f)); + BlockState blockState = getBlockState(); + boolean present = AllBlocks.MECHANICAL_CRAFTER.typeOf(blockState); + Vec3d vec = present ? new Vec3d(blockState.get(HORIZONTAL_FACING).getDirectionVec()).scale(.75f) : Vec3d.ZERO; + Vec3d ejectPos = VecHelper.getCenterOf(pos).add(vec); groupedItems.grid.forEach((pair, stack) -> dropItem(ejectPos, stack)); if (!inventory.getStackInSlot(0).isEmpty()) dropItem(ejectPos, inventory.getStackInSlot(0)); diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/MechanicalCrafterTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/MechanicalCrafterTileEntityRenderer.java index 67df7f724..577bb20b5 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/MechanicalCrafterTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/crafter/MechanicalCrafterTileEntityRenderer.java @@ -19,7 +19,6 @@ import com.simibubi.create.modules.contraptions.components.crafter.RecipeGridHan import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.Vector3f; import net.minecraft.client.renderer.WorldRenderer; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerHandler.java b/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerHandler.java index aa14c55dd..77ec4d990 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerHandler.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerHandler.java @@ -15,6 +15,7 @@ import com.simibubi.create.modules.curiosities.tools.SandPaperItem; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.material.Material; +import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.item.ItemEntity; @@ -113,10 +114,10 @@ public class DeployerHandler { // Check for entities final ServerWorld world = player.getServerWorld(); - List entities = world.getEntitiesWithinAABB(LivingEntity.class, new AxisAlignedBB(clickedPos)); + List entities = world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(clickedPos)); Hand hand = Hand.MAIN_HAND; if (!entities.isEmpty()) { - LivingEntity entity = entities.get(world.rand.nextInt(entities.size())); + Entity entity = entities.get(world.rand.nextInt(entities.size())); List capturedDrops = new ArrayList<>(); boolean success = false; entity.captureDrops(capturedDrops); @@ -131,7 +132,8 @@ public class DeployerHandler { if (cancelResult == null) { if (entity.processInitialInteract(player, hand)) success = true; - else if (stack.interactWithEntity(player, entity, hand)) + else if (entity instanceof LivingEntity + && stack.interactWithEntity(player, (LivingEntity) entity, hand)) success = true; } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerTileEntity.java index 0087f8eda..204b5c8b1 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/deployer/DeployerTileEntity.java @@ -42,8 +42,8 @@ import net.minecraft.util.math.RayTraceContext.FluidMode; import net.minecraft.util.math.Vec3d; import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.Constants.NBT; +import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/components/saw/SawTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/components/saw/SawTileEntity.java index fb695c9f8..34c08729e 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/components/saw/SawTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/components/saw/SawTileEntity.java @@ -24,7 +24,15 @@ import com.simibubi.create.modules.contraptions.components.actors.BlockBreakingK import com.simibubi.create.modules.contraptions.processing.ProcessingInventory; import com.simibubi.create.modules.contraptions.relays.belt.BeltTileEntity; +import net.minecraft.block.BambooBlock; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.block.CactusBlock; +import net.minecraft.block.ChorusPlantBlock; +import net.minecraft.block.KelpBlock; +import net.minecraft.block.KelpTopBlock; +import net.minecraft.block.StemGrownBlock; +import net.minecraft.block.SugarCaneBlock; import net.minecraft.entity.item.ItemEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; @@ -379,7 +387,29 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity { @Override public boolean canBreak(BlockState stateToBreak, float blockHardness) { - return super.canBreak(stateToBreak, blockHardness) && stateToBreak.isIn(BlockTags.LOGS); + boolean sawable = isSawable(stateToBreak); + return super.canBreak(stateToBreak, blockHardness) && sawable; + } + + public static boolean isSawable(BlockState stateToBreak) { + if (stateToBreak.isIn(BlockTags.LOGS) || stateToBreak.isIn(BlockTags.LEAVES)) + return true; + Block block = stateToBreak.getBlock(); + if (block instanceof BambooBlock) + return true; + if (block instanceof StemGrownBlock) + return true; + if (block instanceof CactusBlock) + return true; + if (block instanceof SugarCaneBlock) + return true; + if (block instanceof KelpBlock) + return true; + if (block instanceof KelpTopBlock) + return true; + if (block instanceof ChorusPlantBlock) + return true; + return false; } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/particle/RotationIndicatorParticle.java b/src/main/java/com/simibubi/create/modules/contraptions/particle/RotationIndicatorParticle.java index c2b967fa4..fd83dcf91 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/particle/RotationIndicatorParticle.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/particle/RotationIndicatorParticle.java @@ -13,7 +13,6 @@ import net.minecraft.client.particle.IParticleFactory; import net.minecraft.client.particle.Particle; import net.minecraft.client.particle.SimpleAnimatedParticle; import net.minecraft.client.renderer.ActiveRenderInfo; -import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java index fa05ef4f6..cb698c3ee 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java @@ -87,14 +87,15 @@ public class SequencedGearshiftBlock extends HorizontalAxisKineticBlock implemen return ActionResultType.PASS; } - if (player instanceof ClientPlayerEntity) - DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> withTileEntityDo(worldIn, pos, this::displayScreen)); + DistExecutor.runWhenOn(Dist.CLIENT, + () -> () -> withTileEntityDo(worldIn, pos, te -> this.displayScreen(te, player))); return ActionResultType.SUCCESS; } @OnlyIn(value = Dist.CLIENT) - protected void displayScreen(SequencedGearshiftTileEntity te) { - ScreenOpener.open(new SequencedGearshiftScreen(te)); + protected void displayScreen(SequencedGearshiftTileEntity te, PlayerEntity player) { + if (player instanceof ClientPlayerEntity) + ScreenOpener.open(new SequencedGearshiftScreen(te)); } @Override diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java index b50f20dbd..26453997c 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/advanced/sequencer/SequencedGearshiftTileEntity.java @@ -50,6 +50,8 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { Instruction instruction = getInstruction(currentInstruction); if (instruction == null) return; + if (getSpeed() == 0) + run(-1); // Update instruction time with regards to new speed float initialProgress = timer / (float) currentInstructionDuration; @@ -68,6 +70,8 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { world.setBlockState(pos, getBlockState().with(SequencedGearshiftBlock.STATE, 0), 3); return; } + if (getSpeed() == 0) + return; run(0); } @@ -122,6 +126,8 @@ public class SequencedGearshiftTileEntity extends SplitShaftTileEntity { } public int getModifier() { + if (currentInstruction >= instructions.size()) + return 0; return isIdle() ? 0 : instructions.get(currentInstruction).getSpeedModifier(); } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltBlock.java index e64f8317b..df09e99a3 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltBlock.java @@ -416,9 +416,9 @@ public class BeltBlock extends HorizontalKineticBlock // Init belts int index = 0; - List beltChain = getBeltChain(world, pos); + List beltChain = getBeltChain(world, currentPos); if (beltChain.size() < 2) { - world.destroyBlock(pos, true); + world.destroyBlock(currentPos, true); return; } @@ -426,7 +426,7 @@ public class BeltBlock extends HorizontalKineticBlock TileEntity tileEntity = world.getTileEntity(beltPos); if (tileEntity instanceof BeltTileEntity) { BeltTileEntity te = (BeltTileEntity) tileEntity; - te.setController(pos); + te.setController(currentPos); te.beltLength = beltChain.size(); te.index = index; te.attachKinetics(); @@ -444,7 +444,7 @@ public class BeltBlock extends HorizontalKineticBlock if (te.isController() && isVertical) te.getInventory().ejectAll(); } else { - world.destroyBlock(pos, true); + world.destroyBlock(currentPos, true); return; } index++; diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntity.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntity.java index 1842a17d2..18b546483 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/BeltTileEntity.java @@ -66,11 +66,6 @@ public class BeltTileEntity extends KineticTileEntity { color = -1; } - @Override - public void initialize() { - super.initialize(); - } - @Override public void tick() { super.tick(); @@ -164,7 +159,9 @@ public class BeltTileEntity extends KineticTileEntity { @Override public CompoundNBT write(CompoundNBT compound) { attachmentTracker.write(compound); - compound.put("Controller", NBTUtil.writeBlockPos(controller)); + + if (controller != null) + compound.put("Controller", NBTUtil.writeBlockPos(controller)); compound.putBoolean("IsController", isController()); compound.putInt("Color", color); compound.putInt("Length", beltLength); @@ -178,21 +175,32 @@ public class BeltTileEntity extends KineticTileEntity { @Override public void read(CompoundNBT compound) { super.read(compound); + if (compound.getBoolean("IsController")) controller = pos; - else - controller = NBTUtil.readBlockPos(compound.getCompound("Controller")); - if (!compound.contains("DontClearAttachments")) + if (!wasMoved) { + if (!isController()) + controller = NBTUtil.readBlockPos(compound.getCompound("Controller")); trackerUpdateTag = compound; - color = compound.getInt("Color"); - beltLength = compound.getInt("Length"); - index = compound.getInt("Index"); + color = compound.getInt("Color"); + beltLength = compound.getInt("Length"); + index = compound.getInt("Index"); + } if (isController()) getInventory().read(compound.getCompound("Inventory")); } + @Override + public void clearKineticInformation() { + super.clearKineticInformation(); + beltLength = 0; + index = 0; + controller = null; + trackerUpdateTag = new CompoundNBT(); + } + public void applyColor(DyeColor colorIn) { int colorValue = colorIn.getMapColor().colorValue; for (BlockPos blockPos : BeltBlock.getBeltChain(world, getController())) { @@ -206,6 +214,8 @@ public class BeltTileEntity extends KineticTileEntity { } public BeltTileEntity getControllerTE() { + if (controller == null) + return null; if (!world.isBlockPresent(controller)) return null; TileEntity te = world.getTileEntity(controller); @@ -219,11 +229,11 @@ public class BeltTileEntity extends KineticTileEntity { } public BlockPos getController() { - return controller; + return controller == null ? pos : controller; } public boolean isController() { - return controller.equals(pos); + return pos.equals(controller); } public float getBeltMovementSpeed() { diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/item/BeltConnectorItem.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/item/BeltConnectorItem.java index e70f9edfc..fe4b44830 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/item/BeltConnectorItem.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/belt/item/BeltConnectorItem.java @@ -71,7 +71,7 @@ public class BeltConnectorItem extends BlockItem implements IAddedByOther { if (!canConnect(world, firstPulley, pos)) return ActionResultType.FAIL; - if (!firstPulley.equals(pos)) { + if (firstPulley != null && !firstPulley.equals(pos)) { createBelts(world, firstPulley, pos); if (!context.getPlayer().isCreative()) diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/encased/ClutchBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/encased/ClutchBlock.java index 824e5f7dc..07e9a48e8 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/encased/ClutchBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/encased/ClutchBlock.java @@ -1,8 +1,5 @@ package com.simibubi.create.modules.contraptions.relays.encased; -import com.simibubi.create.modules.contraptions.RotationPropagator; -import com.simibubi.create.modules.contraptions.base.KineticTileEntity; - import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.tileentity.TileEntity; @@ -26,13 +23,7 @@ public class ClutchBlock extends GearshiftBlock { boolean previouslyPowered = state.get(POWERED); if (previouslyPowered != worldIn.isBlockPowered(pos)) { worldIn.setBlockState(pos, state.cycle(POWERED), 2 | 16); - TileEntity te = worldIn.getTileEntity(pos); - if (te == null || !(te instanceof KineticTileEntity)) - return; - if (previouslyPowered) - RotationPropagator.handleAdded(worldIn, pos, (KineticTileEntity) te); - else - RotationPropagator.handleRemoved(worldIn, pos, (KineticTileEntity) te); + detachKinetics(worldIn, pos, previouslyPowered); } } diff --git a/src/main/java/com/simibubi/create/modules/contraptions/relays/encased/GearshiftBlock.java b/src/main/java/com/simibubi/create/modules/contraptions/relays/encased/GearshiftBlock.java index f9e6eb079..c9e17daea 100644 --- a/src/main/java/com/simibubi/create/modules/contraptions/relays/encased/GearshiftBlock.java +++ b/src/main/java/com/simibubi/create/modules/contraptions/relays/encased/GearshiftBlock.java @@ -1,7 +1,10 @@ package com.simibubi.create.modules.contraptions.relays.encased; +import java.util.Random; + import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.modules.contraptions.RotationPropagator; +import com.simibubi.create.modules.contraptions.base.KineticTileEntity; import com.simibubi.create.modules.contraptions.relays.gearbox.GearshiftTileEntity; import net.minecraft.block.Block; @@ -15,7 +18,9 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.IWorldReader; +import net.minecraft.world.TickPriority; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; public class GearshiftBlock extends EncasedShaftBlock implements ITE { @@ -51,7 +56,7 @@ public class GearshiftBlock extends EncasedShaftBlock implements ITE RotationPropagator.handleRemoved(worldIn, pos, te)); + detachKinetics(worldIn, pos, true); worldIn.setBlockState(pos, state.cycle(POWERED), 2); } } @@ -65,4 +70,24 @@ public class GearshiftBlock extends EncasedShaftBlock implements ITE () -> withTileEntityDo(worldIn, pos, this::displayScreen)); + DistExecutor.runWhenOn(Dist.CLIENT, + () -> () -> withTileEntityDo(worldIn, pos, te -> this.displayScreen(te, player))); return ActionResultType.SUCCESS; } @OnlyIn(value = Dist.CLIENT) - protected void displayScreen(StockswitchTileEntity te) { - ScreenOpener.open(new StockswitchScreen(te)); + protected void displayScreen(StockswitchTileEntity te, PlayerEntity player) { + if (player instanceof ClientPlayerEntity) + ScreenOpener.open(new StockswitchScreen(te)); } @Override diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/belts/tunnel/BeltTunnelTileEntityRenderer.java b/src/main/java/com/simibubi/create/modules/logistics/block/belts/tunnel/BeltTunnelTileEntityRenderer.java index 99d623c12..67a10ce65 100644 --- a/src/main/java/com/simibubi/create/modules/logistics/block/belts/tunnel/BeltTunnelTileEntityRenderer.java +++ b/src/main/java/com/simibubi/create/modules/logistics/block/belts/tunnel/BeltTunnelTileEntityRenderer.java @@ -7,7 +7,6 @@ import com.simibubi.create.foundation.block.SafeTileEntityRenderer; import com.simibubi.create.foundation.utility.ColorHelper; import com.simibubi.create.foundation.utility.SuperByteBuffer; -import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.RenderType; diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/diodes/PulseRepeaterBlock.java b/src/main/java/com/simibubi/create/modules/logistics/block/diodes/PulseRepeaterBlock.java index 118e9f15c..0fb7af6e1 100644 --- a/src/main/java/com/simibubi/create/modules/logistics/block/diodes/PulseRepeaterBlock.java +++ b/src/main/java/com/simibubi/create/modules/logistics/block/diodes/PulseRepeaterBlock.java @@ -12,7 +12,6 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.TickPriority; -import net.minecraft.world.World; import net.minecraft.world.server.ServerWorld; public class PulseRepeaterBlock extends RedstoneDiodeBlock { diff --git a/src/main/java/com/simibubi/create/modules/logistics/block/inventories/FlexcrateScreen.java b/src/main/java/com/simibubi/create/modules/logistics/block/inventories/FlexcrateScreen.java index f857ba3b6..49557fe03 100644 --- a/src/main/java/com/simibubi/create/modules/logistics/block/inventories/FlexcrateScreen.java +++ b/src/main/java/com/simibubi/create/modules/logistics/block/inventories/FlexcrateScreen.java @@ -107,6 +107,10 @@ public class FlexcrateScreen extends AbstractSimiContainerScreen= 0) lastModification++; @@ -114,7 +118,7 @@ public class FlexcrateScreen extends AbstractSimiContainerScreen blocks; + private Map tileEntities; private Cuboid bounds; public BlockPos anchor; + public boolean renderMode; - public SchematicWorld(Map blocks, Cuboid bounds, BlockPos anchor, World original) { + public SchematicWorld(BlockPos anchor, World original) { super(original); - this.blocks = blocks; - this.setBounds(bounds); + this.blocks = new HashMap<>(); + this.tileEntities = new HashMap<>(); + this.bounds = new Cuboid(); this.anchor = anchor; } @@ -45,6 +49,19 @@ public class SchematicWorld extends WrappedWorld { @Override public TileEntity getTileEntity(BlockPos pos) { + if (isOutsideBuildHeight(pos)) + return null; + if (tileEntities.containsKey(pos)) + return tileEntities.get(pos); + if (!blocks.containsKey(pos.subtract(anchor))) + return null; + + BlockState blockState = getBlockState(pos); + if (blockState.hasTileEntity()) { + TileEntity tileEntity = blockState.createTileEntity(this); + tileEntities.put(pos, tileEntity); + return tileEntity; + } return null; } @@ -52,7 +69,7 @@ public class SchematicWorld extends WrappedWorld { public BlockState getBlockState(BlockPos globalPos) { BlockPos pos = globalPos.subtract(anchor); - if (pos.getY() - bounds.y == -1) { + if (pos.getY() - bounds.y == -1 && !renderMode) { return Blocks.GRASS_BLOCK.getDefaultState(); } @@ -166,4 +183,8 @@ public class SchematicWorld extends WrappedWorld { this.bounds = bounds; } + public Iterable getTileEntities() { + return tileEntities.values(); + } + } diff --git a/src/main/java/com/simibubi/create/modules/schematics/ServerSchematicLoader.java b/src/main/java/com/simibubi/create/modules/schematics/ServerSchematicLoader.java index 0c7e17f26..303f430f1 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/ServerSchematicLoader.java +++ b/src/main/java/com/simibubi/create/modules/schematics/ServerSchematicLoader.java @@ -14,7 +14,6 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Stream; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocksNew; import com.simibubi.create.Create; import com.simibubi.create.config.AllConfigs; diff --git a/src/main/java/com/simibubi/create/modules/schematics/block/SchematicTableContainer.java b/src/main/java/com/simibubi/create/modules/schematics/block/SchematicTableContainer.java index 1157ab797..40b71cab4 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/block/SchematicTableContainer.java +++ b/src/main/java/com/simibubi/create/modules/schematics/block/SchematicTableContainer.java @@ -44,7 +44,8 @@ public class SchematicTableContainer extends Container { inputSlot = new SlotItemHandler(te.inventory, 0, -9, 40) { @Override public boolean isItemValid(ItemStack stack) { - return AllItems.EMPTY_BLUEPRINT.typeOf(stack) || AllItems.BLUEPRINT_AND_QUILL.typeOf(stack); + return AllItems.EMPTY_BLUEPRINT.typeOf(stack) || AllItems.BLUEPRINT_AND_QUILL.typeOf(stack) + || AllItems.BLUEPRINT.typeOf(stack); } }; diff --git a/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonScreen.java b/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonScreen.java index 4f288e802..bd6669382 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonScreen.java +++ b/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonScreen.java @@ -9,7 +9,6 @@ import java.util.Vector; import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.systems.RenderSystem; -import com.simibubi.create.AllBlocks; import com.simibubi.create.AllBlocksNew; import com.simibubi.create.AllPackets; import com.simibubi.create.ScreenResources; diff --git a/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonTileEntity.java b/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonTileEntity.java index f8caa18d2..c2b01e7c6 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonTileEntity.java +++ b/src/main/java/com/simibubi/create/modules/schematics/block/SchematicannonTileEntity.java @@ -1,6 +1,5 @@ package com.simibubi.create.modules.schematics.block; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -12,7 +11,6 @@ import com.simibubi.create.config.AllConfigs; import com.simibubi.create.config.CSchematics; import com.simibubi.create.foundation.behaviour.base.SmartTileEntity; import com.simibubi.create.foundation.behaviour.base.TileEntityBehaviour; -import com.simibubi.create.foundation.type.Cuboid; import com.simibubi.create.modules.schematics.MaterialChecklist; import com.simibubi.create.modules.schematics.SchematicWorld; import com.simibubi.create.modules.schematics.item.SchematicItem; @@ -466,7 +464,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC } // Load blocks into reader - Template activeTemplate = SchematicItem.getSchematic(blueprint); + Template activeTemplate = SchematicItem.loadSchematic(blueprint); BlockPos anchor = NBTUtil.readBlockPos(blueprint.getTag().getCompound("Anchor")); if (activeTemplate.getSize().equals(BlockPos.ZERO)) { @@ -484,7 +482,7 @@ public class SchematicannonTileEntity extends SmartTileEntity implements INamedC } schematicAnchor = anchor; - blockReader = new SchematicWorld(new HashMap<>(), new Cuboid(), schematicAnchor, world); + blockReader = new SchematicWorld(schematicAnchor, world); activeTemplate.addBlocksToWorld(blockReader, schematicAnchor, SchematicItem.getSettings(blueprint)); schematicLoaded = true; state = State.PAUSED; diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicAndQuillHandler.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicAndQuillHandler.java index ed6a3b514..c0cec4880 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicAndQuillHandler.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicAndQuillHandler.java @@ -8,9 +8,6 @@ import java.nio.file.StandardOpenOption; import org.apache.commons.io.IOUtils; -import com.mojang.blaze3d.matrix.MatrixStack; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.IVertexBuilder; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; import com.simibubi.create.AllSpecialTextures; @@ -20,15 +17,13 @@ import com.simibubi.create.foundation.utility.FilesHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; -import com.simibubi.create.foundation.utility.TessellatorHelper; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.outliner.ChasingAABBOutline; +import com.simibubi.create.foundation.utility.outliner.OutlineParticle; import net.minecraft.block.Blocks; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; -import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.item.BlockItemUseContext; import net.minecraft.item.ItemUseContext; import net.minecraft.nbt.CompoundNBT; @@ -36,6 +31,7 @@ import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.util.Direction; import net.minecraft.util.Direction.AxisDirection; 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.util.math.MathHelper; @@ -53,14 +49,7 @@ public class SchematicAndQuillHandler { private Direction selectedFace; private int range = 10; - private boolean isActive() { - return isPresent() && AllItems.BLUEPRINT_AND_QUILL.typeOf(Minecraft.getInstance().player.getHeldItemMainhand()); - } - - private boolean isPresent() { - return Minecraft.getInstance() != null && Minecraft.getInstance().world != null - && Minecraft.getInstance().currentScreen == null; - } + private OutlineParticle particle; public boolean mouseScrolled(double delta) { if (!isActive()) @@ -69,27 +58,32 @@ public class SchematicAndQuillHandler { return false; if (secondPos == null) range = (int) MathHelper.clamp(range + delta, 1, 100); - if (selectedFace != null) { - MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos); - Vec3i vec = selectedFace.getDirectionVec(); + if (selectedFace == null) + return true; - int x = (int) (vec.getX() * delta); - int y = (int) (vec.getY() * delta); - int z = (int) (vec.getZ() * delta); + AxisAlignedBB bb = new AxisAlignedBB(firstPos, secondPos); + Vec3i vec = selectedFace.getDirectionVec(); + Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView(); + if (bb.contains(projectedView)) + delta *= -1; - AxisDirection axisDirection = selectedFace.getAxisDirection(); - if (axisDirection == AxisDirection.NEGATIVE) - bb.offset(-x, -y, -z); + int x = (int) (vec.getX() * delta); + int y = (int) (vec.getY() * delta); + int z = (int) (vec.getZ() * delta); - bb.maxX = Math.max(bb.maxX - x * axisDirection.getOffset(), bb.minX); - bb.maxY = Math.max(bb.maxY - y * axisDirection.getOffset(), bb.minY); - bb.maxZ = Math.max(bb.maxZ - z * axisDirection.getOffset(), bb.minZ); + AxisDirection axisDirection = selectedFace.getAxisDirection(); + if (axisDirection == AxisDirection.NEGATIVE) + bb = bb.offset(-x, -y, -z); - firstPos = new BlockPos(bb.minX, bb.minY, bb.minZ); - secondPos = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); - Lang.sendStatus(Minecraft.getInstance().player, "schematicAndQuill.dimensions", bb.getXSize(), - bb.getYSize(), bb.getZSize()); - } + double maxX = Math.max(bb.maxX - x * axisDirection.getOffset(), bb.minX); + double maxY = Math.max(bb.maxY - y * axisDirection.getOffset(), bb.minY); + double maxZ = Math.max(bb.maxZ - z * axisDirection.getOffset(), bb.minZ); + bb = new AxisAlignedBB(bb.minX, bb.minY, bb.minZ, maxX, maxY, maxZ); + + firstPos = new BlockPos(bb.minX, bb.minY, bb.minZ); + secondPos = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); + Lang.sendStatus(Minecraft.getInstance().player, "schematicAndQuill.dimensions", (int) bb.getXSize() + 1, + (int) bb.getYSize() + 1, (int) bb.getZSize() + 1); return true; } @@ -110,8 +104,7 @@ public class SchematicAndQuillHandler { } if (secondPos != null) { - TextInputPromptScreen guiScreenIn = new TextInputPromptScreen(this::saveSchematic, s -> { - }); + TextInputPromptScreen guiScreenIn = new TextInputPromptScreen(this::saveSchematic, s -> {}); guiScreenIn.setTitle(Lang.translate("schematicAndQuill.prompt")); guiScreenIn.setButtonTextConfirm(Lang.translate("action.saveToFile")); guiScreenIn.setButtonTextAbort(Lang.translate("action.discard")); @@ -134,6 +127,100 @@ public class SchematicAndQuillHandler { Lang.sendStatus(player, "schematicAndQuill.firstPos"); } + public void tick() { + if (!isActive()) { + if (particle != null) { + particle.setExpired(); + particle = null; + } + return; + } + + ClientPlayerEntity player = Minecraft.getInstance().player; + + if (AllKeys.ACTIVATE_TOOL.isPressed()) { + float pt = Minecraft.getInstance().getRenderPartialTicks(); + Vec3d targetVec = player.getEyePosition(pt).add(player.getLookVec().scale(range)); + setCursor(new BlockPos(targetVec)); + + } else { + BlockRayTraceResult trace = RaycastHelper.rayTraceRange(player.world, player, 75); + if (trace != null && trace.getType() == Type.BLOCK) { + + BlockPos hit = trace.getPos(); + boolean replaceable = player.world.getBlockState(hit) + .isReplaceable(new BlockItemUseContext(new ItemUseContext(player, Hand.MAIN_HAND, trace))); + if (trace.getFace().getAxis().isVertical() && !replaceable) + hit = hit.offset(trace.getFace()); + setCursor(hit); + } else + setCursor(null); + } + + if (particle == null) + return; + + ChasingAABBOutline outline = particle.getOutline(); + if (particle.isAlive()) + outline.tick(); + + if (secondPos == null) { + selectedFace = null; + outline.highlightFace(null); + return; + } + + AxisAlignedBB bb = new AxisAlignedBB(firstPos, secondPos).expand(1, 1, 1).grow(.45f); + Vec3d projectedView = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView(); + boolean inside = bb.contains(projectedView); + + PredicateTraceResult result = + RaycastHelper.rayTraceUntil(player, 70, pos -> inside ^ bb.contains(VecHelper.getCenterOf(pos))); + selectedFace = result.missed() ? null : inside ? result.getFacing().getOpposite() : result.getFacing(); + outline.highlightFace(AllKeys.ACTIVATE_TOOL.isPressed() ? selectedFace : null); + } + + private void setCursor(BlockPos pos) { + selectedPos = pos; + AxisAlignedBB bb = getCurrentSelectionBox(); + + if (particle != null && !particle.isAlive()) + particle = null; + if (bb == null) { + if (particle != null) + particle.setExpired(); + return; + } + + if (particle == null) { + ChasingAABBOutline outline = new ChasingAABBOutline(bb); + outline.setTextures(AllSpecialTextures.CHECKERED, AllSpecialTextures.HIGHLIGHT_CHECKERED); + particle = OutlineParticle.create(outline); + } + + ChasingAABBOutline outline = particle.getOutline(); + outline.target(bb); + } + + private AxisAlignedBB getCurrentSelectionBox() { + if (secondPos == null) { + if (firstPos == null) + return selectedPos == null ? null : new AxisAlignedBB(selectedPos); + return selectedPos == null ? new AxisAlignedBB(firstPos) + : new AxisAlignedBB(firstPos, selectedPos).expand(1, 1, 1); + } + return new AxisAlignedBB(firstPos, secondPos).expand(1, 1, 1); + } + + private boolean isActive() { + return isPresent() && AllItems.BLUEPRINT_AND_QUILL.typeOf(Minecraft.getInstance().player.getHeldItemMainhand()); + } + + private boolean isPresent() { + return Minecraft.getInstance() != null && Minecraft.getInstance().world != null + && Minecraft.getInstance().currentScreen == null; + } + public void saveSchematic(String string) { Template t = new Template(); MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos); @@ -164,118 +251,4 @@ public class SchematicAndQuillHandler { Lang.sendStatus(Minecraft.getInstance().player, "schematicAndQuill.saved", filepath); } - public void render(MatrixStack ms, IRenderTypeBuffer buffer) { - if (!isActive()) - return; - - IVertexBuilder vb = buffer.getBuffer(RenderType.getLines()); - - TessellatorHelper.prepareForDrawing(); - RenderSystem.lineWidth(2); - RenderSystem.color4f(1, 1, 1, 1); - RenderSystem.disableTexture(); - - if (secondPos == null) { - // 1st Step - if (firstPos != null && selectedPos == null) { - MutableBoundingBox bb = new MutableBoundingBox(firstPos, firstPos.add(1, 1, 1)); - BlockPos min = new BlockPos(bb.minX, bb.minY, bb.minZ); - BlockPos max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); - drawBox(ms, vb, min, max, true); - } - - if (firstPos != null && selectedPos != null) { - MutableBoundingBox bb = new MutableBoundingBox(firstPos, selectedPos); - BlockPos min = new BlockPos(bb.minX, bb.minY, bb.minZ); - BlockPos max = new BlockPos(bb.maxX + 1, bb.maxY + 1, bb.maxZ + 1); - drawBox(ms, vb, min, max, true); - } - - if (firstPos == null && selectedPos != null) { - MutableBoundingBox bb = new MutableBoundingBox(selectedPos, selectedPos.add(1, 1, 1)); - BlockPos min = new BlockPos(bb.minX, bb.minY, bb.minZ); - BlockPos max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); - drawBox(ms, vb, min, max, true); - } - } else { - // 2nd Step - MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos); - BlockPos min = new BlockPos(bb.minX, bb.minY, bb.minZ); - BlockPos max = new BlockPos(bb.maxX + 1, bb.maxY + 1, bb.maxZ + 1); - drawBox(ms, vb, min, max, false); - - if (selectedFace != null) { - Vec3d vec = new Vec3d(selectedFace.getDirectionVec()); - Vec3d center = new Vec3d(min.add(max)).scale(1 / 2f); - Vec3d radii = new Vec3d(max.subtract(min)).scale(1 / 2f); - - Vec3d onFaceOffset = new Vec3d(1 - Math.abs(vec.x), 1 - Math.abs(vec.y), 1 - Math.abs(vec.z)) - .mul(radii); - Vec3d faceMin = center.add(vec.mul(radii).add(onFaceOffset)); - Vec3d faceMax = center.add(vec.mul(radii).subtract(onFaceOffset)); - - // TODO 1.15 buffered render - RenderSystem.enableTexture(); - TessellatorHelper.begin(); - AllSpecialTextures.SELECTION.bind(); - TessellatorHelper.doubleFace(Tessellator.getInstance().getBuffer(), new BlockPos(faceMin), - new BlockPos(faceMax.subtract(faceMin)), 1 / 16f * selectedFace.getAxisDirection().getOffset(), - false, false, false); - TessellatorHelper.draw(); - RenderSystem.disableTexture(); - - } - - } - - RenderSystem.lineWidth(1); - RenderSystem.enableTexture(); - TessellatorHelper.cleanUpAfterDrawing(); - } - - protected static void drawBox(MatrixStack ms, IVertexBuilder buffer, BlockPos min, BlockPos max, boolean blue) { - float red = blue ? .8f : 1; - float green = blue ? .9f : 1; - WorldRenderer.drawBox(ms, buffer, min.getX() - 1 / 16d, min.getY() + 1 / 16d, min.getZ() - 1 / 16d, - max.getX() + 1 / 16d, max.getY() + 1 / 16d, max.getZ() + 1 / 16d, red, green, 1, 1); - } - - public void tick() { - if (!isActive()) - return; - ClientPlayerEntity player = Minecraft.getInstance().player; - - selectedPos = null; - if (AllKeys.ACTIVATE_TOOL.isPressed()) { - selectedPos = new BlockPos(player.getEyePosition(Minecraft.getInstance().getRenderPartialTicks()) - .add(player.getLookVec().scale(range))); - } else { - BlockRayTraceResult trace = RaycastHelper.rayTraceRange(player.world, player, 75); - if (trace != null && trace.getType() == Type.BLOCK) { - - BlockPos hit = new BlockPos(trace.getHitVec()); - boolean replaceable = player.world.getBlockState(hit) - .isReplaceable(new BlockItemUseContext(new ItemUseContext(player, Hand.MAIN_HAND, trace))); - if (trace.getFace().getAxis().isVertical() && !replaceable) - hit = hit.offset(trace.getFace()); - - selectedPos = hit; - } else { - selectedPos = null; - } - } - - if (secondPos == null) { - selectedFace = null; - return; - } - - MutableBoundingBox bb = new MutableBoundingBox(firstPos, secondPos); - bb.maxX++; - bb.maxY++; - bb.maxZ++; - - PredicateTraceResult result = RaycastHelper.rayTraceUntil(player, 70, pos -> bb.isVecInside(pos)); - selectedFace = result.missed() ? null : result.getFacing(); - } } \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicEditScreen.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicEditScreen.java index 5dfc2944e..57a7d7fde 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicEditScreen.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicEditScreen.java @@ -15,9 +15,11 @@ import com.simibubi.create.foundation.utility.Lang; import net.minecraft.client.gui.widget.TextFieldWidget; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTUtil; import net.minecraft.util.Mirror; import net.minecraft.util.Rotation; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.gen.feature.template.PlacementSettings; public class SchematicEditScreen extends AbstractSimiScreen { @@ -25,10 +27,10 @@ public class SchematicEditScreen extends AbstractSimiScreen { private TextFieldWidget yInput; private TextFieldWidget zInput; - private final List rotationOptions = Lang.translatedOptions("schematic.rotation", "none", "cw90", "cw180", - "cw270"); - private final List mirrorOptions = Lang.translatedOptions("schematic.mirror", "none", "leftRight", - "frontBack"); + private final List rotationOptions = + Lang.translatedOptions("schematic.rotation", "none", "cw90", "cw180", "cw270"); + private final List mirrorOptions = + Lang.translatedOptions("schematic.mirror", "none", "leftRight", "frontBack"); private final String positionLabel = Lang.translate("schematic.position"); private final String rotationLabel = Lang.translate("schematic.rotation"); private final String mirrorLabel = Lang.translate("schematic.mirror"); @@ -48,10 +50,11 @@ public class SchematicEditScreen extends AbstractSimiScreen { yInput = new TextFieldWidget(font, x + 115, y + 32, 32, 10, ""); zInput = new TextFieldWidget(font, x + 155, y + 32, 32, 10, ""); - if (handler.deployed) { - xInput.setText("" + handler.anchor.getX()); - yInput.setText("" + handler.anchor.getY()); - zInput.setText("" + handler.anchor.getZ()); + BlockPos anchor = handler.getTransformation().getAnchor(); + if (handler.isDeployed()) { + xInput.setText("" + anchor.getX()); + yInput.setText("" + anchor.getY()); + zInput.setText("" + anchor.getZ()); } else { BlockPos alt = minecraft.player.getPosition(); xInput.setText("" + alt.getX()); @@ -77,13 +80,14 @@ public class SchematicEditScreen extends AbstractSimiScreen { }); } + PlacementSettings settings = handler.getTransformation().toSettings(); Label labelR = new Label(x + 99, y + 52, "").withShadow(); rotationArea = new SelectionScrollInput(x + 96, y + 49, 94, 14).forOptions(rotationOptions).titled("Rotation") - .setState(handler.cachedSettings.getRotation().ordinal()).writingTo(labelR); + .setState(settings.getRotation().ordinal()).writingTo(labelR); Label labelM = new Label(x + 99, y + 72, "").withShadow(); mirrorArea = new SelectionScrollInput(x + 96, y + 69, 94, 14).forOptions(mirrorOptions).titled("Mirror") - .setState(handler.cachedSettings.getMirror().ordinal()).writingTo(labelM); + .setState(settings.getMirror().ordinal()).writingTo(labelM); Collections.addAll(widgets, xInput, yInput, zInput); Collections.addAll(widgets, labelR, labelM, rotationArea, mirrorArea); @@ -127,8 +131,8 @@ public class SchematicEditScreen extends AbstractSimiScreen { int y = guiTop; ScreenResources.SCHEMATIC.draw(this, x, y); - font.drawStringWithShadow(handler.cachedSchematicName, - x + 103 - font.getStringWidth(handler.cachedSchematicName) / 2, y + 10, 0xDDEEFF); + font.drawStringWithShadow(handler.getCurrentSchematicName(), + x + 103 - font.getStringWidth(handler.getCurrentSchematicName()) / 2, y + 10, 0xDDEEFF); font.drawString(positionLabel, x + 10, y + 32, ScreenResources.FONT_COLOR); font.drawString(rotationLabel, x + 10, y + 52, ScreenResources.FONT_COLOR); @@ -152,10 +156,22 @@ public class SchematicEditScreen extends AbstractSimiScreen { validCoords = false; } - if (validCoords) - handler.moveTo(newLocation); - handler.setRotation(Rotation.values()[rotationArea.getState()]); - handler.setMirror(Mirror.values()[mirrorArea.getState()]); + PlacementSettings settings = new PlacementSettings(); + settings.setRotation(Rotation.values()[rotationArea.getState()]); + settings.setMirror(Mirror.values()[mirrorArea.getState()]); + + if (validCoords && newLocation != null) { + ItemStack item = handler.getActiveSchematicItem(); + if (item != null) { + item.getTag().putBoolean("Deployed", true); + item.getTag().put("Anchor", NBTUtil.writeBlockPos(newLocation)); + } + + handler.getTransformation().init(newLocation, settings, handler.getBounds()); + handler.markDirty(); + handler.deploy(); + } + } } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHandler.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHandler.java index 7b80c045b..91c328b9b 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHandler.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHandler.java @@ -1,20 +1,17 @@ package com.simibubi.create.modules.schematics.client; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; import com.google.common.collect.ImmutableList; import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.platform.GlStateManager; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; import com.simibubi.create.AllPackets; -import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.gui.ToolSelectionScreen; import com.simibubi.create.foundation.packet.NbtPacket; -import com.simibubi.create.foundation.type.Cuboid; -import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.TessellatorHelper; +import com.simibubi.create.foundation.utility.outliner.AABBOutline; import com.simibubi.create.modules.schematics.SchematicWorld; import com.simibubi.create.modules.schematics.client.tools.Tools; import com.simibubi.create.modules.schematics.item.SchematicItem; @@ -28,79 +25,62 @@ import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.NBTUtil; -import net.minecraft.util.Direction.Axis; -import net.minecraft.util.Mirror; -import net.minecraft.util.Rotation; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.text.StringTextComponent; import net.minecraft.world.gen.feature.template.PlacementSettings; import net.minecraft.world.gen.feature.template.Template; public class SchematicHandler { - public Template cachedSchematic; - public String cachedSchematicName; - public PlacementSettings cachedSettings; + private String displayedSchematic; + private SchematicTransformation transformation; + private AxisAlignedBB bounds; // local space + private AABBOutline outline; + private boolean deployed; + private boolean active; + private Tools currentTool; - public BlockPos anchor; - public BlockPos size; - public boolean active; - public boolean deployed; - public int slot; - public ItemStack item; + private static final int SYNC_DELAY = 10; + private int syncCooldown; + private int activeHotbarSlot; + private ItemStack activeSchematicItem; - private final List mirrors = Arrays.asList("none", "leftRight", "frontBack"); - private final List rotations = Arrays.asList("none", "cw90", "cw180", "cw270"); - - public Tools currentTool; - public ToolSelectionScreen selectionScreen; - - public static final int SYNC_DELAY = 20; - public int syncCooldown; - - private BlueprintHotbarOverlay overlay; + private SchematicRenderer renderer; + private SchematicHotbarSlotOverlay overlay; + private ToolSelectionScreen selectionScreen; public SchematicHandler() { + overlay = new SchematicHotbarSlotOverlay(); + renderer = new SchematicRenderer(); currentTool = Tools.Deploy; - overlay = new BlueprintHotbarOverlay(); selectionScreen = new ToolSelectionScreen(ImmutableList.of(Tools.Deploy), this::equip); + transformation = new SchematicTransformation(); } public void tick() { ClientPlayerEntity player = Minecraft.getInstance().player; + if (activeSchematicItem != null && transformation != null) + transformation.tick(); + ItemStack stack = findBlueprintInHand(player); if (stack == null) { active = false; syncCooldown = 0; - if (item != null && itemLost(player)) { - slot = 0; - item = null; - CreateClient.schematicHologram.setActive(false); + if (activeSchematicItem != null && itemLost(player)) { + activeHotbarSlot = 0; + activeSchematicItem = null; + renderer.setActive(false); } return; } - // Newly equipped - if (!active || !stack.getTag().getString("File").equals(cachedSchematicName)) { - loadSettings(stack); - cachedSchematicName = stack.getTag().getString("File"); - active = true; - if (deployed) { - Tools toolBefore = currentTool; - selectionScreen = new ToolSelectionScreen(Tools.getTools(player.isCreative()), this::equip); - if (toolBefore != null) { - selectionScreen.setSelectedElement(toolBefore); - equip(toolBefore); - } - } else - selectionScreen = new ToolSelectionScreen(ImmutableList.of(Tools.Deploy), this::equip); - sync(); - } - + if (!active || !stack.getTag().getString("File").equals(displayedSchematic)) + init(player, stack); if (!active) return; + renderer.tick(); if (syncCooldown > 0) syncCooldown--; if (syncCooldown == 1) @@ -110,20 +90,62 @@ public class SchematicHandler { currentTool.getTool().updateSelection(); } - public void render(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { - if (!active) - return; - if (Minecraft.getInstance().player.isSneaking()) + private void init(ClientPlayerEntity player, ItemStack stack) { + loadSettings(stack); + displayedSchematic = stack.getTag().getString("File"); + active = true; + if (deployed) { + setupRenderer(); + Tools toolBefore = currentTool; + selectionScreen = new ToolSelectionScreen(Tools.getTools(player.isCreative()), this::equip); + if (toolBefore != null) { + selectionScreen.setSelectedElement(toolBefore); + equip(toolBefore); + } + } else + selectionScreen = new ToolSelectionScreen(ImmutableList.of(Tools.Deploy), this::equip); + } + + private void setupRenderer() { + Template schematic = SchematicItem.loadSchematic(activeSchematicItem); + if (schematic.getSize().equals(BlockPos.ZERO)) return; - currentTool.getTool().renderTool(ms, buffer, light, overlay); + SchematicWorld w = new SchematicWorld(BlockPos.ZERO, Minecraft.getInstance().world); + schematic.addBlocksToWorld(w, BlockPos.ZERO, new PlacementSettings()); + renderer.startHologram(w); + } + + public void render(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { + boolean present = activeSchematicItem != null; + if (!active && !present) + return; + if (active) { + TessellatorHelper.prepareForDrawing(); + currentTool.getTool().renderTool(ms, buffer, light, overlay); + TessellatorHelper.cleanUpAfterDrawing(); + } + + GlStateManager.pushMatrix(); + TessellatorHelper.prepareForDrawing(); + transformation.applyGLTransformations(); + renderer.render(ms, buffer); + GlStateManager.disableCull(); + + if (active) + currentTool.getTool().renderToolLocal(ms, buffer, light, overlay); + + GlStateManager.enableCull(); + GlStateManager.depthMask(true); + TessellatorHelper.cleanUpAfterDrawing(); + GlStateManager.popMatrix(); } public void renderOverlay(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { if (!active) return; - if (item != null) - this.overlay.renderOn(slot); + if (activeSchematicItem != null) + this.overlay.renderOn(activeHotbarSlot); currentTool.getTool().renderOverlay(ms, buffer, light, overlay); selectionScreen.renderPassive(Minecraft.getInstance().getRenderPartialTicks()); @@ -148,7 +170,6 @@ public class SchematicHandler { if (pressed && !selectionScreen.focused) selectionScreen.focused = true; - if (!pressed && selectionScreen.focused) { selectionScreen.focused = false; selectionScreen.onClose(); @@ -156,18 +177,15 @@ public class SchematicHandler { } public boolean mouseScrolled(double delta) { - if (!active) - return false; - if (Minecraft.getInstance().player.isSneaking()) + if (!active || Minecraft.getInstance().player.isSneaking()) return false; + if (selectionScreen.focused) { selectionScreen.cycle((int) delta); return true; } - if (AllKeys.ACTIVATE_TOOL.isPressed()) { + if (AllKeys.ACTIVATE_TOOL.isPressed()) return currentTool.getTool().handleMouseWheel(delta); - } - return false; } @@ -178,16 +196,16 @@ public class SchematicHandler { if (!stack.hasTag()) return null; - item = stack; - slot = player.inventory.currentItem; + activeSchematicItem = stack; + activeHotbarSlot = player.inventory.currentItem; return stack; } private boolean itemLost(PlayerEntity player) { for (int i = 0; i < PlayerInventory.getHotbarSize(); i++) { - if (!player.inventory.getStackInSlot(i).isItemEqual(item)) + if (!player.inventory.getStackInSlot(i).isItemEqual(activeSchematicItem)) continue; - if (!ItemStack.areItemStackTagsEqual(player.inventory.getStackInSlot(i), item)) + if (!ItemStack.areItemStackTagsEqual(player.inventory.getStackInSlot(i), activeSchematicItem)) continue; return false; } @@ -196,25 +214,20 @@ public class SchematicHandler { public void markDirty() { syncCooldown = SYNC_DELAY; - CreateClient.schematicHologram.setActive(false); } public void sync() { - message(Lang.translate("schematics.synchronizing")); - AllPackets.channel.sendToServer(new NbtPacket(item, slot)); + if (activeSchematicItem == null) + return; - if (deployed) { - Template schematic = SchematicItem.getSchematic(item); + PlacementSettings settings = transformation.toSettings(); + CompoundNBT tag = activeSchematicItem.getTag(); + tag.putBoolean("Deployed", deployed); + tag.put("Anchor", NBTUtil.writeBlockPos(transformation.getAnchor())); + tag.putString("Rotation", settings.getRotation().name()); + tag.putString("Mirror", settings.getMirror().name()); - if (schematic.getSize().equals(BlockPos.ZERO)) - return; - - SchematicWorld w = new SchematicWorld(new HashMap<>(), new Cuboid(), anchor, Minecraft.getInstance().world); - PlacementSettings settings = cachedSettings.copy(); - settings.setBoundingBox(null); - schematic.addBlocksToWorld(w, anchor, settings); - CreateClient.schematicHologram.startHologram(w); - } + AllPackets.channel.sendToServer(new NbtPacket(activeSchematicItem, activeHotbarSlot)); } public void equip(Tools tool) { @@ -224,149 +237,66 @@ public class SchematicHandler { public void loadSettings(ItemStack blueprint) { CompoundNBT tag = blueprint.getTag(); - cachedSettings = new PlacementSettings(); - cachedSettings.setRotation(Rotation.valueOf(tag.getString("Rotation"))); - cachedSettings.setMirror(Mirror.valueOf(tag.getString("Mirror"))); + BlockPos anchor = BlockPos.ZERO; + PlacementSettings settings = SchematicItem.getSettings(blueprint); + transformation = new SchematicTransformation(); deployed = tag.getBoolean("Deployed"); if (deployed) anchor = NBTUtil.readBlockPos(tag.getCompound("Anchor")); + BlockPos size = NBTUtil.readBlockPos(tag.getCompound("Bounds")); - size = NBTUtil.readBlockPos(tag.getCompound("Bounds")); + bounds = new AxisAlignedBB(BlockPos.ZERO, size); + outline = new AABBOutline(bounds); + outline.disableCull = true; + transformation.init(anchor, settings, bounds); } - public void flip(Axis axis) { - - Rotation r = cachedSettings.getRotation(); - boolean rotationAt90s = r == Rotation.CLOCKWISE_90 || r == Rotation.COUNTERCLOCKWISE_90; - Mirror mirror = axis == Axis.Z ^ rotationAt90s ? Mirror.FRONT_BACK : Mirror.LEFT_RIGHT; - - BlockPos coordModifier = new BlockPos((r == Rotation.NONE || r == Rotation.COUNTERCLOCKWISE_90) ? 1 : -1, 0, - (r == Rotation.NONE || r == Rotation.CLOCKWISE_90) ? 1 : -1); - BlockPos anchorOffset = axis == Axis.Z - ? new BlockPos(((rotationAt90s ? size.getZ() : size.getX()) - 1) * coordModifier.getX(), 0, 0) - : new BlockPos(0, 0, ((!rotationAt90s ? size.getZ() : size.getX()) - 1) * coordModifier.getZ()); - - Mirror m = cachedSettings.getMirror(); - - if (m == Mirror.NONE) { - cachedSettings.setMirror(mirror); - anchor = anchor.add(anchorOffset); - message(Lang.translate("schematic.mirror") + ": " - + Lang.translate("schematic.mirror." + mirrors.get(cachedSettings.getMirror().ordinal()))); - - } else if (m == mirror) { - cachedSettings.setMirror(Mirror.NONE); - anchor = anchor.subtract(anchorOffset); - message(Lang.translate("schematic.mirror") + ": " - + Lang.translate("schematic.mirror." + mirrors.get(cachedSettings.getMirror().ordinal()))); - - } else if (m != mirror) { - cachedSettings.setMirror(Mirror.NONE); - anchor = anchor.add(anchorOffset); - cachedSettings.setRotation(r.add(Rotation.CLOCKWISE_180)); - message(Lang.translate("schematic.mirror") + ": " - + Lang.translate("schematic.mirror." + mirrors.get(cachedSettings.getMirror().ordinal())) + ", " - + Lang.translate("schematic.rotation") + ": " - + Lang.translate("schematic.rotation." + rotations.get(cachedSettings.getRotation().ordinal()))); + public void deploy() { + if (!deployed) { + List tools = Tools.getTools(Minecraft.getInstance().player.isCreative()); + selectionScreen = new ToolSelectionScreen(tools, this::equip); } - - item.getTag().put("Anchor", NBTUtil.writeBlockPos(anchor)); - item.getTag().putString("Mirror", cachedSettings.getMirror().name()); - item.getTag().putString("Rotation", r.name()); - - markDirty(); - } - - public void message(String msg) { - Minecraft.getInstance().player.sendStatusMessage(new StringTextComponent(msg), true); - } - - public void rotate(Rotation rotation) { - Rotation r = cachedSettings.getRotation(); - BlockPos center = centerOfSchematic(); - cachedSettings.setRotation(r.add(rotation)); - BlockPos diff = center.subtract(anchor); - BlockPos move = diff.subtract(diff.rotate(rotation)); - anchor = anchor.add(move); - - item.getTag().put("Anchor", NBTUtil.writeBlockPos(anchor)); - item.getTag().putString("Rotation", cachedSettings.getRotation().name()); - - message(Lang.translate("schematic.rotation") + ": " - + Lang.translate("schematic.rotation." + rotations.get(cachedSettings.getRotation().ordinal()))); - - markDirty(); - } - - public void setMirror(Mirror mirror) { - cachedSettings.setMirror(mirror); - item.getTag().putString("Mirror", cachedSettings.getMirror().name()); - markDirty(); - } - - public void setRotation(Rotation rotation) { - cachedSettings.setRotation(rotation); - item.getTag().putString("Rotation", cachedSettings.getRotation().name()); - markDirty(); - } - - public void moveTo(BlockPos anchor) { - if (!deployed) - selectionScreen = new ToolSelectionScreen(Tools.getTools(Minecraft.getInstance().player.isCreative()), - this::equip); - deployed = true; - this.anchor = anchor; - item.getTag().putBoolean("Deployed", true); - item.getTag().put("Anchor", NBTUtil.writeBlockPos(anchor)); - markDirty(); + setupRenderer(); + } + + public String getCurrentSchematicName() { + return displayedSchematic != null ? displayedSchematic : "-"; } public void printInstantly() { - AllPackets.channel.sendToServer(new SchematicPlacePacket(item.copy())); - CompoundNBT nbt = item.getTag(); + AllPackets.channel.sendToServer(new SchematicPlacePacket(activeSchematicItem.copy())); + CompoundNBT nbt = activeSchematicItem.getTag(); nbt.putBoolean("Deployed", false); - item.setTag(nbt); - CreateClient.schematicHologram.setActive(false); + activeSchematicItem.setTag(nbt); + renderer.setActive(false); active = false; + markDirty(); } - public BlockPos getTransformedSize() { - BlockPos flipped = size; - if (cachedSettings.getMirror() == Mirror.FRONT_BACK) - flipped = new BlockPos(-flipped.getX(), flipped.getY(), flipped.getZ()); - if (cachedSettings.getMirror() == Mirror.LEFT_RIGHT) - flipped = new BlockPos(flipped.getX(), flipped.getY(), -flipped.getZ()); - - BlockPos rotate = flipped.rotate(cachedSettings.getRotation()); - return rotate; + public AABBOutline getOutline() { + return outline; } - public BlockPos getTransformedAnchor() { - BlockPos anchor = this.anchor; - Rotation r = cachedSettings.getRotation(); - - BlockPos flipOffset = BlockPos.ZERO; - if (cachedSettings.getMirror() == Mirror.FRONT_BACK) - flipOffset = new BlockPos(1, 0, 0); - if (cachedSettings.getMirror() == Mirror.LEFT_RIGHT) - flipOffset = new BlockPos(0, 0, 1); - - flipOffset = flipOffset.rotate(r); - anchor = anchor.add(flipOffset); - - if (r == Rotation.CLOCKWISE_90 || r == Rotation.CLOCKWISE_180) - anchor = anchor.add(1, 0, 0); - if (r == Rotation.COUNTERCLOCKWISE_90 || r == Rotation.CLOCKWISE_180) - anchor = anchor.add(0, 0, 1); - return anchor; + public boolean isActive() { + return active; } - public BlockPos centerOfSchematic() { - BlockPos size = getTransformedSize(); - BlockPos center = new BlockPos(size.getX() / 2, 0, size.getZ() / 2); - return anchor.add(center); + public AxisAlignedBB getBounds() { + return bounds; + } + + public SchematicTransformation getTransformation() { + return transformation; + } + + public boolean isDeployed() { + return deployed; + } + + public ItemStack getActiveSchematicItem() { + return activeSchematicItem; } } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/BlueprintHotbarOverlay.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHotbarSlotOverlay.java similarity index 90% rename from src/main/java/com/simibubi/create/modules/schematics/client/BlueprintHotbarOverlay.java rename to src/main/java/com/simibubi/create/modules/schematics/client/SchematicHotbarSlotOverlay.java index 762c0ef88..d595dfe58 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/BlueprintHotbarOverlay.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHotbarSlotOverlay.java @@ -7,7 +7,7 @@ import net.minecraft.client.MainWindow; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.AbstractGui; -public class BlueprintHotbarOverlay extends AbstractGui { +public class SchematicHotbarSlotOverlay extends AbstractGui { public void renderOn(int slot) { MainWindow mainWindow = Minecraft.getInstance().getWindow(); diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHologram.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicRenderer.java similarity index 66% rename from src/main/java/com/simibubi/create/modules/schematics/client/SchematicHologram.java rename to src/main/java/com/simibubi/create/modules/schematics/client/SchematicRenderer.java index 45b6926af..ec24de984 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicHologram.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicRenderer.java @@ -1,7 +1,6 @@ package com.simibubi.create.modules.schematics.client; import java.nio.ByteBuffer; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -13,7 +12,6 @@ import org.lwjgl.system.MemoryUtil; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.datafixers.util.Pair; -import com.simibubi.create.foundation.type.Cuboid; import com.simibubi.create.modules.schematics.SchematicWorld; import net.minecraft.block.BedBlock; @@ -32,12 +30,10 @@ import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.Entity; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; -import net.minecraft.world.gen.feature.template.PlacementSettings; -import net.minecraft.world.gen.feature.template.Template; import net.minecraftforge.client.ForgeHooksClient; import net.minecraftforge.client.model.data.EmptyModelData; -public class SchematicHologram { +public class SchematicRenderer { private final RegionRenderCacheBuilder bufferCache = new RegionRenderCacheBuilder(); private final Set usedBlockRenderLayers = new HashSet<>(RenderType.getBlockLayers().size()); @@ -47,17 +43,10 @@ public class SchematicHologram { private SchematicWorld schematic; private BlockPos anchor; - public SchematicHologram() { + public SchematicRenderer() { changed = false; } - public void startHologram(Template schematic, BlockPos anchor) { - SchematicWorld world = new SchematicWorld(new HashMap<>(), new Cuboid(BlockPos.ZERO, BlockPos.ZERO), anchor, - Minecraft.getInstance().world); - schematic.addBlocksToWorld(world, anchor, new PlacementSettings()); - startHologram(world); - } - public void startHologram(SchematicWorld world) { this.anchor = world.anchor; this.schematic = world; @@ -76,15 +65,47 @@ public class SchematicHologram { public void tick() { if (!active) return; - Minecraft minecraft = Minecraft.getInstance(); - if (minecraft.world == null) + Minecraft mc = Minecraft.getInstance(); + if (mc.world == null || mc.player == null || !changed) return; - if (minecraft.player == null) + + redraw(mc); + changed = false; + } + + public void render(MatrixStack ms, IRenderTypeBuffer buffer) { + // TODO 1.15 buffered render + if (!active) + return; + + final Entity entity = Minecraft.getInstance().getRenderViewEntity(); + + if (entity == null) { return; - if (changed) { - redraw(minecraft); - changed = false; } + + ActiveRenderInfo renderInfo = Minecraft.getInstance().gameRenderer.getActiveRenderInfo(); + Vec3d view = renderInfo.getProjectedView(); + double renderPosX = view.x; + double renderPosY = view.y; + double renderPosZ = view.z; + + RenderSystem.enableAlphaTest(); + RenderSystem.enableBlend(); + Minecraft.getInstance().getTextureManager().bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE); + + for (RenderType layer : RenderType.getBlockLayers()) { + if (!usedBlockRenderLayers.contains(layer)) { + continue; + } + final BufferBuilder bufferBuilder = bufferCache.get(layer); + RenderSystem.pushMatrix(); + RenderSystem.translated(-renderPosX, -renderPosY, -renderPosZ); + drawBuffer(bufferBuilder); + RenderSystem.popMatrix(); + } + RenderSystem.disableAlphaTest(); + RenderSystem.disableBlend(); } private void redraw(Minecraft minecraft) { @@ -112,21 +133,17 @@ public class SchematicHologram { bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); } } - // OptiFine Shaders compatibility - // if (Config.isShaders()) SVertexBuilder.pushEntity(state, pos, - // blockAccess, bufferBuilder); // Block transformations if (state.getBlock() instanceof BedBlock) { state = Blocks.QUARTZ_SLAB.getDefaultState(); } - if (blockRendererDispatcher.renderModel(state, pos, blockAccess, new MatrixStack(), bufferBuilder, true, minecraft.world.rand, EmptyModelData.INSTANCE)) { + if (blockRendererDispatcher.renderModel(state, pos, blockAccess, new MatrixStack(), bufferBuilder, true, + minecraft.world.rand, EmptyModelData.INSTANCE)) { usedBlockRenderLayers.add(blockRenderLayer); } blockstates.add(state); - // if (Config.isShaders()) - // SVertexBuilder.popEntity(bufferBuilder); } ForgeHooksClient.setRenderLayer(null); } @@ -140,42 +157,6 @@ public class SchematicHologram { } } - public void render(MatrixStack ms, IRenderTypeBuffer buffer) { - // TODO 1.15 buffered render - if (active) { - final Entity entity = Minecraft.getInstance().getRenderViewEntity(); - - if (entity == null) { - return; - } - - ActiveRenderInfo renderInfo = Minecraft.getInstance().gameRenderer.getActiveRenderInfo(); - Vec3d view = renderInfo.getProjectedView(); - double renderPosX = view.x; - double renderPosY = view.y; - double renderPosZ = view.z; - - RenderSystem.enableAlphaTest(); - RenderSystem.enableBlend(); - Minecraft.getInstance().getTextureManager().bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE); - - for (RenderType layer : RenderType.getBlockLayers()) { - if (!usedBlockRenderLayers.contains(layer)) { - continue; - } - final BufferBuilder bufferBuilder = bufferCache.get(layer); - RenderSystem.pushMatrix(); - RenderSystem.translated(-renderPosX, -renderPosY, -renderPosZ); - drawBuffer(bufferBuilder); - RenderSystem.popMatrix(); - } - RenderSystem.disableAlphaTest(); - RenderSystem.disableBlend(); - } - } - - // Coppied from WorldVertexBufferUploader - Draw everything but don't - // reset the buffer private static void drawBuffer(final BufferBuilder bufferBuilder) { Pair pair = bufferBuilder.popData(); BufferBuilder.DrawState state = pair.getFirst(); @@ -186,4 +167,5 @@ public class SchematicHologram { state.getVertexFormat().endDrawing(); } } + } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/SchematicTransformation.java b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicTransformation.java new file mode 100644 index 000000000..20eb873b6 --- /dev/null +++ b/src/main/java/com/simibubi/create/modules/schematics/client/SchematicTransformation.java @@ -0,0 +1,209 @@ +package com.simibubi.create.modules.schematics.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingAngle; +import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.Mirror; +import net.minecraft.util.Rotation; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.gen.feature.template.PlacementSettings; + +public class SchematicTransformation { + + private InterpolatedChasingValue x, y, z, scaleFrontBack, scaleLeftRight; + private InterpolatedChasingAngle rotation; + private double xOrigin; + private double zOrigin; + + public SchematicTransformation() { + x = new InterpolatedChasingValue(); + y = new InterpolatedChasingValue(); + z = new InterpolatedChasingValue(); + scaleFrontBack = new InterpolatedChasingValue(); + scaleLeftRight = new InterpolatedChasingValue(); + rotation = new InterpolatedChasingAngle(); + } + + public void init(BlockPos anchor, PlacementSettings settings, AxisAlignedBB bounds) { + int leftRight = settings.getMirror() == Mirror.LEFT_RIGHT ? -1 : 1; + int frontBack = settings.getMirror() == Mirror.FRONT_BACK ? -1 : 1; + scaleFrontBack.start(frontBack); + scaleLeftRight.start(leftRight); + xOrigin = bounds.getXSize() / 2f; + zOrigin = bounds.getZSize() / 2f; + + int r = -(settings.getRotation().ordinal() * 90); + rotation.start(r); + + Vec3d vec = fromAnchor(anchor); + x.start((float) vec.x); + y.start((float) vec.y); + z.start((float) vec.z); + } + + public void applyGLTransformations() { + float pt = Minecraft.getInstance().getRenderPartialTicks(); + + // Translation + RenderSystem.translated(x.get(pt), y.get(pt), z.get(pt)); + + Vec3d rotationOffset = getRotationOffset(true); + + // Rotation & Mirror + + RenderSystem.translated(xOrigin + rotationOffset.x, 0, zOrigin + rotationOffset.z); + RenderSystem.rotatef(rotation.get(pt), 0, 1, 0); + RenderSystem.translated(-rotationOffset.x, 0, -rotationOffset.z); + RenderSystem.scaled(scaleFrontBack.get(pt), 1, scaleLeftRight.get(pt)); + RenderSystem.translated(-xOrigin, 0, -zOrigin); + + } + + public Vec3d getRotationOffset(boolean ignoreMirrors) { + Vec3d rotationOffset = Vec3d.ZERO; + if ((int) (zOrigin * 2) % 2 != (int) (xOrigin * 2) % 2) { + boolean xGreaterZ = xOrigin > zOrigin; + float xIn = (xGreaterZ ? 0 : .5f); + float zIn = (!xGreaterZ ? 0 : .5f); + if (!ignoreMirrors) { + xIn *= getMirrorModifier(Axis.X); + zIn *= getMirrorModifier(Axis.Z); + } + rotationOffset = new Vec3d(xIn, 0, zIn); + } + return rotationOffset; + } + + public Vec3d toLocalSpace(Vec3d vec) { + float pt = Minecraft.getInstance().getRenderPartialTicks(); + Vec3d rotationOffset = getRotationOffset(true); + + vec = vec.subtract(x.get(pt), y.get(pt), z.get(pt)); + vec = vec.subtract(xOrigin + rotationOffset.x, 0, zOrigin + rotationOffset.z); + vec = VecHelper.rotate(vec, -rotation.get(pt), Axis.Y); + vec = vec.add(rotationOffset.x, 0, rotationOffset.z); + vec = vec.mul(scaleFrontBack.get(pt), 1, scaleLeftRight.get(pt)); + vec = vec.add(xOrigin, 0, zOrigin); + + return vec; + } + + public PlacementSettings toSettings() { + PlacementSettings settings = new PlacementSettings(); + + int i = (int) rotation.getTarget(); + + boolean mirrorlr = scaleLeftRight.getTarget() < 0; + boolean mirrorfb = scaleFrontBack.getTarget() < 0; + if (mirrorlr && mirrorfb) { + mirrorlr = mirrorfb = false; + i += 180; + } + i = i % 360; + if (i < 0) + i += 360; + + Rotation rotation = Rotation.NONE; + switch (i) { + case 90: + rotation = Rotation.COUNTERCLOCKWISE_90; + break; + case 180: + rotation = Rotation.CLOCKWISE_180; + break; + case 270: + rotation = Rotation.CLOCKWISE_90; + break; + default: + } + + settings.setRotation(rotation); + if (mirrorfb) + settings.setMirror(Mirror.FRONT_BACK); + if (mirrorlr) + settings.setMirror(Mirror.LEFT_RIGHT); + + return settings; + } + + public BlockPos getAnchor() { + Vec3d vec = Vec3d.ZERO.add(.5, 0, .5); + Vec3d rotationOffset = getRotationOffset(false); + vec = vec.subtract(xOrigin, 0, zOrigin); + vec = vec.subtract(rotationOffset.x, 0, rotationOffset.z); + vec = vec.mul(scaleFrontBack.getTarget(), 1, scaleLeftRight.getTarget()); + vec = VecHelper.rotate(vec, rotation.getTarget(), Axis.Y); + vec = vec.add(xOrigin, 0, zOrigin); + + vec = vec.add(x.getTarget(), y.getTarget(), z.getTarget()); + return new BlockPos(vec.x, vec.y, vec.z); + } + + public Vec3d fromAnchor(BlockPos pos) { + Vec3d vec = Vec3d.ZERO.add(.5, 0, .5); + Vec3d rotationOffset = getRotationOffset(false); + vec = vec.subtract(xOrigin, 0, zOrigin); + vec = vec.subtract(rotationOffset.x, 0, rotationOffset.z); + vec = vec.mul(scaleFrontBack.getTarget(), 1, scaleLeftRight.getTarget()); + vec = VecHelper.rotate(vec, rotation.getTarget(), Axis.Y); + vec = vec.add(xOrigin, 0, zOrigin); + + return new Vec3d(pos.subtract(new BlockPos(vec.x, vec.y, vec.z))); + } + + public int getRotationTarget() { + return (int) rotation.getTarget(); + } + + public int getMirrorModifier(Axis axis) { + if (axis == Axis.Z) + return (int) scaleLeftRight.getTarget(); + return (int) scaleFrontBack.getTarget(); + } + + public float getCurrentRotation() { + float pt = Minecraft.getInstance().getRenderPartialTicks(); + return rotation.get(pt); + } + + public void tick() { + x.tick(); + y.tick(); + z.tick(); + scaleLeftRight.tick(); + scaleFrontBack.tick(); + rotation.tick(); + } + + public void flip(Axis axis) { + if (axis == Axis.X) + scaleLeftRight.target(scaleLeftRight.getTarget() * -1); + if (axis == Axis.Z) + scaleFrontBack.target(scaleFrontBack.getTarget() * -1); + } + + public void rotate90(boolean clockwise) { + rotation.target(rotation.getTarget() + (clockwise ? -90 : 90)); + } + + public void move(float xIn, float yIn, float zIn) { + moveTo(x.getTarget() + xIn, y.getTarget() + yIn, z.getTarget() + zIn); + } + + public void moveTo(BlockPos pos) { + moveTo(pos.getX(), pos.getY(), pos.getZ()); + } + + public void moveTo(float xIn, float yIn, float zIn) { + x.target(xIn); + y.target(yIn); + z.target(zIn); + } + +} diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/DeployTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/DeployTool.java index 2b8a692a4..b84569cf1 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/DeployTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/DeployTool.java @@ -3,13 +3,19 @@ package com.simibubi.create.modules.schematics.client.tools; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllKeys; +import com.simibubi.create.AllSpecialTextures; +import com.simibubi.create.modules.schematics.client.SchematicTransformation; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.util.math.Vec3d; public class DeployTool extends PlacementToolBase { @@ -18,62 +24,79 @@ public class DeployTool extends PlacementToolBase { super.init(); selectionRange = -1; } - + @Override public void updateSelection() { - if (schematicHandler.active && selectionRange == -1) { - selectionRange = (int) schematicHandler.size.manhattanDistance(BlockPos.ZERO) / 2; + if (schematicHandler.isActive() && selectionRange == -1) { + selectionRange = (int) (schematicHandler.getBounds().getCenter().length() / 2); selectionRange = MathHelper.clamp(selectionRange, 1, 100); } selectIgnoreBlocks = AllKeys.ACTIVATE_TOOL.isPressed(); - super.updateSelection(); } - + @Override public void renderTool(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { super.renderTool(ms, buffer, light, overlay); - - if (selectedPos == null) + + if (selectedPos == null) return; - - BlockPos size = schematicHandler.getTransformedSize(); - BlockPos min = selectedPos.add(Math.round(size.getX() * -.5f), 0, Math.round(size.getZ() * -.5f)); - BlockPos max = min.add(size.getX(), size.getY(), size.getZ()); - - if (schematicHandler.deployed) { - MutableBoundingBox bb = new MutableBoundingBox(min, min.add(schematicHandler.getTransformedSize())); - min = new BlockPos(bb.minX, bb.minY, bb.minZ); - max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); - } - -// RenderSystem.color4f(.5f, .8f, 1, 1); TODO 1.15 - - WorldRenderer.drawBox(ms, buffer.getBuffer(RenderType.getLines()), min.getX() - 1 / 8d, min.getY() + 1 / 16d, min.getZ() - 1 / 8d, - max.getX() + 1 / 8d, max.getY() + 1 / 8d, max.getZ() + 1 / 8d, .8f, .9f, 1, 1); + + RenderSystem.pushMatrix(); + RenderHelper.disableStandardItemLighting(); + RenderSystem.enableBlend(); + float pt = Minecraft.getInstance().getRenderPartialTicks(); + double x = MathHelper.lerp(pt, lastChasingSelectedPos.x, chasingSelectedPos.x); + double y = MathHelper.lerp(pt, lastChasingSelectedPos.y, chasingSelectedPos.y); + double z = MathHelper.lerp(pt, lastChasingSelectedPos.z, chasingSelectedPos.z); + + SchematicTransformation transformation = schematicHandler.getTransformation(); + AxisAlignedBB bounds = schematicHandler.getBounds(); + Vec3d center = bounds.getCenter(); + Vec3d rotationOffset = transformation.getRotationOffset(true); + int centerX = (int) center.x; + int centerZ = (int) center.z; + double xOrigin = bounds.getXSize() / 2f; + double zOrigin = bounds.getZSize() / 2f; + + RenderSystem.translated(x - centerX, y, z - centerZ); + RenderSystem.translated(xOrigin + rotationOffset.x, 0, zOrigin + rotationOffset.z); + RenderSystem.rotatef(transformation.getCurrentRotation(), 0, 1, 0); + RenderSystem.translated(-rotationOffset.x, 0, -rotationOffset.z); + RenderSystem.translated(-xOrigin, 0, -zOrigin); + + schematicHandler.getOutline().setTextures(AllSpecialTextures.CHECKERED, null); + schematicHandler.getOutline().render(Tessellator.getInstance().getBuffer()); + schematicHandler.getOutline().setTextures(null, null); + RenderSystem.popMatrix(); } - + @Override public boolean handleMouseWheel(double delta) { - - if (selectIgnoreBlocks) { - selectionRange += delta; - selectionRange = MathHelper.clamp(selectionRange, 1, 100); - return true; - } - - return super.handleMouseWheel(delta); + if (!selectIgnoreBlocks) + return super.handleMouseWheel(delta); + selectionRange += delta; + selectionRange = MathHelper.clamp(selectionRange, 1, 100); + return true; } - + @Override public boolean handleRightClick() { if (selectedPos == null) return super.handleRightClick(); - - BlockPos size = schematicHandler.getTransformedSize(); - schematicHandler.moveTo(selectedPos.add(Math.round(size.getX() * -.5f), 0, Math.round(size.getZ() * -.5f))); - + Vec3d center = schematicHandler.getBounds().getCenter(); + BlockPos target = selectedPos.add(-((int) center.x), 0, -((int) center.z)); + + ItemStack item = schematicHandler.getActiveSchematicItem(); + if (item != null) { + item.getTag().putBoolean("Deployed", true); + item.getTag().put("Anchor", NBTUtil.writeBlockPos(target)); + } + + schematicHandler.getTransformation().moveTo(target); + schematicHandler.markDirty(); + schematicHandler.deploy(); return true; } - + } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/FlipTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/FlipTool.java index c404d4b58..59635bff3 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/FlipTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/FlipTool.java @@ -1,11 +1,23 @@ package com.simibubi.create.modules.schematics.client.tools; +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.foundation.utility.ColorHelper; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.Vec3d; + public class FlipTool extends PlacementToolBase { @Override public void init() { super.init(); - renderSelectedFace = true; + renderSelectedFace = false; } @Override @@ -23,17 +35,70 @@ public class FlipTool extends PlacementToolBase { @Override public void updateSelection() { super.updateSelection(); - - if (!schematicSelected) - return; - - renderSelectedFace = selectedFace.getAxis().isHorizontal(); } private void mirror() { if (schematicSelected && selectedFace.getAxis().isHorizontal()) { - schematicHandler.flip(selectedFace.getAxis()); + schematicHandler.getTransformation().flip(selectedFace.getAxis()); + schematicHandler.markDirty(); } } + @Override + public void renderToolLocal(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { + super.renderToolLocal(ms, buffer, light, overlay); + + if (!schematicSelected || !selectedFace.getAxis().isHorizontal()) + return; + + GlStateManager.pushMatrix(); + RenderHelper.disableStandardItemLighting(); + GlStateManager.enableBlend(); + + Direction facing = selectedFace.rotateY(); + Axis axis = facing.getAxis(); + Vec3d color = ColorHelper.getRGB(0x4d80e4); + AxisAlignedBB bounds = schematicHandler.getBounds(); + + Vec3d plane = VecHelper.planeByNormal(new Vec3d(facing.getDirectionVec())); + plane = plane.mul(bounds.getXSize() / 2f + 1, bounds.getYSize() / 2f + 1, bounds.getZSize() / 2f + 1); + Vec3d center = bounds.getCenter(); + + Vec3d v1 = plane.add(center); + plane = plane.mul(-1, 1, -1); + Vec3d v2 = plane.add(center); + plane = plane.mul(1, -1, 1); + Vec3d v3 = plane.add(center); + plane = plane.mul(-1, 1, -1); + Vec3d v4 = plane.add(center); + +// BufferBuilder buffer = Tessellator.getInstance().getBuffer();TODO 1.15 +// buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); +// +// AABBOutline outline = schematicHandler.getOutline(); +// AllSpecialTextures.BLANK.bind(); +// outline.renderAACuboidLine(v1, v2, color, 1, builder); +// outline.renderAACuboidLine(v2, v3, color, 1, builder); +// outline.renderAACuboidLine(v3, v4, color, 1, builder); +// outline.renderAACuboidLine(v4, v1, color, 1, builder); +// +// Tessellator.getInstance().draw(); +// buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); +// +// GlHelper.enableTextureRepeat(); +// GlStateManager.depthMask(false); +// Vec3d uDiff = v2.subtract(v1); +// Vec3d vDiff = v4.subtract(v1); +// float maxU = (float) Math.abs(axis == Axis.X ? uDiff.z : uDiff.x); +// float maxV = (float) Math.abs(axis == Axis.Y ? vDiff.z : vDiff.y); +// +// GlStateManager.enableCull(); +// AllSpecialTextures.HIGHLIGHT_CHECKERED.bind(); +// outline.putQuadUV(v1, v2, v3, v4, 0, 0, maxU, maxV, color, 1, builder); +// outline.putQuadUV(v2, v1, v4, v3, 0, 0, maxU, maxV, color, 1, builder); +// Tessellator.getInstance().draw(); +// GlStateManager.popMatrix(); +// GlHelper.disableTextureRepeat(); + } + } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/ISchematicTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/ISchematicTool.java index ba7ef001f..0d0647fe4 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/ISchematicTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/ISchematicTool.java @@ -14,6 +14,6 @@ public interface ISchematicTool { public void renderTool(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay); public void renderOverlay(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay); - + public void renderToolLocal(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay); } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveTool.java index 80500ba89..116f2f81f 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveTool.java @@ -1,5 +1,11 @@ package com.simibubi.create.modules.schematics.client.tools; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.modules.schematics.client.SchematicTransformation; + +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.Vec3d; + public class MoveTool extends PlacementToolBase { @Override @@ -17,13 +23,19 @@ public class MoveTool extends PlacementToolBase { renderSelectedFace = selectedFace.getAxis().isHorizontal(); } - + @Override public boolean handleMouseWheel(double delta) { - if (schematicSelected && selectedFace.getAxis().isHorizontal()) { - schematicHandler.moveTo(delta < 0 ? schematicHandler.anchor.add(selectedFace.getDirectionVec()) - : schematicHandler.anchor.subtract(selectedFace.getDirectionVec())); - } + if (!schematicSelected || !selectedFace.getAxis().isHorizontal()) + return true; + + SchematicTransformation transformation = schematicHandler.getTransformation(); + Vec3d vec = new Vec3d(selectedFace.getDirectionVec()).scale(-Math.signum(delta)); + vec = vec.mul(transformation.getMirrorModifier(Axis.X), 1, transformation.getMirrorModifier(Axis.Z)); + vec = VecHelper.rotate(vec, transformation.getRotationTarget(), Axis.Y); + transformation.move((float) vec.x, 0, (float) vec.z); + schematicHandler.markDirty(); + return true; } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveVerticalTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveVerticalTool.java index 3910a0a22..a0d583018 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveVerticalTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/MoveVerticalTool.java @@ -4,8 +4,9 @@ public class MoveVerticalTool extends PlacementToolBase { @Override public boolean handleMouseWheel(double delta) { - if (schematicHandler.deployed) { - schematicHandler.moveTo(schematicHandler.anchor.add(0, delta, 0)); + if (schematicHandler.isDeployed()) { + schematicHandler.getTransformation().move(0, (float) Math.signum(delta), 0); + schematicHandler.markDirty(); } return true; } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/RotateTool.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/RotateTool.java index 171f132f0..0e150bc21 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/RotateTool.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/RotateTool.java @@ -1,13 +1,39 @@ package com.simibubi.create.modules.schematics.client.tools; -import net.minecraft.util.Rotation; +import com.mojang.blaze3d.matrix.MatrixStack; + +import net.minecraft.client.renderer.IRenderTypeBuffer; public class RotateTool extends PlacementToolBase { @Override public boolean handleMouseWheel(double delta) { - schematicHandler.rotate(delta > 0 ? Rotation.CLOCKWISE_90 : Rotation.COUNTERCLOCKWISE_90); + schematicHandler.getTransformation().rotate90(delta > 0); + schematicHandler.markDirty(); return true; } + @Override + public void renderToolLocal(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { + super.renderToolLocal(ms, buffer, light, overlay); + +// GlStateManager.pushMatrix();TODO 1.15 +// RenderHelper.disableStandardItemLighting(); +// GlStateManager.enableBlend(); +// +// Vec3d color = ColorHelper.getRGB(0x4d80e4); +// AxisAlignedBB bounds = schematicHandler.getBounds(); +// double height = bounds.getYSize() + Math.max(20, bounds.getYSize()); +// +// Vec3d center = bounds.getCenter().add(schematicHandler.getTransformation().getRotationOffset(false)); +// Vec3d start = center.subtract(0, height / 2, 0); +// Vec3d end = center.add(0, height / 2, 0); +// +// BufferBuilder buffer = Tessellator.getInstance().getBuffer(); +// buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.PARTICLE_POSITION_TEX_COLOR_LMAP); +// schematicHandler.getOutline().renderAACuboidLine(start, end, color, 1, buffer); +// Tessellator.getInstance().draw(); +// GlStateManager.popMatrix(); + } + } diff --git a/src/main/java/com/simibubi/create/modules/schematics/client/tools/SchematicToolBase.java b/src/main/java/com/simibubi/create/modules/schematics/client/tools/SchematicToolBase.java index 0b8ad5fa2..cfc450a38 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/client/tools/SchematicToolBase.java +++ b/src/main/java/com/simibubi/create/modules/schematics/client/tools/SchematicToolBase.java @@ -1,24 +1,29 @@ package com.simibubi.create.modules.schematics.client.tools; +import java.util.Arrays; +import java.util.List; + import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllKeys; +import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; +import com.simibubi.create.foundation.utility.VecHelper; +import com.simibubi.create.foundation.utility.outliner.AABBOutline; import com.simibubi.create.modules.schematics.client.SchematicHandler; +import com.simibubi.create.modules.schematics.client.SchematicTransformation; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.item.ItemUseContext; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; 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.util.math.MutableBoundingBox; import net.minecraft.util.math.RayTraceResult.Type; import net.minecraft.util.math.Vec3d; @@ -26,13 +31,18 @@ public abstract class SchematicToolBase implements ISchematicTool { protected SchematicHandler schematicHandler; - public BlockPos selectedPos; - public boolean selectIgnoreBlocks; - public int selectionRange; + protected BlockPos selectedPos; + protected Vec3d chasingSelectedPos; + protected Vec3d lastChasingSelectedPos; - public boolean schematicSelected; - public boolean renderSelectedFace; - public Direction selectedFace; + protected boolean selectIgnoreBlocks; + protected int selectionRange; + protected boolean schematicSelected; + protected boolean renderSelectedFace; + protected Direction selectedFace; + + protected final List mirrors = Arrays.asList("none", "leftRight", "frontBack"); + protected final List rotations = Arrays.asList("none", "cw90", "cw180", "cw270"); @Override public void init() { @@ -40,78 +50,95 @@ public abstract class SchematicToolBase implements ISchematicTool { selectedPos = null; selectedFace = null; schematicSelected = false; + chasingSelectedPos = Vec3d.ZERO; + lastChasingSelectedPos = Vec3d.ZERO; } @Override public void updateSelection() { + updateTargetPos(); + + if (selectedPos == null) + return; + lastChasingSelectedPos = chasingSelectedPos; + Vec3d target = new Vec3d(selectedPos); + if (target.distanceTo(chasingSelectedPos) < 1 / 512f) { + chasingSelectedPos = target; + return; + } + + chasingSelectedPos = chasingSelectedPos.add(target.subtract(chasingSelectedPos).scale(1 / 2f)); + } + + public void updateTargetPos() { ClientPlayerEntity player = Minecraft.getInstance().player; // Select Blueprint - if (schematicHandler.deployed) { - BlockPos min = schematicHandler.getTransformedAnchor(); - MutableBoundingBox bb = new MutableBoundingBox(min, min.add(schematicHandler.getTransformedSize())); - PredicateTraceResult result = RaycastHelper.rayTraceUntil(player, 70, - pos -> bb.isVecInside(pos)); + if (schematicHandler.isDeployed()) { + SchematicTransformation transformation = schematicHandler.getTransformation(); + AxisAlignedBB localBounds = schematicHandler.getBounds(); + + Vec3d traceOrigin = RaycastHelper.getTraceOrigin(player); + Vec3d start = transformation.toLocalSpace(traceOrigin); + Vec3d end = transformation.toLocalSpace(RaycastHelper.getTraceTarget(player, 70, traceOrigin)); + PredicateTraceResult result = + RaycastHelper.rayTraceUntil(start, end, pos -> localBounds.contains(VecHelper.getCenterOf(pos))); + schematicSelected = !result.missed(); selectedFace = schematicSelected ? result.getFacing() : null; } + boolean snap = this.selectedPos == null; + // Select location at distance if (selectIgnoreBlocks) { - selectedPos = new BlockPos(player.getEyePosition(Minecraft.getInstance().getRenderPartialTicks()) - .add(player.getLookVec().scale(selectionRange))); + float pt = Minecraft.getInstance().getRenderPartialTicks(); + selectedPos = new BlockPos(player.getEyePosition(pt).add(player.getLookVec().scale(selectionRange))); + if (snap) + lastChasingSelectedPos = chasingSelectedPos = new Vec3d(selectedPos); return; } // Select targeted Block + selectedPos = null; BlockRayTraceResult trace = RaycastHelper.rayTraceRange(player.world, player, 75); - if (trace != null && trace.getType() == Type.BLOCK) { + if (trace == null || trace.getType() != Type.BLOCK) + return; - BlockPos hit = new BlockPos(trace.getHitVec()); - boolean replaceable = player.world.getBlockState(hit) - .isReplaceable(new BlockItemUseContext(new ItemUseContext(player, Hand.MAIN_HAND, trace))); - if (trace.getFace().getAxis().isVertical() && !replaceable) - hit = hit.offset(trace.getFace()); - - selectedPos = hit; - } else { - selectedPos = null; - } + BlockPos hit = new BlockPos(trace.getHitVec()); + boolean replaceable = player.world.getBlockState(hit).getMaterial().isReplaceable(); + if (trace.getFace().getAxis().isVertical() && !replaceable) + hit = hit.offset(trace.getFace()); + selectedPos = hit; + if (snap) + lastChasingSelectedPos = chasingSelectedPos = new Vec3d(selectedPos); } @Override public void renderTool(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { + if (!schematicHandler.isDeployed()) + return; - if (schematicHandler.deployed) { - BlockPos min = schematicHandler.getTransformedAnchor(); - MutableBoundingBox bb = new MutableBoundingBox(min, min.add(schematicHandler.getTransformedSize())); - min = new BlockPos(bb.minX, bb.minY, bb.minZ); - BlockPos max = new BlockPos(bb.maxX, bb.maxY, bb.maxZ); - - WorldRenderer.drawBox(buffer.getBuffer(RenderType.getLines()), min.getX() - 1 / 8d, min.getY() + 1 / 16d, min.getZ() - 1 / 8d, - max.getX() + 1 / 8d, max.getY() + 1 / 8d, max.getZ() + 1 / 8d, 1, 1, 1, 1); - - if (schematicSelected && renderSelectedFace && AllKeys.ACTIVATE_TOOL.isPressed()) { - Vec3d vec = new Vec3d(selectedFace.getDirectionVec()); - Vec3d center = new Vec3d(min.add(max)).scale(1 / 2f); - Vec3d radii = new Vec3d(max.subtract(min)).scale(1 / 2f); - - Vec3d onFaceOffset = new Vec3d(1 - Math.abs(vec.x), 1 - Math.abs(vec.y), 1 - Math.abs(vec.z)) - .mul(radii); - Vec3d faceMin = center.add(vec.mul(radii).add(onFaceOffset)).add(vec.scale(1/8f)); - Vec3d faceMax = center.add(vec.mul(radii).subtract(onFaceOffset)).add(vec.scale(1/8f)); - - // RenderSystem.lineWidth(6); TODO 1.15 custom line size render type - WorldRenderer.drawBox(buffer.getBuffer(RenderType.getLines()), faceMin.getX(), faceMin.getY() + 1 / 16d, faceMin.getZ(), faceMax.getX(), - faceMax.getY() + 1 / 8d, faceMax.getZ(), .6f, .7f, 1, 1); - } + AABBOutline outline = schematicHandler.getOutline(); + if (renderSelectedFace) { + schematicHandler.getOutline().setTextures(null, + AllKeys.ctrlDown() ? AllSpecialTextures.HIGHLIGHT_CHECKERED : AllSpecialTextures.CHECKERED); + outline.highlightFace(selectedFace); } + RenderHelper.disableStandardItemLighting(); + RenderSystem.pushMatrix(); + RenderSystem.enableBlend(); + outline.render(Tessellator.getInstance().getBuffer()); + RenderSystem.popMatrix(); + outline.setTextures(null, null); + } @Override - public void renderOverlay(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) { - - } + public void renderOverlay(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) {} + + @Override + public void renderToolLocal(MatrixStack ms, IRenderTypeBuffer buffer, int light, int overlay) {} } diff --git a/src/main/java/com/simibubi/create/modules/schematics/item/SchematicItem.java b/src/main/java/com/simibubi/create/modules/schematics/item/SchematicItem.java index c0cc6a790..c53bc74fa 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/item/SchematicItem.java +++ b/src/main/java/com/simibubi/create/modules/schematics/item/SchematicItem.java @@ -75,22 +75,20 @@ public class SchematicItem extends Item { public static void writeSize(ItemStack blueprint) { CompoundNBT tag = blueprint.getTag(); - Template t = getSchematic(blueprint); + Template t = loadSchematic(blueprint); tag.put("Bounds", NBTUtil.writeBlockPos(t.getSize())); blueprint.setTag(tag); } public static PlacementSettings getSettings(ItemStack blueprint) { CompoundNBT tag = blueprint.getTag(); - PlacementSettings settings = new PlacementSettings(); settings.setRotation(Rotation.valueOf(tag.getString("Rotation"))); settings.setMirror(Mirror.valueOf(tag.getString("Mirror"))); - return settings; } - public static Template getSchematic(ItemStack blueprint) { + public static Template loadSchematic(ItemStack blueprint) { Template t = new Template(); String owner = blueprint.getTag().getString("Owner"); String schematic = blueprint.getTag().getString("File"); @@ -120,14 +118,25 @@ public class SchematicItem extends Item { @Override public ActionResultType onItemUse(ItemUseContext context) { - if (context.getPlayer().isSneaking() && context.getHand() == Hand.MAIN_HAND) { - DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { - displayBlueprintScreen(); - }); - return ActionResultType.SUCCESS; - } + if (!onItemUse(context.getPlayer(), context.getHand())) + return super.onItemUse(context); + return ActionResultType.SUCCESS; + } - return super.onItemUse(context); + @Override + public ActionResult onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) { + if (!onItemUse(playerIn, handIn)) + return super.onItemRightClick(worldIn, playerIn, handIn); + return new ActionResult(ActionResultType.SUCCESS, playerIn.getHeldItem(handIn)); + } + + private boolean onItemUse(PlayerEntity player, Hand hand) { + if (!player.isSneaking() || hand != Hand.MAIN_HAND) + return false; + if (!player.getHeldItem(hand).hasTag()) + return false; + DistExecutor.runWhenOn(Dist.CLIENT, () -> this::displayBlueprintScreen); + return true; } @OnlyIn(value = Dist.CLIENT) @@ -135,17 +144,4 @@ public class SchematicItem extends Item { ScreenOpener.open(new SchematicEditScreen()); } - @Override - public ActionResult onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) { - if (playerIn.isSneaking() && handIn == Hand.MAIN_HAND) { - if (playerIn.getHeldItem(handIn).hasTag()) - DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> { - displayBlueprintScreen(); - }); - return new ActionResult(ActionResultType.SUCCESS, playerIn.getHeldItem(handIn)); - } - - return super.onItemRightClick(worldIn, playerIn, handIn); - } - } diff --git a/src/main/java/com/simibubi/create/modules/schematics/packet/SchematicPlacePacket.java b/src/main/java/com/simibubi/create/modules/schematics/packet/SchematicPlacePacket.java index c58b5212d..82db762ef 100644 --- a/src/main/java/com/simibubi/create/modules/schematics/packet/SchematicPlacePacket.java +++ b/src/main/java/com/simibubi/create/modules/schematics/packet/SchematicPlacePacket.java @@ -31,7 +31,7 @@ public class SchematicPlacePacket extends SimplePacketBase { public void handle(Supplier context) { context.get().enqueueWork(() -> { ServerPlayerEntity player = context.get().getSender(); - Template t = SchematicItem.getSchematic(stack); + Template t = SchematicItem.loadSchematic(stack); t.addBlocksToWorld(player.getServerWorld(), NBTUtil.readBlockPos(stack.getTag().getCompound("Anchor")), SchematicItem.getSettings(stack)); }); diff --git a/src/main/resources/assets/create/blockstates/plough.json b/src/main/resources/assets/create/blockstates/plough.json new file mode 100644 index 000000000..1805fe595 --- /dev/null +++ b/src/main/resources/assets/create/blockstates/plough.json @@ -0,0 +1,14 @@ +{ + "forge_marker": 1, + "defaults": { + "model": "create:block/plough" + }, + "variants": { + "facing": { + "north": { "y": 180 }, + "south": {}, + "east": { "y": 270 }, + "west": { "y": 90 } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/lang/de_de.json b/src/main/resources/assets/create/lang/de_de.json index bee30b997..a2f647e60 100644 --- a/src/main/resources/assets/create/lang/de_de.json +++ b/src/main/resources/assets/create/lang/de_de.json @@ -151,12 +151,12 @@ "create.recipe.crushing":"Mahlen", "create.recipe.splashing":"Waschen", "create.recipe.splashing.fan":"Propeller hinter fließendem Wasser", - "create.recipe.smokingViaFan":"Räuchern", - "create.recipe.smokingViaFan.fan":"Propeller hinter Feuer", - "create.recipe.blastingViaFan":"Schmelzen", - "create.recipe.blastingViaFan.fan":"Propeller hinter Lava", + "create.recipe.smoking_via_fan":"Räuchern", + "create.recipe.smoking_via_fan.fan":"Propeller hinter Feuer", + "create.recipe.blasting_via_fan":"Schmelzen", + "create.recipe.blasting_via_fan.fan":"Propeller hinter Lava", "create.recipe.pressing":"Mechanische Presse", - "create.recipe.blockzapperUpgrade":"Blockpistole", + "create.recipe.blockzapper_upgrade":"Blockpistole", "create.recipe.processing.chance":"Chance: %1$s%%", "create.generic.range":"Reichweite", diff --git a/src/main/resources/assets/create/lang/en_us.json b/src/main/resources/assets/create/lang/en_us.json index 06d09ad10..566681264 100644 --- a/src/main/resources/assets/create/lang/en_us.json +++ b/src/main/resources/assets/create/lang/en_us.json @@ -36,6 +36,8 @@ "item.create.crushed_gold": "Crushed Gold Ore", "item.create.sand_paper": "Sand Paper", "item.create.red_sand_paper": "Red Sand Paper", + "item.create.super_glue": "Super Glue", + "item.create.minecart_contraption": "Minecart with Contraption", "item.create.brass_ingot": "Brass Ingot", "item.create.brass_sheet": "Brass Sheets", @@ -98,6 +100,7 @@ "block.create.drill": "Mechanical Drill", "block.create.portable_storage_interface": "Portable Storage Interface", "block.create.harvester": "Mechanical Harvester", + "block.create.plough": "Mechanical Plough", "block.create.saw": "Mechanical Saw", "block.create.water_wheel": "Water Wheel", "block.create.mechanical_press": "Mechanical Press", @@ -256,6 +259,10 @@ "block.create.creative_crate": "Schematicannon Creatifier", "block.create.cocoa_log": "Cocoa Jungle Log", + + "entity.create.contraption": "Moving Contraption", + "entity.create.stationary_contraption": "Stationary Contraption", + "entity.create.super_glue": "Superglue", "_comment": "-------------------------] UI & MESSAGES [------------------------------------------------", @@ -272,17 +279,17 @@ "create.recipe.milling": "Milling", "create.recipe.splashing": "Bulk Washing", "create.recipe.splashing.fan": "Fan behind Flowing Water", - "create.recipe.smokingViaFan": "Bulk Smoking", - "create.recipe.smokingViaFan.fan": "Fan behind Fire", - "create.recipe.blastingViaFan": "Bulk Smelting", - "create.recipe.blastingViaFan.fan": "Fan behind Lava", + "create.recipe.smoking_via_fan": "Bulk Smoking", + "create.recipe.smoking_via_fan.fan": "Fan behind Fire", + "create.recipe.blasting_via_fan": "Bulk Smelting", + "create.recipe.blasting_via_fan.fan": "Fan behind Lava", "create.recipe.pressing": "Pressing", "create.recipe.mixing": "Mixing", "create.recipe.packing": "Compacting", "create.recipe.sawing": "Sawing", "create.recipe.mechanical_crafting": "Mechanical Crafting", "create.recipe.block_cutting": "Block Cutting", - "create.recipe.blockzapperUpgrade": "Handheld Blockzapper", + "create.recipe.blockzapper_upgrade": "Handheld Blockzapper", "create.recipe.sandpaper_polishing": "Sandpaper Polishing", "create.recipe.mystery_conversion": "Chromatic Metamorphosis", "create.recipe.processing.catalyst": "Catalyst", @@ -385,6 +392,10 @@ "create.contraptions.movement_mode.rotate_place": "Always Place when Stopped", "create.contraptions.movement_mode.rotate_place_returned": "Only Place near Initial Angle", "create.contraptions.movement_mode.rotate_never_place": "Only Place when Anchor Destroyed", + "create.contraptions.cart_movement_mode": "Cart Movement Mode", + "create.contraptions.cart_movement_mode.rotate": "Always face toward motion", + "create.contraptions.cart_movement_mode.rotate_paused": "Pause actors while rotating", + "create.contraptions.cart_movement_mode.rotation_locked": "Lock rotation", "create.logistics.filter": "Filter", "create.logistics.firstFrequency": "Freq. #1", @@ -876,8 +887,8 @@ "block.create.mechanical_press.tooltip.behaviour1": "_Starts_ to compress items dropped below it.", "block.create.mechanical_press.tooltip.condition2": "When Above a Mechanical Belt", "block.create.mechanical_press.tooltip.behaviour2": "_Automatically_ compresses bypassing items on the Belt.", - "block.create.mechanical_mixer.tooltip.condition3": "When above Basin", - "block.create.mechanical_mixer.tooltip.behaviour3": "Starts to _compact_ _items_ in the basin whenever all necessary ingredients are present.", + "block.create.mechanical_press.tooltip.condition3": "When above Basin", + "block.create.mechanical_press.tooltip.behaviour3": "Starts to _compact_ _items_ in the basin whenever all necessary ingredients are present.", "block.create.basin.tooltip": "BASIN", "block.create.basin.tooltip.summary": "A handy _item_ _container_ used in processing with the _Mechanical_ _Mixer_ and the _Mechanical_ _Press_. Supports _Redstone_ _Comparators_.", @@ -981,16 +992,21 @@ "block.create.rotation_chassis.tooltip.action1": "Makes the clicked face _Sticky_. When Chassis move, all designated blocks attached to the sticky side are moved with it.", "block.create.drill.tooltip": "MECHANICAL DRILL", - "block.create.drill.tooltip.summary": "A mechanical device suitable for _breaking_ _blocks_. It is movable with _Mechanical_ _Pistons_ or _Bearings_.", + "block.create.drill.tooltip.summary": "A mechanical device suitable for _breaking_ _blocks_. It is movable with _Mechanical_ _Pistons_, _Bearings_ or other controllers.", "block.create.drill.tooltip.condition1": "When Rotated", "block.create.drill.tooltip.behaviour1": "Acts as a _stationary_ Block Breaker. Also _hurts_ _entities_ in its effective area.", "block.create.drill.tooltip.condition2": "While Moving", "block.create.drill.tooltip.behaviour2": "Breaks Blocks with which the drill collides.", "block.create.harvester.tooltip": "MECHANICAL HARVESTER", - "block.create.harvester.tooltip.summary": "A mechanical plant cutter suitable for medium scale crop automation. It is movable with _Mechanical_ _Pistons_ or _Bearings_.", + "block.create.harvester.tooltip.summary": "A mechanical plant cutter suitable for medium scale crop automation. It is movable with _Mechanical_ _Pistons_, _Bearings_ or other controllers.", "block.create.harvester.tooltip.condition1": "While Moving", "block.create.harvester.tooltip.behaviour1": "_Harvests_ all _mature_ _crops_ which which the blade collides and reset them to their initial growth state.", + + "block.create.plough.tooltip": "MECHANICAL PLOUGH", + "block.create.plough.tooltip.summary": "A mechanical plough has a variety of uses. It is movable with _Mechanical_ _Pistons_, _Bearings_ or other controllers.", + "block.create.plough.tooltip.condition1": "While Moving", + "block.create.plough.tooltip.behaviour1": "_Breaks_ _blocks_ which _cannot_ _be_ _collided_ with, such as torches, tracks or snow layers. _Applies_ its _motion_ to _entities_ without hurting them. _Tills_ _soil_ _blocks_ as though a Hoe would be used on them.", "block.create.saw.tooltip": "MECHANICAL SAW", "block.create.saw.tooltip.summary": "Suitable for _cutting_ _trees_ effectively and for _cutting_ _blocks_ into their carpentered counterparts. It is movable using _Mechanical_ _Pistons_ or _Bearings_.", @@ -1020,7 +1036,7 @@ "block.create.redstone_bridge.tooltip.action2": "Toggles between _Receiver_ and _Transmitter_ Mode.", "block.create.contact.tooltip": "REDSTONE CONTACT", - "block.create.contact.tooltip.summary": "Only emits redstone power in pairs. It is movable with _Mechanical_ _Pistons_ or _Bearings_.", + "block.create.contact.tooltip.summary": "Only emits redstone power in pairs. It is movable with _Mechanical_ _Pistons_, _Bearings_ or other controllers.", "block.create.contact.tooltip.condition1": "When facing other Contact", "block.create.contact.tooltip.behaviour1": "Provides a _Redstone_ _Signal_.", "block.create.contact.tooltip.condition2": "While Moving", @@ -1134,6 +1150,13 @@ "tool.create.sand_paper.tooltip.summary": "A rough paper that can be used to _polish_ _materials_. Can be automatically applied using the Deployer.", "tool.create.sand_paper.tooltip.condition1": "When Used", "tool.create.sand_paper.tooltip.behaviour1": "Applies polish to items held in the _offhand_ or lying on the _floor_ when _looking_ _at_ _them_", + + "item.create.super_glue.tooltip": "SUPER GLUE", + "item.create.super_glue.tooltip.summary": "Glue a block to another, and they will forever be inseparable.", + "item.create.super_glue.tooltip.condition1": "When Used", + "item.create.super_glue.tooltip.behaviour1": "Makes the _clicked_ _face_ of a block _sticky_. Blocks attached to sticky faces will be _dragged_ _along_ when moved by _mechanical_ _pistons_, _bearings_ and other controllers.", + "item.create.super_glue.tooltip.condition2": "When Held in Offhand", + "item.create.super_glue.tooltip.behaviour2": "_Automatically_ _attaches_ blocks placed from the main hand to the _side_ they were _placed_ _against._", "item.create.refined_radiance.tooltip": "REFINED RADIANCE", "item.create.refined_radiance.tooltip.summary": "A Chromatic material forged from _absorbed_ _light_.", diff --git a/src/main/resources/assets/create/lang/fr_fr.json b/src/main/resources/assets/create/lang/fr_fr.json index ae456fc26..f045cbea1 100644 --- a/src/main/resources/assets/create/lang/fr_fr.json +++ b/src/main/resources/assets/create/lang/fr_fr.json @@ -283,17 +283,17 @@ "create.recipe.crushing": "Ecrasement", "create.recipe.splashing": "Lavage en vrac", "create.recipe.splashing.fan": "Ventilateur derrière de l'eau qui coule", - "create.recipe.smokingViaFan": "Fumer en vrac", - "create.recipe.smokingViaFan.fan": "Fan behind Fire", - "create.recipe.blastingViaFan": "Ventilateur derrière du feu", - "create.recipe.blastingViaFan.fan": "Ventilateur derrière de la lave", + "create.recipe.smoking_via_fan": "Fumer en vrac", + "create.recipe.smoking_via_fan.fan": "Fan behind Fire", + "create.recipe.blasting_via_fan": "Ventilateur derrière du feu", + "create.recipe.blasting_via_fan.fan": "Ventilateur derrière de la lave", "create.recipe.pressing": "Pressage", "create.recipe.mixing": "Mixage", "create.recipe.packing": "Compactage", "create.recipe.sawing": "Sciage", "create.recipe.mechanical_crafting": "Fabrication mécanique", "create.recipe.block_cutting": "Coupe de bloc", - "create.recipe.blockzapperUpgrade": "Blockzappeur portable", + "create.recipe.blockzapper_upgrade": "Blockzappeur portable", "create.recipe.sandpaper_polishing": "Polissage au papier de verre", "create.recipe.mystery_conversion": "Métamorphose chromatique", "create.recipe.processing.catalyst": "Catalyseur", diff --git a/src/main/resources/assets/create/lang/it_it.json b/src/main/resources/assets/create/lang/it_it.json new file mode 100644 index 000000000..631e7e68f --- /dev/null +++ b/src/main/resources/assets/create/lang/it_it.json @@ -0,0 +1,1156 @@ +{ + + "_comment": "-------------------------] GAME ELEMENTS [------------------------------------------------", + + "item.create.symmetry_wand": "Asta di Simetria", + "item.create.placement_handgun": "Zapper di Blocchi Portatile", + "item.create.terrain_zapper": "Plasmatore del Mondo Portatile", + "item.create.tree_fertilizer": "Fertilizzante per Alberi", + "item.create.empty_blueprint": "Schematica Vuota", + "item.create.andesite_alloy": "Lega di Andesite", + "item.create.chromatic_compound": "Composto Cromatico", + "item.create.shadow_steel": "Acciaio Oscuro", + "item.create.blueprint_and_quill": "Schematica e Penna d'Oca", + "item.create.blueprint": "Schematica", + "item.create.belt_connector": "Nastro Meccanico", + "item.create.goggles": "Occhiali da Ingegnere", + "item.create.filter": "Filtro", + "item.create.property_filter": "Filtro Attributi", + "item.create.rose_quartz": "Quarzo Rosa", + "item.create.polished_rose_quartz": "Quarzo Rosa Levigato", + "item.create.refined_radiance": "Radiance Raffinata", + "item.create.iron_sheet": "Lamiera di Ferro", + "item.create.gold_sheet": "Lamiera di Oro", + "item.create.lapis_plate": "Placcatura di Lapislazzuli", + "item.create.obsidian_dust": "Polvere di Ossidiana", + "item.create.propeller": "Elica", + "item.create.whisk": "Frusta", + "item.create.brass_hand": "Mano", + "item.create.slot_cover": "Rivestimento Slot Creazione", + "item.create.zinc_handle": "Impugnatura per Strumenti di Qualità", + "item.create.flour": "Farina di Grano", + "item.create.dough": "Impasto", + "item.create.wrench": "Chiave Inglese", + "item.create.deforester": "Deforestatore", + "item.create.crushed_iron": "Ferro Grezzo Frantumato", + "item.create.crushed_gold": "Oro Grezzo Frantumato", + "item.create.sand_paper": "Carta Vetrata", + "item.create.red_sand_paper": "Carta Vetrata Rossa", + + "item.create.brass_ingot": "Lingotto di Ottone", + "item.create.brass_sheet": "Lamiera di Ottone", + "item.create.brass_nugget": "Pepita di Ottone", + "item.create.crushed_brass": "Ottone Frantumato", + "item.create.zinc_ingot": "Barra di Zinco", + "item.create.zinc_nugget": "Pepita di Zinco", + "item.create.crushed_zinc": "Zinco Frantumato", + "item.create.copper_sheet": "Lamiera di Rame", + "item.create.copper_ingot": "Lingotto di Rame", + "item.create.copper_nugget": "Pepita di Rame", + "item.create.crushed_copper": "Rame Frantumato", + + "item.create.electron_tube": "Valvola", + "item.create.integrated_circuit": "Circuito Integrato", + + "item.create.blazing_pickaxe": "Piccone Fiammeggiante", + "item.create.blazing_shovel": "Pala Fiammeggiante", + "item.create.blazing_axe": "Ascia Fiammeggiante", + "item.create.blazing_sword": "Mannaia Fiammeggiante", + + "item.create.shadow_steel_pickaxe": "Piccone di Acciaio Oscuro", + "item.create.shadow_steel_mattock": "Zappa di Acciaio Oscuro", + "item.create.shadow_steel_sword": "Spada di Acciaio Oscuro", + + "item.create.rose_quartz_pickaxe": "Piccone di Quarzo Dorato", + "item.create.rose_quartz_shovel": "Pala di Quarzo Dorato", + "item.create.rose_quartz_axe": "Ascia di Quarzo Dorato", + "item.create.rose_quartz_sword": "Spada di Quarzo Dorato", + + "block.create.copper_ore": "Rame Grezzo", + "block.create.copper_block": "Blocco di Rame", + "block.create.copper_shingles": "Tegole di Rame", + "block.create.zinc_ore": "Zinco Grezzo", + "block.create.zinc_block": "Blocco di Zinco", + "block.create.brass_block": "Blocco di Ottone", + + "block.create.andesite_casing": "Involucro di Andesite", + "block.create.brass_casing": "Involucro di Ottone", + "block.create.copper_casing": "Involucro di Rame", + + "block.create.cogwheel": "Ruota Dentata", + "block.create.large_cogwheel": "Ruota Dentata Grande", + "block.create.turntable": "Piatto", + "block.create.gearbox": "Riduttore", + "block.create.gearshift": "Cambio", + "block.create.clutch": "Frizione", + "block.create.shaft": "Albero", + "block.create.encased_belt": "Nastro Incassato", + "block.create.encased_shaft": "Albero Incassato", + "block.create.encased_fan": "Ventilatore incassato", + "block.create.adjustable_pulley": "Puleggia analogica", + "block.create.nozzle": "Ugello", + "block.create.hand_crank": "Manovella", + "block.create.cuckoo_clock": "Orologio a Cucù", + "block.create.creative_motor": "Motore", + "block.create.belt": "Nastro Meccanico", + "block.create.millstone": "Macina", + "block.create.crushing_wheel": "Ruota di Frantumazione", + "block.create.drill": "Trapano Meccanico", + "block.create.portable_storage_interface": "Interfaccia di Archiviazione Portatile", + "block.create.harvester": "Mietitrice Meccanica", + "block.create.saw": "Sega Meccanica", + "block.create.water_wheel": "Ruota d'Acqua", + "block.create.mechanical_press": "Pressa Meccanica", + "block.create.mechanical_mixer": "Miscelatore Meccanico", + "block.create.deployer": "Installatore", + "block.create.basin": "Bacinella", + "block.create.mechanical_crafter": "Costruttore Meccanico", + "block.create.flywheel": "Volano", + "block.create.furnace_engine": "Motore Fornace", + "block.create.speed_gauge": "Tachimetro", + "block.create.stress_gauge": "Stressometro", + "block.create.cart_assembler": "Assemblatore Carrello da Miniera", + "block.create.analog_lever": "Leva Analogica", + "block.create.rotation_speed_controller": "Regolatore di Velocità di Rotazione", + + "block.create.sticky_mechanical_piston": "Pistome Meccanico Appiccicoso", + "block.create.mechanical_piston": "Pistome Meccanico", + "block.create.mechanical_piston_head": "Testa Pistome Meccanico", + "block.create.piston_pole": "Palo Pistome", + "block.create.mechanical_bearing": "Supporto Meccanico", + "block.create.clockwork_bearing": "Supporto del Orologio", + "block.create.rope_pulley": "Puleggia della Corda", + "block.create.rope": "Corda", + "block.create.pulley_magnet": "Magnete della Puleggia", + "block.create.translation_chassis": "Telaio Lineare", + "block.create.rotation_chassis": "Telaio Radiale", + + "block.create.contact": "Contatto Redstone", + "block.create.redstone_bridge": "Collegamento Redstone", + "block.create.stockswitch": "Interruttore Accumulatore", + "block.create.flexcrate": "Baule Regolabile", + "block.create.extractor": "Estrattore", + "block.create.belt_funnel": "Imbuto", + "block.create.linked_extractor": "Estrattore Connesso", + "block.create.transposer": "Traspositore", + "block.create.linked_transposer": "Traspositore Connesso", + "block.create.pulse_repeater": "Ripetitore di Impulsi", + "block.create.flexpulsepeater": "Ripetitore di Impulsi Regolabile", + "block.create.redstone_latch": "Leva Alimentata", + "block.create.toggle_latch": "Leva Alimentata Alterata", + "block.create.flexpeater": "Ripetitore Regolabile", + "block.create.entity_detector": "Osservatore a Cinghia", + "block.create.belt_tunnel": "Tunnel Trasportatore", + "block.create.sequenced_gearshift": "Cambio Sequenziale", + + "block.create.tiled_glass": "Vetro Piastrellato", + "block.create.framed_glass": "Finestra Grande Vetro", + "block.create.vertical_framed_glass": "Finestra Verticale Vetro", + "block.create.horizontal_framed_glass": "Finestra Orizzontale Vetro", + "block.create.oak_glass": "Finestra di Quercia", + "block.create.spruce_glass": "Finestra di Abete", + "block.create.birch_glass": "Finestra di Betulla", + "block.create.jungle_glass": "Finestra della Giungla", + "block.create.dark_oak_glass": "Finestra di Quercia Oscura", + "block.create.acacia_glass": "Finestra di Acacia", + "block.create.iron_glass": "Finestra di Ferro Ornata", + + "block.create.tiled_glass_pane": "Pannello di Vetro Piastrellato", + "block.create.framed_glass_pane": "Pannello di Finestra Grande Vetro", + "block.create.vertical_framed_glass_pane": "Pannello di Finestra Verticale Vetro", + "block.create.horizontal_framed_glass_pane": "Pannello di Finestra Orizzontale Vetro", + "block.create.oak_glass_pane": "Pannello di Finestra di Quercia", + "block.create.spruce_glass_pane": "Pannello di Finestra di Abete", + "block.create.birch_glass_pane": "Pannello di Finestra di Betulla", + "block.create.jungle_glass_pane": "Pannello di Finestra della Giungla", + "block.create.dark_oak_glass_pane": "Pannello di Finestra di Quercia Oscura", + "block.create.acacia_glass_pane": "Pannello di Finestra di Acacia", + "block.create.iron_glass_pane": "Pannello di Finestra di Ferro Ornata", + + "block.create.window_in_a_block": "BLocco con Pannello di Vetro", + "block.create.andesite_bricks": "Mattoni di Andesite", + "block.create.andesite_layers": "Andesite Stratificata", + "block.create.diorite_bricks": "Mattoni di Diorite", + "block.create.diorite_layers": "Diorite Stratificata", + "block.create.granite_bricks": "Mattoni di Granito", + "block.create.granite_layers": "Granito Stratificato", + + "block.create.gabbro": "Gabbro", + "block.create.gabbro_stairs": "Scalini di Gabbro", + "block.create.gabbro_slab": "Lastra di Gabbro", + "block.create.gabbro_wall": "Muretto di Gabbro", + "block.create.polished_gabbro": "Gabbro Levigato", + "block.create.gabbro_bricks": "Mattoni di Gabbro", + "block.create.gabbro_bricks_stairs": "Scalini di Mattoni di Gabbro", + "block.create.gabbro_bricks_wall": "Muretto di Mattoni di Gabbro", + "block.create.paved_gabbro_bricks": "Mattoni di Gabbro Pavimentato", + "block.create.paved_gabbro_bricks_slab": "Lastra di Mattoni di Gabbro Pavimentato", + "block.create.indented_gabbro": "Piastrella di Gabbro Frastagliato", + "block.create.indented_gabbro_slab": "Lastra di Gabbro Frastagliato", + "block.create.Limestone": "Mattoni di Gabbro Muschiosi", + "block.create.mossy_gabbro_bricks": "Mattoni di Gabbro Coperto di Vegetazione", + "block.create.gabbro_layers": "Gabbro Stratificato", + + "block.create.weathered_limestone": "Calcare Consumato", + "block.create.weathered_limestone_stairs": "Scalini di Calcare Consumato", + "block.create.weathered_limestone_wall": "Muretto di Calcare Consumato", + "block.create.weathered_limestone_slab": "Lastra di Calcare Consumato", + "block.create.polished_weathered_limestone": "Calcare Consumato Levigato", + "block.create.polished_weathered_limestone_slab": "Lastra di Calcare Consumato Levigato", + "block.create.weathered_limestone_bricks": "Mattoni di Calcare Consumato", + "block.create.weathered_limestone_bricks_stairs": "Scalini di Mattoni di Calcare Consumato Levigato", + "block.create.weathered_limestone_bricks_wall": "Muretto di Mattoni di Calcare Consumato Levigato", + "block.create.weathered_limestone_bricks_slab": "Lastra di Mattoni di Calcare Consumato", + "block.create.weathered_limestone_pillar": "Pilastro di Calcare Consumato", + "block.create.weathered_limestone_layers": "Calcare Consumato Stratificato", + + "block.create.dolomite_pillar": "Pilastro di Dolomite", + "block.create.dolomite": "Dolomite", + "block.create.dolomite_stairs": "Scalini di Dolomite", + "block.create.dolomite_wall": "Muretto di Dolomite", + "block.create.dolomite_slab": "Lastra di Dolomite", + "block.create.dolomite_bricks": "Mattoni di Dolomite", + "block.create.dolomite_bricks_wall": "Muretto di Mattoni di Dolomite", + "block.create.dolomite_bricks_stairs": "Scalini di Mattoni di Dolomite", + "block.create.dolomite_bricks_slab": "Lastra di Mattoni di Dolomite", + "block.create.polished_dolomite": "Dolomite Levigato", + "block.create.dolomite_layers": "Dolomite Stratificato", + + "block.create.limesand": "Silico Calcare", + "block.create.limestone": "Calcare", + "block.create.limestone_stairs": "Scalini di Calcare", + "block.create.limestone_slab": "Lastra di Calcare", + "block.create.limestone_wall": "Muretto di Calcare", + "block.create.limestone_bricks": "Mattoni di Calcare", + "block.create.limestone_bricks_stairs": "Scalini di Mattoni di Calcare Levigato", + "block.create.limestone_bricks_slab": "Lastra di Mattoni di Calcare", + "block.create.limestone_bricks_wall": "Muretto di Mattoni di Calcare Levigato", + "block.create.polished_limestone": "Calcare Levigato", + "block.create.polished_limestone_slab": "Lastra di Calcare Levigato", + "block.create.limestone_pillar": "Pilastro di Calcare", + "block.create.limestone_layers": "Calcare Stratificato", + + "block.create.natural_scoria": "Scoria Naturale", + "block.create.scoria": "Scoria", + "block.create.scoria_stairs": "Scalini di Scoria", + "block.create.scoria_slab": "Lastra di Scoria", + "block.create.scoria_wall": "Muretto di Scoria", + "block.create.scoria_bricks": "Mattoni di Scoria", + "block.create.polished_scoria": "Scoria Levigata", + "block.create.polished_scoria_slab": "Lastra di Scoria Levigata", + "block.create.scoria_pillar": "Pilastro di Scoria", + "block.create.scoria_layers": "Scoria Stratificata", + + "block.create.dark_scoria": "Scoria Scura", + "block.create.polished_dark_scoria": "Scoria Scura Levigata", + "block.create.dark_scoria_tiles": "Piastrelle di Scoria Scura", + "block.create.dark_scoria_tiles_stairs": "Scalini di Piastrelle di Scoria Scura", + "block.create.dark_scoria_tiles_slab": "Lastra di Piastrelle di Scoria Scura", + "block.create.dark_scoria_bricks": "Mattoni di Scoria Scura", + "block.create.dark_scoria_bricks_stairs": "Scalini di Mattoni di Scoria Scura", + "block.create.dark_scoria_bricks_slab": "Lastra di Mattoni di Scoria Scura", + "block.create.dark_scoria_bricks_wall": "Muretto di Mattoni di Scoria Scura", + + "block.create.schematicannon": "Cannoneschematico", + "block.create.schematic_table": "Banco Schematico", + "block.create.creative_crate": "Creatore Cannoneschematico", + + "block.create.cocoa_log": "Tronco di Giungla Cacao", + + "_comment": "-------------------------] UI & MESSAGES [------------------------------------------------", + + "death.attack.create.crush": "%1$s è stato elaborato dala Ruota di Frantumazione", + "death.attack.create.fan_fire": "%1$s è stato bruciato a morte da aria calda", + "death.attack.create.fan_lava": "%1$s è stato bruciato a morte dal ventilatore di lava", + "death.attack.create.drill": "%1$s è stato impalato dal Trapano Meccanico", + "death.attack.create.saw": "%1$s è stato tagliato a metà dalla Sega Meccanica", + "create.block.deployer.damage_source_name": "un Disadattato", + "death.attack.create.curse_polish": "%1$s ha provato a lucidare un oggetto maledetto", + "death.attack.create.cuckoo_clock_explosion": "%1$s è saltato in aria dall'orologio a cucù manomesso", + + "create.recipe.crushing": "Frantumazione", + "create.recipe.milling": "Fresatura", + "create.recipe.splashing": "Lavaggio alla Rinfusa", + "create.recipe.splashing.fan": "Ventilatore Dietro l'Acqua Corrente", + "create.recipe.smokingViaFan": "Massa di Fumo", + "create.recipe.smokingViaFan.fan": "Ventilatore Dietro il Fuoco", + "create.recipe.blastingViaFan": "Fusione", + "create.recipe.blastingViaFan.fan": "Ventilatore Dietro la Lava", + "create.recipe.pressing": "Pressatura", + "create.recipe.mixing": "Mescolamento", + "create.recipe.packing": "Compattazione", + "create.recipe.sawing": "Segagione", + "create.recipe.mechanical_crafting": "Creazione Meccanico", + "create.recipe.block_cutting": "Taglio Blocco", + "create.recipe.blockzapperUpgrade": "Posizionatore di Blocchi Portatile", + "create.recipe.sandpaper_polishing": "Carta Vetrata Levigata", + "create.recipe.mystery_conversion": "Metamorfosi Cromatica", + "create.recipe.processing.catalyst": "Catalizzatore", + "create.recipe.processing.chance": "%1$s%% Possibilità", + "create.recipe.processing.chanceToReturn": "%1$s%% Possibilità di Ritorno", + + "create.generic.range": "Gamma", + "create.generic.radius": "Raggio", + "create.generic.width": "Larghezza", + "create.generic.height": "Altezza", + "create.generic.length": "Lunghezza", + "create.generic.speed": "Velocità", + "create.generic.delay": "Ritardo", + "create.generic.unit.ticks": "Tick", + "create.generic.unit.seconds": "Secondi", + "create.generic.unit.minutes": "Minuti", + "create.generic.unit.rpm": "RPM", + "create.generic.unit.stress": "su", + "create.generic.unit.degrees": "°", + + "create.action.scroll": "Scorri", + "create.action.confirm": "Conferma", + "create.action.abort": "Annulla", + "create.action.saveToFile": "Salva", + "create.action.discard": "Scarta", + + "create.keyinfo.toolmenu": "Focalizza sul Menu Strumento", + "create.keyinfo.scrollup": "Simula Rotellina del Mouse Verso Su (nel mondo)", + "create.keyinfo.scrolldown": "Simula Rotellina del Mouse Verso Giù (nel mondo)", + + "create.gui.scrollInput.defaultTitle": "Scegli un Opzione:", + "create.gui.scrollInput.scrollToModify": "Scorri per Modificare", + "create.gui.scrollInput.scrollToAdjustAmount": "Scorri Fino a Regolare l'Importo", + "create.gui.scrollInput.scrollToSelect": "Scorri per Selezionare", + "create.gui.scrollInput.shiftScrollsFaster": "Premi Shift per Scorrere più Velocemente", + + "create.gui.toolmenu.focusKey": "Premi [%1$s] per Aprire il Menu", + "create.gui.toolmenu.cycle": "[SCORRI] per navigare", + + "create.gui.symmetryWand.mirrorType": "Specchio", + "create.gui.symmetryWand.orientation": "Orientamento", + "create.symmetry.mirror.plane": "Una volta", + "create.symmetry.mirror.doublePlane": "Rettangolare", + "create.symmetry.mirror.triplePlane": "Ottagonale", + "create.orientation.orthogonal": "Ortogonale", + "create.orientation.diagonal": "Diagonale", + "create.orientation.horizontal": "Orizzontale", + "create.orientation.alongZ": "Lungo Z", + "create.orientation.alongX": "Lungo X", + + "create.gui.blockzapper.title": "Posizionatore di Blocchi", + "create.gui.blockzapper.replaceMode": "Modalità Sostituire", + "create.gui.blockzapper.searchDiagonal": "Segui Diagonali", + "create.gui.blockzapper.searchFuzzy": "Ignora i Bordi dei Materiali", + "create.gui.blockzapper.range": "Gamma Diffusione", + "create.gui.blockzapper.needsUpgradedAmplifier": "Richiede Aggirnamento del Amplificatore", + "create.gui.blockzapper.patternSection": "Schema", + "create.gui.blockzapper.pattern.solid": "Solido", + "create.gui.blockzapper.pattern.checkered": "Scacchiera", + "create.gui.blockzapper.pattern.inversecheckered": "Scacchiera Invertita", + "create.gui.blockzapper.pattern.chance25": "25% Riempito", + "create.gui.blockzapper.pattern.chance50": "50% Riempito", + "create.gui.blockzapper.pattern.chance75": "75% Riempito", + + "create.gui.terrainzapper.title": "Plasmatore del Mondo", + "create.gui.terrainzapper.placement": "Piazzamento", + "create.gui.terrainzapper.placement.merged": "Fuso", + "create.gui.terrainzapper.placement.attached": "Attaccato", + "create.gui.terrainzapper.placement.inserted": "Inserito", + "create.gui.terrainzapper.brush": "Pennello", + "create.gui.terrainzapper.brush.cuboid": "Cuboide", + "create.gui.terrainzapper.brush.sphere": "Sferico", + "create.gui.terrainzapper.brush.cylinder": "Cilindrico", + "create.gui.terrainzapper.tool": "Strumento", + "create.gui.terrainzapper.tool.fill": "Riempi", + "create.gui.terrainzapper.tool.place": "Piazza", + "create.gui.terrainzapper.tool.replace": "Sostituisci", + "create.gui.terrainzapper.tool.clear": "Ripulisci", + "create.gui.terrainzapper.tool.overlay": "Ricopri", + "create.gui.terrainzapper.tool.flatten": "Appiattisci", + "create.terrainzapper.shiftRightClickToSet": "Clic-Destro e Shift per selezionare una forma", + + "create.blockzapper.usingBlock": "In utilizzo: %1$s", + "create.blockzapper.componentUpgrades": "Aggiornamenti dei Componenti:", + "create.blockzapper.component.body": "Corpo", + "create.blockzapper.component.amplifier": "Amplificatore", + "create.blockzapper.component.accelerator": "Acceleratore", + "create.blockzapper.component.retriever": "Cane da Riporto", + "create.blockzapper.component.scope": "Portata", + "create.blockzapper.componentTier.none": "Nessuno", + "create.blockzapper.componentTier.brass": "Ottone", + "create.blockzapper.componentTier.chromatic": "Cromatico", + "create.blockzapper.leftClickToSet": "Clic-Sinistro su un blocco per impostare il materiale", + "create.blockzapper.empty": "Fuori dai Blocchi!", + + "create.contraptions.movement_mode": "Modalità Movimento", + "create.contraptions.movement_mode.move_place": "Posizionare Sempre quando è Fermo", + "create.contraptions.movement_mode.move_place_returned": "Posiziona solo nella Posizione Iniziale", + "create.contraptions.movement_mode.move_never_place": "Posiziona solo quando Ancora Distrutto", + "create.contraptions.movement_mode.rotate_place": "Posiziona Sempre quando è Fermo", + "create.contraptions.movement_mode.rotate_place_returned": "Posiziona solo vicino all'Angolo Iniziale", + "create.contraptions.movement_mode.rotate_never_place": "Posiziona Solo quando l'Ancora viene Distrutta", + + "create.logistics.filter": "Filtro", + "create.logistics.firstFrequency": "Freq. #1", + "create.logistics.secondFrequency": "Freq. #2", + + "create.gui.goggles.generator_stats": "Statistiche del Generatore:", + "create.gui.goggles.kinetic_stats": "Statistiche Cinetiche:", + "create.gui.goggles.at_current_speed": "Alla velocità Attuale", + "create.gui.goggles.base_value": "Valore Base", + + "create.gui.gauge.info_header": "Informazioni sul Calibro:", + "create.gui.speed_gauge.title": "Velocità di Rotazione", + "create.gui.stress_gauge.title": "Stress della Rete", + "create.gui.stress_gauge.capacity": "Capacità Rimanente", + "create.gui.stress_gauge.overstressed": "Sovrastressato", + "create.gui.stress_gauge.no_rotation": "Nessuna Rotazione", + + "create.gui.contraptions.not_fast_enough": "Sembra che questo %1$s _non_ stia girando con una _velocità_ _sufficiente_.", + "create.gui.contraptions.network_overstressed": "Sembra che questo marchingegno sia _sovraccarico_. Aggiungi più fonti o _rallenta_ i componenti con un forte _impatto_ _di_ _stress_.", + + "create.gui.flexcrate.title": "Baule Regolabile", + "create.gui.flexcrate.storageSpace": "Spazio di Immagazzinamento", + + "create.gui.stockswitch.title": "Interruttore Accumulatore", + "create.gui.stockswitch.lowerLimit": "Soglia Inferiore", + "create.gui.stockswitch.upperLimit": "Soglia Superiore", + "create.gui.stockswitch.startAt": "Inizia Segnale al", + "create.gui.stockswitch.startAbove": "Inizia il Segnale dop.", + "create.gui.stockswitch.stopAt": "Ferma Segnale al", + "create.gui.stockswitch.stopBelow": "Ferma il Segnale dop.", + "create.gui.sequenced_gearshift.title": "Cambio Sequenziale", + "create.gui.sequenced_gearshift.instruction": "Istruzione", + "create.gui.sequenced_gearshift.instruction.turn_angle": "Gira", + "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "Angolo", + "create.gui.sequenced_gearshift.instruction.turn_distance": "Pistone", + "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "Distanza", + "create.gui.sequenced_gearshift.instruction.wait": "Aspetta", + "create.gui.sequenced_gearshift.instruction.wait.duration": "Durata", + "create.gui.sequenced_gearshift.instruction.end": "Fine", + "create.gui.sequenced_gearshift.speed": "Velocità, Direzione", + "create.gui.sequenced_gearshift.speed.forward": "Velocità di ingresso, Avanti", + "create.gui.sequenced_gearshift.speed.forward_fast": "Doppia velocità, Avanti", + "create.gui.sequenced_gearshift.speed.back": "Velocità di ingresso, Invertita", + "create.gui.sequenced_gearshift.speed.back_fast": "Doppia velocità, Invertita", + + "create.schematicAndQuill.dimensions": "Dimensione Schematica: %1$sx%2$sx%3$s", + "create.schematicAndQuill.firstPos": "Prima posizione impostata.", + "create.schematicAndQuill.secondPos": "Seconda posizione impostata.", + "create.schematicAndQuill.noTarget": "Premi [Ctrl] per selezionare il Blocco d'Aria.", + "create.schematicAndQuill.abort": "Selezione rimossa.", + "create.schematicAndQuill.prompt": "Immettere un nome per lo schema:", + "create.schematicAndQuill.fallbackName": "La mia Schematica", + "create.schematicAndQuill.saved": "Salvata come %1$s", + + "create.schematic.invalid": "[!] Oggetto non valido - Utilizza invece il Banco Schematico", + "create.schematic.position": "Posizione", + "create.schematic.rotation": "Rotazione", + "create.schematic.rotation.none": "Nessuna", + "create.schematic.rotation.cw90": "Senso Orario 90", + "create.schematic.rotation.cw180": "Senso Orario 180", + "create.schematic.rotation.cw270": "Senso Orario 270", + "create.schematic.mirror": "Specchio", + "create.schematic.mirror.none": "Nessuno", + "create.schematic.mirror.frontBack": "Fronte-Retro", + "create.schematic.mirror.leftRight": "Sinistra-Destra", + + "create.schematic.tool.deploy": "Installa", + "create.schematic.tool.move": "Muovi XZ", + "create.schematic.tool.movey": "Muovi Y", + "create.schematic.tool.rotate": "Ruota", + "create.schematic.tool.print": "Stampa", + "create.schematic.tool.flip": "Capovolgi", + + "create.schematic.tool.deploy.description.0": "Sposta la struttura in una posizione.", + "create.schematic.tool.deploy.description.1": "Clic-Destro sul terreno per posizionarla.", + "create.schematic.tool.deploy.description.2": "premi [Ctrl] per selezionare a distanza fissa.", + "create.schematic.tool.deploy.description.3": "[Ctrl]-Scorri per cambiare la distanza.", + "create.schematic.tool.move.description.0": "Sposta la Schematica in Orizzontale.", + "create.schematic.tool.move.description.1": "Indica la Schematica e [CTRL]-Scorri per spingerla.", + "create.schematic.tool.move.description.2": "", + "create.schematic.tool.move.description.3": "", + "create.schematic.tool.movey.description.0": "Sposta la Schematica verticalmente.", + "create.schematic.tool.movey.description.1": "[CTRL]-Scorri per spostarla su/giù.", + "create.schematic.tool.movey.description.2": "", + "create.schematic.tool.movey.description.3": "", + "create.schematic.tool.rotate.description.0": "Ruota la Schematica attorno al suo centro.", + "create.schematic.tool.rotate.description.1": "[CTRL]-Scorri ruota di 90 gradi.", + "create.schematic.tool.rotate.description.2": "", + "create.schematic.tool.rotate.description.3": "", + "create.schematic.tool.print.description.0": "Posiziona istantaneamente la struttura nel mondo.", + "create.schematic.tool.print.description.1": "[Clic-Destro] per confermare la posizione corrente.", + "create.schematic.tool.print.description.2": "Questo strumento è solo per la modalità creativa.", + "create.schematic.tool.print.description.3": "", + "create.schematic.tool.flip.description.0": "Capovolge la schematica lungo la faccia selezionata.", + "create.schematic.tool.flip.description.1": "Indica la schematica e [CTRL]-Scorri per capovolgerla.", + "create.schematic.tool.flip.description.2": "", + "create.schematic.tool.flip.description.3": "", + + "create.schematics.synchronizing": "Sincronizzazione...", + "create.schematics.uploadTooLarge": "La schematica è troppo grande.", + "create.schematics.maxAllowedSize": "La dimensione massima consentita del file schematica è:", + + "create.gui.schematicTable.title": "Banco Schematico", + "create.gui.schematicTable.availableSchematics": "Schatiche disponibili", + "create.gui.schematicTable.noSchematics": "Nessuna Schatica Salvata", + "create.gui.schematicTable.uploading": "Caricamento...", + "create.gui.schematicTable.finished": "Caricamento Finito!", + + "create.gui.schematicannon.title": "Cannoneschematico", + "create.gui.schematicannon.settingsTitle": "Impostazioni di Posizionamento", + "create.gui.schematicannon.listPrinter": "Stampante Lisra dei Materiali", + "create.gui.schematicannon.gunpowderLevel": "Polvere da sparo al %1$s%%", + "create.gui.schematicannon.shotsRemaining": "Spari Rimanenti: %1$s", + "create.gui.schematicannon.shotsRemainingWithBackup": "Con il backup: %1$s", + "create.gui.schematicannon.optionEnabled": "Attualmente Abilitato", + "create.gui.schematicannon.optionDisabled": "Attualmente Disabilitato", + "create.gui.schematicannon.option.dontReplaceSolid": "Non sostituire i Blocchi Solidi", + "create.gui.schematicannon.option.replaceWithSolid": "Sostituisci Solidi con Solidi", + "create.gui.schematicannon.option.replaceWithAny": "Sostituisci Solidi con Qualsiasi", + "create.gui.schematicannon.option.replaceWithEmpty": "Sostituisci Solidi con il Vuoto", + "create.gui.schematicannon.option.skipMissing": "Salta i Blocchi Mancanti", + "create.gui.schematicannon.option.skipTileEntities": "Proteggi i Blocchi Entità", + + "create.gui.schematicannon.option.skipMissing.description": "Se il cannone non riesce a trovare un blocco richiesto per il posizionamento, continuerà nella posizione successiva.", + "create.gui.schematicannon.option.skipTileEntities.description": "Il cannone eviterà di sostituire i blocchi di dati come bauli.", + "create.gui.schematicannon.option.dontReplaceSolid.description": "Il cannone non sostituirà mai alcun blocco Solido nella sua area di lavoro, solo non solidi e aria.", + "create.gui.schematicannon.option.replaceWithSolid.description": "Il cannone sostituirà i blocchi solidi nella sua area di lavoro se lo schema contiene un blocco solido nella posizione.", + "create.gui.schematicannon.option.replaceWithAny.description": "Il cannone sostituirà i blocchi solidi nella sua area di lavoro se lo schema contiene qualche blocco nella posizione.", + "create.gui.schematicannon.option.replaceWithEmpty.description": "Il cannone eliminerà tutti i blocchi nell'area di lavoro, compresi quelli sostituiti dal aria.", + + "create.schematicannon.status.idle": "Inattivo", + "create.schematicannon.status.ready": "Pronto", + "create.schematicannon.status.running": "In Esecuzione", + "create.schematicannon.status.finished": "Finito", + "create.schematicannon.status.paused": "In Pausa", + "create.schematicannon.status.stopped": "Fermato", + "create.schematicannon.status.noGunpowder": "Niente Polvere da sparo", + "create.schematicannon.status.targetNotLoaded": "Il Blocco non è Caricato", + "create.schematicannon.status.targetOutsideRange": "Obbiettivo Troppo Lontano", + "create.schematicannon.status.searching": "Ricercando", + "create.schematicannon.status.skipping": "Saltando", + "create.schematicannon.status.missingBlock": "Bloc. Mancante:", + "create.schematicannon.status.placing": "Piazzando", + "create.schematicannon.status.clearing": "Cancellando Blocchi", + "create.schematicannon.status.schematicInvalid": "Schematica Non Valida", + "create.schematicannon.status.schematicNotPlaced": "Schematica Non Implementata", + "create.schematicannon.status.schematicExpired": "File Schematica Scaduto", + + "create.gui.filter.blacklist": "Lista Nera", + "create.gui.filter.blacklist.description": "Gli oggetti passano se NON corrispondono a nessuno dei precedenti. Una Lista Nera vuota accetta tutto.", + "create.gui.filter.whitelist": "Lista Bianca", + "create.gui.filter.whitelist.description": "Gli oggetti passano se corrispondono a uno dei precedenti. Una Lista Bianca vuota rifiuta tutto.", + "create.gui.filter.respect_data": "Rispetto dei Dati", + "create.gui.filter.respect_data.description": "Gli oggetti corrispondono solo se la loro durata, incantesimi e altri attributi corrispondono.", + "create.gui.filter.ignore_data": "Ignora Dati", + "create.gui.filter.ignore_data.description": "Gli oggetti corrispondono indipendentemente dai loro attributi.", + + "create.item_attributes.placeable": "è posizionabile", + "create.item_attributes.consumable": "può essere mangiato", + "create.item_attributes.smeltable": "può essere Fuso", + "create.item_attributes.washable": "può essere Lavato", + "create.item_attributes.smokable": "può essere Affumicato", + "create.item_attributes.blastable": "è fondibile in un Forno fusorio", + "create.item_attributes.enchanted": "è incantato", + "create.item_attributes.damaged": "è danneggiato", + "create.item_attributes.badly_damaged": "è gravemente danneggiato", + "create.item_attributes.not_stackable": "non impilabile", + "create.item_attributes.equipable": "può essere equipaggiato", + "create.item_attributes.furnace_fuel": "è il combustibile della fornace", + "create.item_attributes.in_tag": "è etichettato %1$s", + "create.item_attributes.in_item_group": "appartiene a %1$s", + "create.item_attributes.added_by": "è stato aggiunto da %1$s", + + "create.gui.attribute_filter.no_selected_attributes": "Nessun attributo selezionato", + "create.gui.attribute_filter.selected_attributes": "Attributi selezionati:", + "create.gui.attribute_filter.whitelist_disjunctive": "Lista Bianca (Qualsiasi)", + "create.gui.attribute_filter.whitelist_disjunctive.description": "Gli oggetti passano se hanno uno degli attributi selezionati.", + "create.gui.attribute_filter.whitelist_conjunctive": "Lista Bianca (Tutti)", + "create.gui.attribute_filter.whitelist_conjunctive.description": "Gli oggetti passano solo se hanno TUTTI gli attributi selezionati.", + "create.gui.attribute_filter.blacklist": "Lista Nera", + "create.gui.attribute_filter.blacklist.description": "Gli oggetti passano se NON hanno nessuno degli attributi selezionati.", + "create.gui.attribute_filter.add_reference_item": "Agg. Oggetto di Riferim.", + + "create.tooltip.holdKey": "Premi [%1$s]", + "create.tooltip.holdKeyOrKey": "Premi [%1$s] o [%2$s]", + "create.tooltip.keyShift": "Shift", + "create.tooltip.keyCtrl": "Ctrl", + + "create.tooltip.speedRequirement": "Velocità Richiesta: %1$s", + "create.tooltip.speedRequirement.none": "Nessuna", + "create.tooltip.speedRequirement.medium": "Moderata", + "create.tooltip.speedRequirement.high": "Veloce", + + "create.tooltip.stressImpact": "Impatto sullo Stress: %1$s", + "create.tooltip.stressImpact.low": "Basso", + "create.tooltip.stressImpact.medium": "Moderato", + "create.tooltip.stressImpact.high": "Alto", + "create.tooltip.stressImpact.overstressed": "Sovrastressato", + + "create.tooltip.capacityProvided": "Capacità dello Stress: %1$s", + "create.tooltip.capacityProvided.low": "Piccola", + "create.tooltip.capacityProvided.medium": "Media", + "create.tooltip.capacityProvided.high": "Grande", + "create.tooltip.capacityProvided.asGenerator": "(Come generatore)", + "create.tooltip.generationSpeed": "Genera %1$s %2$s", + + "create.tooltip.analogStrength": "Forza Analogica: %1$s/15", + + "create.tooltip.wip": "WIP", + "create.tooltip.workInProgress": "Work in progress!", + + "create.tooltip.randomWipDescription0": "Si prega di tenere questo oggetto lontano dai bambini.", + "create.tooltip.randomWipDescription1": "Un cucciolo di panda muore ogni volta che usi questo oggetto. Ogni. Volta.", + "create.tooltip.randomWipDescription2": "Da utilizzare a proprio rischio.", + "create.tooltip.randomWipDescription3": "Questo non è l'oggetto che stai cercando, *le dita si muovono* perfavore dispartene.", + "create.tooltip.randomWipDescription4": "Questo oggetto si autodistruggerà tra 10 secondi. 10, 9, 8...", + "create.tooltip.randomWipDescription5": "Credimi, è inutile.", + "create.tooltip.randomWipDescription6": "Utilizzando questo articolo, acconsenti al nostro disclaimer e accetti i suoi termini.", + "create.tooltip.randomWipDescription7": "Questo forse non fa per te. Che ne dici di quello?", + "create.tooltip.randomWipDescription8": "Usalo e rimpiangi immediatamente la tua decisione.", + + "create.mechanical_mixer.min_ingredients": "Ingredienti Min.", + + "create.command.killTPSCommand": "killtps", + "create.command.killTPSCommand.status.slowed_by.0": "[Create]: Il tick del server è attualmente rallentato di %s ms :o", + "create.command.killTPSCommand.status.slowed_by.1": "[Create]: Il tick del server è ora rallentato di %s ms >:)", + "create.command.killTPSCommand.status.slowed_by.2": "[Create]: Il tick del server è tornato alla velocità normale :D", + "create.command.killTPSCommand.status.usage.0": "[Create]: usa /killtps per riportare il tick del server alla velocità normale", + "create.command.killTPSCommand.status.usage.1": "[Create]: usa /killtps avvia per rallentare artificialmente il tick del server", + "create.command.killTPSCommand.argument.tickTime": "tickTime", + + "advancement.create:root": "All'inizio, Creiamo!", + "advancement.create:root.desc": "È il momento di iniziare a costruire alcuni meravigliosi aggeggi!", + "advancement.create:andesite_alloy": "Allitterazioni in Abbondanza", + "advancement.create:andesite_alloy.desc": "I materiali di Create hanno nomi strani, Lega di Andesite è uno di questi.", + "advancement.create:andesite_casing": "L'Era del Andesite", + "advancement.create:andesite_casing.desc": "Usa del Andesite, Ferro, e Legno per creare un Involucro di base.", + "advancement.create:crushing_wheel": "Un Paio di Giganti", + "advancement.create:crushing_wheel.desc": "Crea delle Ruote di Frantumazione per frammentare i materiali.", + "advancement.create:rotation": "È vivo!", + "advancement.create:rotation.desc": "Guarda il tuo primo componente cinetico girare.", + "advancement.create:overstressed": "Sovrastressato", + "advancement.create:overstressed.desc": "Sperimenta in prima persona le leggi della fisica.", + "advancement.create:sand_paper": "Potere Levigatore", + "advancement.create:sand_paper.desc": "Crea della Carta Vetrata per rendere le cose belle.", + "advancement.create:polished_rose_quartz": "Diamanti Rosa", + "advancement.create:polished_rose_quartz.desc": "Leviga il Quarzo Rosa fino a quando non riesci a vedere attraverso di esso.", + "advancement.create:sand_paper_secret": "Carta Vetrata Grana 9001", + "advancement.create:sand_paper_secret.desc": "Usa la tua Carta Vetrata per levigare della Carta Vetrata.", + "advancement.create:press": "'Bonk!' ", + "advancement.create:press.desc": "Crea una Pressa Meccanica e usala per creare alcune Lamiere", + "advancement.create:mixer": "Mischiando", + "advancement.create:mixer.desc": "Crea un Miscelatore Meccanico.", + "advancement.create:brass": "Una Lega Vera", + "advancement.create:brass.desc": "Usa Rame e Zinco per creare un pò di Ottone.", + "advancement.create:brass_casing": "L'Era dell'Ottone", + "advancement.create:brass_casing.desc": "Usa L'Ottone appena ottenuto e un pò di Legno per creare un Involucro più avanzato.", + "advancement.create:deployer": "Colpisci, Posiziona e Attacca", + "advancement.create:deployer.desc": "Crea un Installatore, il riflesso perfetto di te stesso.", + "advancement.create:deployer_secret": "Tirartelo, Fra!", + "advancement.create:deployer_secret.desc": "Fai due Installatori batti pugno.", + "advancement.create:chromatic_compound": "Materiali Bipolari", + "advancement.create:chromatic_compound.desc": "Crea una Barra di Composto Cromatico.", + "advancement.create:shadow_steel": "Void Returner", + "advancement.create:shadow_steel.desc": "Crea l'Acciaio Oscuro, una barra di metallo del nulla.", + "advancement.create:refined_radiance": "Luminoso e Atimolante", + "advancement.create:refined_radiance.desc": "Crea una Radiance Raffinata, una potente sostanza cromatica.", + "advancement.create:refined_radiance_secret": "Forgiato dal Raggio di Luce", + "advancement.create:refined_radiance_secret.desc": "Trova il modo alternativo per rendere la Radiance Raffinata.", + "advancement.create:speed_secret": "Bello ", + "advancement.create:speed_secret.desc": "Guarda un tachimetro raggiungere esattamente 69 rpm.", + + "create.subtitle.schematicannon_launch_block": "Tiri del Cannoneschematico", + "create.subtitle.schematicannon_finish": "Finiture Cannoneschematico", + "create.subtitle.slime_added": "Slime schiacciato", + "create.subtitle.mechanical_press_activation": "Pressa Meccanica attiva", + "create.subtitle.mechanical_press_item_break": "Metal clanks", + "create.subtitle.blockzapper_place": "Posiziona blocchi nello spazio", + "create.subtitle.blockzapper_confirm": "Ding Affermativo", + "create.subtitle.blockzapper_deny": "Boop in Calo", + "create.subtitle.block_funnel_eat": "CHOMPS a Imbuto", + + "_comment": "-------------------------] ITEM DESCRIPTIONS [------------------------------------------------", + + "item.create.example_item.tooltip": "OGGETTO DI ESEMPIO (solo un indicatore che esiste nella descrizione)", + "item.create.example_item.tooltip.summary": "Una breve descrizione dell'oggetto. La _sottolineatura_ evidenzia un termine.", + "item.create.example_item.tooltip.condition1": "Quando questo", + "item.create.example_item.tooltip.behaviour1": "Quindi questo articolo fa questo. (i comportamenti mostrati con shift)", + "item.create.example_item.tooltip.condition2": "E quando questo", + "item.create.example_item.tooltip.behaviour2": "Puoi aggiungere tutti i comportamenti che desideri", + "item.create.example_item.tooltip.control1": "Quando premi Ctrl", + "item.create.example_item.tooltip.action1": "Questi controlli vengono visualizzati.", + + "item.create.symmetry_wand.tooltip": "ASTA DI SIMETRIA", + "item.create.symmetry_wand.tooltip.summary": "Rispecchia perfettamente il posizionamento dei blocchi su piani configurati.", + "item.create.symmetry_wand.tooltip.condition1": "In Hotbar", + "item.create.symmetry_wand.tooltip.behaviour1": "Rimane attivo", + "item.create.symmetry_wand.tooltip.control1": "Clic-Destro sul Terreno", + "item.create.symmetry_wand.tooltip.action1": "_Crea_ o _Sposta_ lo Specchio", + "item.create.symmetry_wand.tooltip.control2": "Clic-Destro in Aria", + "item.create.symmetry_wand.tooltip.action2": "_Rimuove_ lo Specchio attivo", + "item.create.symmetry_wand.tooltip.control3": "Clic-Destro da Accovacciato", + "item.create.symmetry_wand.tooltip.action3": "Apre l'_Interfaccia_ _di_ _Configurazione_", + + "item.create.placement_handgun.tooltip": "POSIZIONATORE DI BLOCCHI PORTATILE", + "item.create.placement_handgun.tooltip.summary": "Nuovo gadget per posizionare o scambiare blocchi a distanza.", + "item.create.placement_handgun.tooltip.control1": "Clic-Sinistro su un Blocco", + "item.create.placement_handgun.tooltip.action1": "Imposta i blocchi posizionati dallo strumento sul blocco selezionato.", + "item.create.placement_handgun.tooltip.control2": "Clic-Destro su un Blocco", + "item.create.placement_handgun.tooltip.action2": "_Piazza_ o _Sostituisce_ il blocco selezionato.", + "item.create.placement_handgun.tooltip.control3": "Clic-Destro da Accovacciato", + "item.create.placement_handgun.tooltip.action3": "Apre l'_Interfaccia_ _di_ _Configurazione_.", + + "item.create.terrain_zapper.tooltip": "PLASMATORE DEL MONDO PORTATILE", + "item.create.terrain_zapper.tooltip.summary": "Strumento per la creazione di _paesaggi_ e _caratteristiche_ _del_ _terreno_.", + "item.create.terrain_zapper.tooltip.control1": "Clic-Sinistro su un Blocco", + "item.create.terrain_zapper.tooltip.action1": "Imposta i blocchi posizionati dallo strumento sul blocco selezionato.", + "item.create.terrain_zapper.tooltip.control2": "Clic-Destro su un Blocco", + "item.create.terrain_zapper.tooltip.action2": "Applica il _Pennello_ e lo _Strumento_ attualmente selezionati nella posizione selezionata.", + "item.create.terrain_zapper.tooltip.control3": "Clic-Destro da Accovacciato", + "item.create.terrain_zapper.tooltip.action3": "Apre l'_Interfaccia_ _di_ _Configurazione_", + + "item.create.tree_fertilizer.tooltip": "FERTILIZZANTE PER ALBERI", + "item.create.tree_fertilizer.tooltip.summary": "Una potente combinazione di minerali adatta ad accelerare la crescita di tipi di alberi comuni.", + "item.create.tree_fertilizer.tooltip.condition1": "Se utilizzato su un Arboscello", + "item.create.tree_fertilizer.tooltip.behaviour1": "Cresce gli Alberi _indipendentemente_ dalle _condizioni_ _di_ _spaziatura_", + + "item.create.deforester.tooltip": "DEFORESTATORE", + "item.create.deforester.tooltip.summary": "Un' _ascia_ _radiante_ in grado di abbattere alberi in una frazione di secondo.", + + "item.create.filter.tooltip": "FILTRO", + "item.create.filter.tooltip.summary": "_Controlla_ _gli_ _output_ e gli _input_ dei dispositivi logistici con maggiore _precisione_, confrontandoli con una _serie_ _di_ _oggetti_ o diversi _filtri_ _nidificati_.", + "item.create.filter.tooltip.condition1": "Quando si trova nello slot del filtro", + "item.create.filter.tooltip.behaviour1": "_Controlla_ il flusso degli oggetti in base alla sua _configurazione_.", + "item.create.filter.tooltip.condition2": "Clic-Destro su di esso", + "item.create.filter.tooltip.behaviour2": "Apre l'_Interfaccia_ _di_ _Configurazione_.", + + "item.create.property_filter.tooltip": "FILTRO ATTRIBUTI", + "item.create.property_filter.tooltip.summary": "_Controlla_ _gli_ _output_ e gli _input_ dei dispositivi logistici con maggiore _precisione_, abbinandolo a una _serie_ _di_ _attributi_ e _categorie_ di oggetti.", + "item.create.property_filter.tooltip.condition1": "Quando si trova nello slot del filtro", + "item.create.property_filter.tooltip.behaviour1": "_Controlla_ il flusso degli oggetti in base alla sua _configurazione_.", + "item.create.property_filter.tooltip.condition2": "Clic-Destro su di esso", + "item.create.property_filter.tooltip.behaviour2": "Apre l'_Interfaccia_ _di_ _Configurazione_.", + + "block.create.cocoa_log.tooltip": "TRONCO DI GIUNGLA CACAO", + "block.create.cocoa_log.tooltip.summary": "Un tronco della giungla che consente una più facile automazione delle _Fave_ _di_ _cacao_.", + "block.create.cocoa_log.tooltip.condition1": "Quando Maturo", + "block.create.cocoa_log.tooltip.behaviour1": "Cresce i _Baccelli_ _di_ _Cacao_ su tutti i lati.", + + "item.create.empty_blueprint.tooltip": "SCHEMATICA VUOTA", + "item.create.empty_blueprint.tooltip.summary": "Utilizzato come ingrediente per ricette e per la scrittura al _Banco_ _Schematico_.", + + "item.create.blueprint.tooltip": "SCHEMATICA", + "item.create.blueprint.tooltip.summary": "Contiene una struttura da posizionare e collocare nel mondo. Posiziona l'ologramma come desiderato e usa un _Cannoneschematico_ per costruirla.", + "item.create.blueprint.tooltip.condition1": "Quando Tenuto", + "item.create.blueprint.tooltip.behaviour1": "Può essere posizionato utilizzando gli Strumenti sullo Schermo.", + "item.create.blueprint.tooltip.control1": "Clic-Destro da Accovacciato", + "item.create.blueprint.tooltip.action1": "Apre un'_Interfaccia_ per l'immissione di _Coordinate_ esatte.", + + "item.create.blueprint_and_quill.tooltip": "SCHEMATICA E PENNA D'OCA", + "item.create.blueprint_and_quill.tooltip.summary": "Utilizzato per salvare una struttura nel tuo mondo in un file .nbt.", + "item.create.blueprint_and_quill.tooltip.condition1": "Passo 1", + "item.create.blueprint_and_quill.tooltip.behaviour1": "Seleziona due punti d'angolo usando il Clic-Destro.", + "item.create.blueprint_and_quill.tooltip.condition2": "Passo 2", + "item.create.blueprint_and_quill.tooltip.behaviour2": "_Ctrl-Scorri_ sui volti per regolare le dimensioni. Clic-Destro di nuovo per salvare.", + "item.create.blueprint_and_quill.tooltip.control1": "Clic-Destro", + "item.create.blueprint_and_quill.tooltip.action1": "Seleziona un punto d'angolo / conferma il salvataggio.", + "item.create.blueprint_and_quill.tooltip.control2": "Ctrl Premuto", + "item.create.blueprint_and_quill.tooltip.action2": "Seleziona i punti a _mezz'aria_. _Scorri_ per regolare la distanza.", + "item.create.blueprint_and_quill.tooltip.control3": "Clic-Destro da Accovacciato", + "item.create.blueprint_and_quill.tooltip.action3": "_Resetta_ e rimuove la selezione.", + + "block.create.creative_crate.tooltip": "CREATORE CANNONESCHEMATICO", + "block.create.creative_crate.tooltip.summary": "Fornisce una scorta infinita di blocchi ai _Cannoneschematici_ adiacenti.", + + "block.create.schematicannon.tooltip": "CANNONESCHEMATICO", + "block.create.schematicannon.tooltip.summary": "Spara blocchi per ricreare una _Schematica_ distribuita nel Mondo. Usa gli oggetti degli inventari adiacenti e della _Polvere da sparo_ come combustibile.", + "block.create.schematicannon.tooltip.control1": "Clic-Destro su di esso", + "block.create.schematicannon.tooltip.action1": "Apre l'_Interfaccia_", + + "block.create.schematic_table.tooltip": "BANCO SCHEMATICO", + "block.create.schematic_table.tooltip.summary": "Scrive schematiche salvate su una _Schematica_ _Vuota_.", + "block.create.schematic_table.tooltip.condition1": "Quando viene fornita una Schematica Vuota", + "block.create.schematic_table.tooltip.behaviour1": "Carica un file selezionato dalla cartella Schematics.", + + "block.create.shaft.tooltip": "ALBERO", + "block.create.shaft.tooltip.summary": "_Rotazione_ _Relè_ in linea retta.", + + "block.create.cogwheel.tooltip": "RUOTA DENTATA", + "block.create.cogwheel.tooltip.summary": "_Rotazione_ _Relè_ in linea retta e su _Ruote_ _Dentate_ adiacenti.", + + "block.create.large_cogwheel.tooltip": "RUOTA DENTATA GRANDE", + "block.create.large_cogwheel.tooltip.summary": "Una versione più grande della _Ruota_ _Dentata_, consente di _modificare_ la _Velocità_ _di_ _Rotazione_ quando è collegato alla sua controparte più piccola.", + + "block.create.encased_shaft.tooltip": "ALBERO INCASSATO", + "block.create.encased_shaft.tooltip.summary": "_Rotazione_ _Relè_ in linea retta. Adatto per propagare la rotazione attraverso le pareti.", + + "block.create.gearbox.tooltip": "RIDUTTORE", + "block.create.gearbox.tooltip.summary": "_Rotazione_ _Relè_ in _quatro_ _direzioni_ Inverte le connessioni diritte.", + + "block.create.gearshift.tooltip": "CAMBIO", + "block.create.gearshift.tooltip.summary": "Un controllo per attivare / disattivare la direzione di rotazione per gli alberi collegati.", + "block.create.gearshift.tooltip.condition1": "Quando Alimentato", + "block.create.gearshift.tooltip.behaviour1": "_Inverte_ la rotazione in uscita.", + + "block.create.clutch.tooltip": "FRIZIONE", + "block.create.clutch.tooltip.summary": "Un controllo per innestare / disinnestare la rotazione per gli alberi collegati.", + "block.create.clutch.tooltip.condition1": "Quando Alimentato", + "block.create.clutch.tooltip.behaviour1": "_Interrompe_ il trasferimento della rotazione dall'altro lato.", + + "block.create.encased_belt.tooltip": "NASTRO INCASSATO", + "block.create.encased_belt.tooltip.summary": "_Rotazione_ _Relè_ attraverso il suo blocco attaccato ai _Nastri_ _Incassati_", + "block.create.encased_belt.tooltip.condition1": "Quando Connesso", + "block.create.encased_belt.tooltip.behaviour1": "I blocchi collegati avranno la _stessa_ _velocità_ _di_ _rotazione_ e direzione esatte. Non devono affrontare allo stesso modo.", + + "block.create.adjustable_pulley.tooltip": "PULEGGIA ANALOGICA", + "block.create.adjustable_pulley.tooltip.summary": "_Rotazione_ _Relè_ attraverso il suo blocco attaccato ai _Nastri_ _Incassati_. I nastri incassati attaccati _ruoteranno_ _più_ _velocemente_ in base al _segnale_ _analogico_ _di_ _redstone_ ricevuto da questo blocco.", + "block.create.adjustable_pulley.tooltip.condition1": "Controllo Redstone", + "block.create.adjustable_pulley.tooltip.behaviour1": "Senza un segnale, _non_ _accelererà_ i nastri collegati. Con un segnale a piena forza collegato al nastro, la velocità _raddoppia_.", + + "item.create.belt_connector.tooltip": "NASTRO MECCANICO", + "item.create.belt_connector.tooltip.summary": "Collega due o più _Alberi_ con un _Nastro_ _Meccanico_. Gli alberi collegati avranno la stessa velocità e direzione di rotazione esatte. Il Nastro può fungere da _Trasportatore_ per _Oggetti_ ed _Entità_.", + "item.create.belt_connector.tooltip.control1": "Clic-Destro sui Alberi", + "item.create.belt_connector.tooltip.action1": "Seleziona l'albero come una puleggia del Nastro. Entrambi gli Alberi selezionati devono _allinearsi_ _Verticalmente_, _Orizzontalmente_, o _Diagonalmente_ verso la direzione del Nastro.", + "item.create.belt_connector.tooltip.control2": "Clic-Destro da Accovacciato", + "item.create.belt_connector.tooltip.action2": "_Reimposta_ la prima posizione selezionata per il Nastro.", + + "item.create.goggles.tooltip": "OCCHIALI DA INGEGNERE", + "item.create.goggles.tooltip.summary": "Un paio di occhiali per migliorare la tua visione con utili _informazioni_ _cinetiche_.", + "item.create.goggles.tooltip.condition1": "Quando indossati", + "item.create.goggles.tooltip.behaviour1": "Mostra gli _indicatori_ _colorati_ corrispondenti al _Livello_ _di_ _Velocità_ di un componente cinetico posizionato, nonché all'_Impatto_ _dello_ _Stress_ e la capacità dei singoli componenti.", + "item.create.goggles.tooltip.condition2": "Quando si guarda il calibro", + "item.create.goggles.tooltip.behaviour2": "Mostra informazioni dettagliate sulla _Velocità_ o lo _Stress_ della rete a cui è collegato il misuratore.", + + "item.create.wrench.tooltip": "CHIAVE INGLESE", + "item.create.wrench.tooltip.summary": "Uno strumento utile per lavorare su congegni cinetici. Può essere usato per _Ruotare_, _Smontare_ e _Configurare_ i componenti.", + "item.create.wrench.tooltip.control1": "Clic-Destro su un blocco cinetico", + "item.create.wrench.tooltip.action1": "_Ruota_ _i_ _componenti_ verso o lontano dalla faccia con cui hai interagito.", + "item.create.wrench.tooltip.control2": "Clic-Destro da Accovacciato", + "item.create.wrench.tooltip.action2": "_Smonta_ _i_ _Componenti_ _Cinetici_ e li rimette nel _tuo_ _inventario_.", + + "block.create.creative_motor.tooltip": "MOTORE", + "block.create.creative_motor.tooltip.summary": "Una fonte configurabile di _Forza_ _di_ _Rotazione_.", + + "block.create.water_wheel.tooltip": "RUOTA D'ACQUA", + "block.create.water_wheel.tooltip.summary": "Fornisce un _Forza_ _di_ _Rotazione_ prelevata da correnti d'_Acqua_ _Adiacenti_.", + + "block.create.encased_fan.tooltip": "VENTILATORE INCASSATO", + "block.create.encased_fan.tooltip.summary": "Converte la _Forza_ _di_ _Rotazione_ in _Correnti_ _d'Aria_ e ritorno. Ha una varietà di usi.", + "block.create.encased_fan.tooltip.condition1": "Quando Alimentato da Redstone", + "block.create.encased_fan.tooltip.behaviour1": "Fornisce _forza_ _di_ _rotazione_ da qualsiasi _fonte_ _di_ _calore_ immediatamente al di sotto di sé. Il ventilatore deve essere rivolto verso il basso.", + "block.create.encased_fan.tooltip.condition2": "Quando in Ruotazione", + "block.create.encased_fan.tooltip.behaviour2": "_Spinge_ o _Tira_ Entità, a seconda della velocità di Rotazione in entrata.", + "block.create.encased_fan.tooltip.condition3": "Quando soffia attraverso blocchi speciali", + "block.create.encased_fan.tooltip.behaviour3": "_Liquidi_ e particelle di _Fuoco_ vengono emessi nel flusso d'aria. Questo può essere usato per _elaborare_ _oggetti_.", + + "block.create.nozzle.tooltip": "UGELLO", + "block.create.nozzle.tooltip.summary": "Attacca la parte anteriore di un _Ventilatore_ _Incassato_ per distribuire il suo effetto sulle Entità in _tutte_ _le_ _direzioni_.", + + "block.create.hand_crank.tooltip": "MANOVELLA", + "block.create.hand_crank.tooltip.summary": "Una semplice _fonte_ di _Forza_ _di_ _Rotazione_ che richiede l'interazione dei giocatori.", + "block.create.hand_crank.tooltip.condition1": "Quando usata", + "block.create.hand_crank.tooltip.behaviour1": "Fornisce una _Forza_ _di_ _Rotazione_ a un aggeggio attaccato. _Accovacciati_ _per_ _invertire_ la rotazione.", + + "block.create.cuckoo_clock.tooltip": "OROLOGIO A CUCÙ", + "block.create.cuckoo_clock.tooltip.summary": "Artigianato raffinato per _decorare_ uno spazio e _tener_ _traccia_ _del_ _tempo_.", + "block.create.cuckoo_clock.tooltip.condition1": "Quando Ruotato", + "block.create.cuckoo_clock.tooltip.behaviour1": "Mostra l'_ora_ _corrente_ e suona una melodia due volte al giorno. Si _attiva_ una volta a mezzogiorno e al crepuscolo, non appena i _giocatori_ _possono_ _dormire_.", + + "block.create.turntable.tooltip": "PIATTO", + "block.create.turntable.tooltip.summary": "Trasforma la _Forza_ _di_ _Rotazione_ in una Raffinata Cinetosi.", + + "block.create.millstone.tooltip": "MACINA", + "block.create.millstone.tooltip.summary": "Un componente cinetico adatto per la _rettifica_ dei _materiali_ inseriti. Può essere alimentato da una ruota dentata adiacente o collegandosi all'albero nella parte inferiore. I risultati devono essere estratti dal componente.", + "block.create.millstone.tooltip.condition1": "Quando Ruotato", + "block.create.millstone.tooltip.behaviour1": "Inizia ad applicare le _ricette_ di _fresatura_ a tutti gli elementi inseriti dal lato o dalla parte superiore del blocco.", + "block.create.millstone.tooltip.condition2": "Quando Toccato con Clic-Destro", + "block.create.millstone.tooltip.behaviour2": "Raccogli manualmente gli output.", + + "block.create.crushing_wheel.tooltip": "RUOTA DI FRANTUMAZIONE", + "block.create.crushing_wheel.tooltip.summary": "Grandi ruote girevoli che _rompono_ qualsiasi cosa.", + "block.create.crushing_wheel.tooltip.condition1": "Se collegata ad altre ruote di frantumazione", + "block.create.crushing_wheel.tooltip.behaviour1": "Forma una frantumatrice per la lavorazione di una varietà di cose. I denti delle ruote devono connettersi e muoversi con la _stessa_ _velocità_ in _direzioni_ _opposte_.", + + "block.create.mechanical_press.tooltip": "PRESSA MECCANICA", + "block.create.mechanical_press.tooltip.summary": "Un pistone potente per comprimere gli oggetti sottostanti. Richiede una _Forza_ _di_ _Rotazione_ costante.", + "block.create.mechanical_press.tooltip.condition1": "Quando alimentata da Redstone", + "block.create.mechanical_press.tooltip.behaviour1": "_Inizia_ a comprimere gli oggetti rilasciati al di sotto di esso.", + "block.create.mechanical_press.tooltip.condition2": "Quando sopra a un Nastro Meccanico", + "block.create.mechanical_press.tooltip.behaviour2": "Comprime _Automaticamente_ gli oggetti che passano sul Nastro.", + "block.create.mechanical_mixer.tooltip.condition3": "Quando sopra a una Bacinella", + "block.create.mechanical_mixer.tooltip.behaviour3": "Inizia a _Compattare_ _gli_ _Oggetti_ nella bacinella ogni volta che sono presenti tutti gli ingredienti necessari.", + + "block.create.basin.tooltip": "BACINELLA", + "block.create.basin.tooltip.summary": "Un pratico _contenitore_ _di_ _oggetti_ utilizzato nella lavorazione con il _Miscelatore_ _Meccanico_ e la _Pressa_ _Meccanica_. Supporta i _Comparatori_ _Redstone_.", + + "block.create.mechanical_mixer.tooltip": "MISCELATORE MECCANICO", + "block.create.mechanical_mixer.tooltip.summary": "Una frusta cinetica per applicare qualsiasi ricetta di creazione informe agli oggetti sottostanti. Richiede una _Forza_ _di_ _Rotazione_ costante e una _Bacinella_ posizionata sotto (con uno spazio in mezzo).", + "block.create.mechanical_mixer.tooltip.condition1": "Quando sopra a una Bacinella", + "block.create.mechanical_mixer.tooltip.behaviour1": "Inizia a mescolare gli oggetti nella bacinella ogni volta che sono presenti tutti gli ingredienti necessari.", + "block.create.mechanical_mixer.tooltip.condition2": "Se utilizzato con la Chiave Inglese", + "block.create.mechanical_mixer.tooltip.behaviour2": "Configura la quantità minima di _ingredienti_ _totali_ per le ricette applicate. Utilizzare questa opzione per _escludere_ _ricette_ _indesiderate_ con ingredienti simili o meno.", + + "block.create.mechanical_crafter.tooltip": "COSTRUTTORE MECCANICO", + "block.create.mechanical_crafter.tooltip.summary": "Un assemblatore cinetico per _automatizzare_ qualsiasi ricetta di _creazione_ _modellata_. Posiziona i _multipli_ _in_ _una_ _griglia_ corrispondente alla tua ricetta, e _disponi_ _i_ _loro_ _nastri_ per creare un _flusso_ che esce dalla griglia su uno degli costruttori.", + "block.create.mechanical_crafter.tooltip.condition1": "Quando ruotato", + "block.create.mechanical_crafter.tooltip.behaviour1": "_Inizia_ _il_ _processo_ _di_ _creazione_ non appena a tutti i costruttori della griglia è stato assegnato un oggetto.", + "block.create.mechanical_crafter.tooltip.control1": "Quando Strappato sul Davanti", + "block.create.mechanical_crafter.tooltip.action1": "_Cicla_ _la_ _direzione_ verso cui un singolo costruttore _sposta_ _i_ _suoi_ _oggetti_. Per formare una griglia di lavoro, _disporre_ _i_ _nastri_ _in_ _un_ _flusso_ che sposta tutti gli oggetti verso il costruttore finale. Il costruttore finale deve puntare lontano dalla griglia.", + "block.create.mechanical_crafter.tooltip.control2": "Quando Strappato sul Dietro", + "block.create.mechanical_crafter.tooltip.action2": "_Collega_ l'_inventario_ _di_ _input_ _ dei costruttori adiacenti. Usa questo per _combinare_ _gli_ _slot_ nella griglia di creazione e _risparmiare_ _sul_ _lavoro_ _di_ _input_.", + + "block.create.furnace_engine.tooltip": "MOTORE FORNACE", + "block.create.furnace_engine.tooltip.summary": "Una potente fonte di _Potenza_ _Rotazionale_ che richiede un _forno_ _funzionante_ per funzionare.", + "block.create.furnace_engine.tooltip.condition1": "Se Collegato alla Fornace Accesa", + "block.create.furnace_engine.tooltip.behaviour1": "_Inizia_ _a_ _alimentare_ un _Volano_ posto di fronte (a 1m di distanza). Utilizza un Forno Fusorio per velocità più elevate.", + + "block.create.flywheel.tooltip": "VOLANO", + "block.create.flywheel.tooltip.summary": "Una grande ruota di metallo per _imbrigliare_ _e_ _stabilizzare_ la forza generata da un _motore_ _collegato_. I volani si collegano ai motori se sono a _1m_ di distanza e ad un _angolo_ _di_ _90°_ l'uno dall'altro.", + "block.create.flywheel.tooltip.condition1": "Se collegato a un Motore in Funzione", + "block.create.flywheel.tooltip.behaviour1": "Fornisce la _Forza_ _di_ _Rotazione_ a un aggeggio connesso in base alla forza e alla velocità del generatore.", + + "block.create.portable_storage_interface.tooltip": "INTERFACCIA DI ARCHIVIAZIONE PORTATILE", + "block.create.portable_storage_interface.tooltip.summary": "Un punto di interscambio portatile per _spostare_ _oggetti_ da e verso una _struttura_ mossa da un pistone, supporto, carrello da miniera o puleggia.", + "block.create.portable_storage_interface.tooltip.condition1": "In Movimento", + "block.create.portable_storage_interface.tooltip.behaviour1": "Interagisce con i _traspositori_ fissi in modo tale che i traspositori _rivolti_ _lontano_ dall'interfaccia _estraggano_ _gli_ _oggetti_, e i traspositori che puntano l'interfaccia _inseriranno_ _gli_ _oggetti_ dall'inventario allegato. Il congegno si arresterà brevemente quando gli oggetti vengono scambiati.", + + "block.create.rotation_speed_controller.tooltip": "REGOLATORE DI VELOCITÀ DI ROTAZIONE", + "block.create.rotation_speed_controller.tooltip.summary": "Un _relè_ _configurabile_ in grado di accelerare o rallentare il componente selezionato a qualsiasi velocità desiderata.", + "block.create.rotation_speed_controller.tooltip.condition1": "Se collegato a una Ruota Dentata Grande", + "block.create.rotation_speed_controller.tooltip.behaviour1": "Inoltra la forza di rotazione in entrata alla ruota, cercando di far _corrispondere_ la _velocità_ con cui è configurata come obbiettivo. La ruota dentata deve essere fissata sulla parte superiore del controllo.", + + "block.create.mechanical_piston.tooltip": "PISTOME MECCANICO", + "block.create.mechanical_piston.tooltip.summary": "Una versione più avanzata del _Pistone_. Usa la _Forza_ _di_ _Rotazione_ per spostare con precisione le strutture attaccate. I _Pali_ _di_ _Estensione_ _del_ _Pistone_ nella parte posteriore definiscono la _Gamma_ di questo dispositivo. Senza estensioni, il pistone non si muoverà. Usa _Telai_ o _Blocchi_ _di_ _Slime_ per muovere più di una singola linea di blocchi.", + "block.create.mechanical_piston.tooltip.condition1": "Quando Ruotato", + "block.create.mechanical_piston.tooltip.behaviour1": "Inizia a spostare la struttura collegata. La Velocità e la direzione sono correlate alla Velocità di Rotazione in entrata.", + + "block.create.sticky_mechanical_piston.tooltip": "PISTOME MECCANICO APPICCICOSO", + "block.create.sticky_mechanical_piston.tooltip.summary": "Una versione più avanzata del _Pistone_ _Appiccicoso_. Usa la _Forza_ _di_ _Rotazione_ per spostare con precisione le strutture attaccate. I _Pali_ _di_ _Estensione_ _del_ _Pistone_ nella parte posteriore definiscono la _Gamma_ di questo dispositivo. Senza estensioni, il pistone non si muoverà. Usa _Telai_ o _Blocchi_ _di_ _Slime_ per muovere più di una singola linea di blocchi.", + "block.create.sticky_mechanical_piston.tooltip.condition1": "Quando Ruotato", + "block.create.sticky_mechanical_piston.tooltip.behaviour1": "Inizia a spostare la struttura collegata. La Velocità e la direzione sono correlate alla Velocità di Rotazione in entrata.", + + "block.create.piston_pole.tooltip": "PALO PISTOME", + "block.create.piston_pole.tooltip.summary": "Estende la gamma dei _Pistoni_ _Meccanici_.", + "block.create.piston_pole.tooltip.condition1": "Se collegato al Pistone Meccanico", + "block.create.piston_pole.tooltip.behaviour1": "Estende la gamma di un pistone di 1 blocco", + + "block.create.mechanical_bearing.tooltip": "SUPPORTO MECCANICO", + "block.create.mechanical_bearing.tooltip.summary": "Utilizzato per ruotare _strutture_ _grandi_ o sfruttare la _Forza_ _di_ _Rotazione_ dal vento.", + "block.create.mechanical_bearing.tooltip.condition1": "Quando Ruotato", + "block.create.mechanical_bearing.tooltip.behaviour1": "Inizia a ruotare i blocchi collegati. Usa _Telai_ o _Blocchi_ _di_ _Slime_ per spostare più di un singolo blocco.", + "block.create.mechanical_bearing.tooltip.condition2": "Quando Alimentato da Redstone", + "block.create.mechanical_bearing.tooltip.behaviour2": "Inizia a fornire _Forza_ _di_ _Rotazione_ generata dalla rotazione della struttura collegata. La struttura deve includere _Blocchi_ _di_ _Vela_ adatti (attualmente qualsiasi blocco di lana).", + + "block.create.clockwork_bearing.tooltip": "SUPPORTO DEL OROLOGIO", + "block.create.clockwork_bearing.tooltip.summary": "Una versione avanzata del _Supporto_ _Meccanico_ per ruotare fino a due _lancette_ in base al _tempo_ _di_ _gioco_ corrente.", + "block.create.clockwork_bearing.tooltip.condition1": "Quando Ruotato", + "block.create.clockwork_bearing.tooltip.behaviour1": "Inizia a ruotare la Struttura collegata verso l'_ora_ _corrente_. Se è presente una seconda struttura, fungerà da _lancetta_ _dei_ _minuti_.", + + "block.create.sequenced_gearshift.tooltip": "CAMBIO SEQUENZIALE", + "block.create.sequenced_gearshift.tooltip.summary": "Un _componente_ _di_ _utilità_ _programmabile_, che può cambiare il suo _throughput_ _rotazionale_ secondo un massimo di _5_ _istruzioni_ _consecutive_. Utilizzalo per alimentare i Supporti Meccanici, Pistoni o Pulegge con un maggiore controllo sui tempi e sulla velocità. Può diventare meno preciso a velocità più elevate.", + "block.create.sequenced_gearshift.tooltip.condition1": "Quando alimentato da Redstone", + "block.create.sequenced_gearshift.tooltip.behaviour1": "_Inizia_ _l'esecuzione_ delle istruzioni programmate in base alla velocità in input.", + "block.create.sequenced_gearshift.tooltip.condition2": "Quando Toccato con Clic-Destro", + "block.create.sequenced_gearshift.tooltip.behaviour2": "Apre l'_Interfaccia_ _di_ _Configurazione_", + + "block.create.cart_assembler.tooltip": "ASSEMBLATORE CARRELLO DA MINIERA", + "block.create.cart_assembler.tooltip.summary": "Monta una Struttura connessa su un _Carrello_ _da_ _miniera_ di _passaggio_.", + "block.create.cart_assembler.tooltip.condition1": "Quando Alimentato da Redstone", + "block.create.cart_assembler.tooltip.behaviour1": "Smonta le strutture montate nei _carrelli_ _da_ _miniera_ di _passaggio_ e le rimette nel mondo.", + + "block.create.rope_pulley.tooltip": "PULEGGIA DELLA CORDA", + "block.create.rope_pulley.tooltip.summary": "Sposta i blocchi e le strutture collegati in verticale. Usa _Telai_ o _Blocchi_ _di_ _Slime_ per spostare più di un singolo blocco.", + "block.create.rope_pulley.tooltip.condition1": "Quando Ruotato", + "block.create.rope_pulley.tooltip.behaviour1": "Inizia a spostare la struttura collegata. La velocità e la direzione sono correlate alla Velocità di Rotazione in input.", + + "block.create.translation_chassis.tooltip": "TELAIO LINEARE", + "block.create.translation_chassis.tooltip.summary": "Un blocco base configurabile che collega le strutture per il movimento.", + "block.create.translation_chassis.tooltip.condition1": "Quando Spostato", + "block.create.translation_chassis.tooltip.behaviour1": "_Sposta_ tutti i _Telai_ _attaccati_ con lo stesso orientamento e una colonna di Blocchi all'interno della sua gamma. I blocchi verranno tirati solo se la faccia del telaio è _Appiccicosa_ (Vedi con [Ctrl]).", + "block.create.translation_chassis.tooltip.condition2": "Con Chiave Inglese", + "block.create.translation_chassis.tooltip.behaviour2": "Configura la _gamma_ per questo telaio. Premi CTRL per modificare anche la gamma di tutti i blocchi telaio collegati.", + "block.create.translation_chassis.tooltip.control1": "Quando si fa Clic-Destro con la Palla di slime", + "block.create.translation_chassis.tooltip.action1": "Crea la faccia cliccata _Appiccicosa_. Quando viene spostato, il telaio tirerà i blocchi collegati, indipendentemente dalla direzione del movimento.", + + "block.create.rotation_chassis.tooltip": "TELAIO RADIALE", + "block.create.rotation_chassis.tooltip.summary": "Un blocco base configurabile che collega le strutture per il movimento.", + "block.create.rotation_chassis.tooltip.condition1": "Quando Spostato", + "block.create.rotation_chassis.tooltip.behaviour1": "_Sposta_ tutti i _Telai_ _collegati_ in una colonna, e un cilindro di blocchi attorno a se stesso. I blocchi attorno ad esso vengono spostati solo quando si trovano nella gamma e sono attaccati a un lato appiccicoso (Vedi con [Ctrl]).", + "block.create.rotation_chassis.tooltip.condition2": "Con Chiave Inglese", + "block.create.rotation_chassis.tooltip.behaviour2": "Configura la _gamma_ per questo telaio. Premi CTRL per modificare anche la gamma di tutti i blocchi telaio collegati.", + "block.create.rotation_chassis.tooltip.control1": "Quando si fa Clic-Destro con la Palla di slime", + "block.create.rotation_chassis.tooltip.action1": "Crea la faccia cliccata _Appiccicosa_. Quando viene spostato, il telaio tirerà i blocchi collegati, indipendentemente dalla direzione del movimento.", + + "block.create.drill.tooltip": "TRAPANO MECCANICO", + "block.create.drill.tooltip.summary": "Un dispositivo meccanico adatto per _rompere_ i _blocchi_. È mobile con _Pistoni_ o _Supporti_ _meccanici_.", + "block.create.drill.tooltip.condition1": "Quando Ruotato", + "block.create.drill.tooltip.behaviour1": "Funziona come un Rompi blocchi _stazionario_. Fa anche _male_ _alle_ _entità_ nella sua area effettiva", + "block.create.drill.tooltip.condition2": "In Movimento", + "block.create.drill.tooltip.behaviour2": "Rompe i blocchi con cui il trapano si scontra.", + + "block.create.harvester.tooltip": "MIETITRICE MECCANICA", + "block.create.harvester.tooltip.summary": "Una mietitrice meccanica adatta per l'automazione delle colture di medie dimensioni. È mobile con _Pistoni_ o _Supporti_ _Meccanici_.", + "block.create.harvester.tooltip.condition1": "In Movimento", + "block.create.harvester.tooltip.behaviour1": "_Raccoglie_ tutte le _colture_ _mature_ con cui la lama si scontra e ripristina il loro stato iniziale di crescita.", + + "block.create.saw.tooltip": "SEGA MECCANICA", + "block.create.saw.tooltip.summary": "Adatto per _tagliare_ _alberi_ in modo efficace e per _tagliare_ _blocchi_ nelle loro controparti carpentate. È mobile con _Pistoni_ o _Supporti_ _Meccanici_.", + "block.create.saw.tooltip.condition1": "Di fronte", + "block.create.saw.tooltip.behaviour1": "Applica le _Ricette_ di _Segatura_ e _Lavorazione_ _della_ _Pietra_ agli oggetti rilasciati o inseriti al suo interno. Quando sono possibili gli output, le scorre ciclicamente a meno che non sia assegnato un _filtro_.", + "block.create.saw.tooltip.condition2": "Di fronte in orizzontale", + "block.create.saw.tooltip.behaviour2": "_Rompe_ i _tronchi_ di fronte a se. Se il troco supportava un albero da solo, l'albero crollerebbe lontano dalla sega.", + "block.create.saw.tooltip.condition3": "In Movimento", + "block.create.saw.tooltip.behaviour3": "_Taglia_ tutti gli _alberi_ con cui la sega si scontra.", + + "block.create.stockswitch.tooltip": "INTERRUTTORE ACCUMULATORE", + "block.create.stockswitch.tooltip.summary": "Attiva / disattiva un segnale Redstone in base allo _Spazio_ _di_ _Stoccaggio_ nel Contenitore collegato.", + "block.create.stockswitch.tooltip.condition1": "Quando inferiore al limite inferiore", + "block.create.stockswitch.tooltip.behaviour1": "Smette di fornire il _Segnale_ _Redstone_", + "block.create.stockswitch.tooltip.condition2": "Quando supera il Limite Superiore.", + "block.create.stockswitch.tooltip.behaviour2": "Inizia a fornire un _Segnale_ _Redstone_ fino al raggiungimento del limite inferiore.", + "block.create.stockswitch.tooltip.control1": "Quando Toccato con Clic-Destro", + "block.create.stockswitch.tooltip.action1": "Apre l'_Interfaccia_ _di_ _Configurazione_.", + + "block.create.redstone_bridge.tooltip": "COLLEGAMENTO REDSTONE", + "block.create.redstone_bridge.tooltip.summary": "Endpoint per connessioni _Wireless_ _di_ _Redstone_. Le _Frequenze_ possono essere assegnate utilizzando qualsiasi oggetto. La gamma del segnale è limitata, sebbene ragionevolmente lontana.", + "block.create.redstone_bridge.tooltip.condition1": "Quando Alimentato", + "block.create.redstone_bridge.tooltip.behaviour1": "La ricezione di collegamenti della stessa _Frequenza_ produrrà un segnale Redstone.", + "block.create.redstone_bridge.tooltip.control1": "Quando Clic-Destro su un oggetto", + "block.create.redstone_bridge.tooltip.action1": "Imposta la _Frequenza_ su quell'oggetto. È possibile utilizzare un totale di _due_ _oggetti_ _differenti_ in combinazione per definire una frequenza.", + "block.create.redstone_bridge.tooltip.control2": "Clic-Destro da Accovacciato", + "block.create.redstone_bridge.tooltip.action2": "Alterna tra la modalità _Ricevitore_ e _Trasmettitore_.", + + "block.create.contact.tooltip": "CONTATTO REDSTONE", + "block.create.contact.tooltip.summary": "Emette solo un segnale di pietrarossa in coppia. È mobile con _Pistoni_ o _Supporti_ _Meccanici_.", + "block.create.contact.tooltip.condition1": "Di fronte ad altri Contatti", + "block.create.contact.tooltip.behaviour1": "Fornisce un _Segnale_ _Redstone_.", + "block.create.contact.tooltip.condition2": "In Movimento", + "block.create.contact.tooltip.behaviour2": "Attiva tutti i contatti fissi che passa.", + + "block.create.flexcrate.tooltip": "BAULE REGOLABILE", + "block.create.flexcrate.tooltip.summary": "Questo _Contenitore_ _di_ _Stoccaggio_ consente il controllo manuale sulla sua capacità. Può contenere fino a _16_ _Pile_ di qualsiasi oggetto. Supporta _Comparatori_ _Redstone_.", + "block.create.flexcrate.tooltip.control1": "Quando Cliccato con Clic-Destro", + "block.create.flexcrate.tooltip.action1": "Apre l'_Interfaccia_.", + + "block.create.extractor.tooltip": "ESTRATTORE", + "block.create.extractor.tooltip.summary": "_Prende_ _Oggetti_ da un _Inventario _ allegato e li lascia cadere a terra. Non lascerà cadere gli oggetti a meno che lo spazio non sia libero. Può essere assegnata una pila di oggetti come _filtro_.", + "block.create.extractor.tooltip.condition1": "Quando alimentato da Redstone", + "block.create.extractor.tooltip.behaviour1": "_Ferma_ l'Estrattore.", + "block.create.extractor.tooltip.condition2": "Attiva Tiraggio del Nastro", + "block.create.extractor.tooltip.behaviour2": "Gli estrattori possono estrarre oggetti _da_ _nastri_ rinforzati con un _involucro_ _di_ _ottone_. Quando l'estrattore è bloccato, il _nastro_ _si_ _arresterà_.", + "block.create.extractor.tooltip.control1": "Clic-Destro sullo Spazio del Filtro", + "block.create.extractor.tooltip.action1": "Assegna la _pila_ attualmente _trattenuta_ come _Filtro_. L'estrattore estrarrà esclusivamente il _tipo_ di oggetto e il _conteggio_ della pila come filtro.", + + "block.create.transposer.tooltip": "TRASPOSITORE", + "block.create.transposer.tooltip.summary": "_Prende_ _oggetti_ da un _inventario_ allegato e li inserisce immediatamente nell'_inventario_ di destinazione. Può essere assegnata una pila di oggetti come _filtro_.", + "block.create.transposer.tooltip.condition1": "Quando Alimentato da Redstone", + "block.create.transposer.tooltip.behaviour1": "_Ferma_ il Traspositore.", + "block.create.transposer.tooltip.condition2": "Attiva Tiraggio del Nastro", + "block.create.transposer.tooltip.behaviour2": "I Traspositori possono estrarre oggetti _dai_ _nastri_ rinforzati con un _involucro_ _di_ _ottone_. Quando viene eseguito il backup del traspositore, il _nastro_ _si_ _arresterà_.", + "block.create.transposer.tooltip.control1": "Clic-Destro sullo Spazio del Filtro", + "block.create.transposer.tooltip.action1": "Assegna la _pila_ attualmente _trattenuta_ come _Filtro_. L'estrattore estrarrà esclusivamente il _tipo_ di oggetto e il _conteggio_ della pila come filtro.", + + "block.create.deployer.tooltip": "INSTALLATORE", + "block.create.deployer.tooltip.summary": "_Punzoni_, _Usi_ e _Attivazioni_. Questa macchina proverà a _imitare_ un _giocatore_ il più possibile. Può _Prendere_ e _depositare_ _oggetti_ nell'_Inventario_ adiacente. Può essere assegnata una pila di oggetti come _filtro_.", + "block.create.deployer.tooltip.condition1": "Quando Ruotato", + "block.create.deployer.tooltip.behaviour1": "Allunga il braccio e si _attiva_ nello spazio di un blocco _2m_ _davanti_ a sé.", + "block.create.deployer.tooltip.condition2": "Clic-Destro con la Chiave Inglese", + "block.create.deployer.tooltip.behaviour2": "Attiva / disattiva la modalità di perforazione. In _modalità_ _pugno_, l'Installatore tenterà di usare il suo oggetto per _rompere_ _blocchi_ o _ferire_ _entità_.", + + "block.create.linked_extractor.tooltip": "ESTRATTORE CONNESSO", + "block.create.linked_extractor.tooltip.summary": "_Prende_ _gli_ _oggetti_ da un _Inventario_ attaccato e li lascia cadere a terra. Non lascerà cadere gli oggetti a meno che lo spazio non sia libero. Può essere assegnata una pila di oggetti come _filtro_. Può essere controllato a distanza tramite un _Collegamento_ _Redstone_.", + "block.create.linked_extractor.tooltip.condition1": "Quando il Collegamento Redstone è attivo", + "block.create.linked_extractor.tooltip.behaviour1": "_Ferma_ l'Estrattore.", + "block.create.linked_extractor.tooltip.control1": "Clic-Destro sullo Spazio del Filtro", + "block.create.linked_extractor.tooltip.action1": "Assegna la _pila_ attualmente _trattenuta_ come _Filtro_. L'estrattore estrarrà esclusivamente il _tipo_ di oggetto e il _conteggio_ della pila come filtro.", + "block.create.linked_extractor.tooltip.control2": "Clic-Destro sullo Spazio di Frequenza", + "block.create.linked_extractor.tooltip.action2": "Assegna l'_oggetto_ attualmente _trattenuto_ come parte della Frequenza ascoltata. Ogni volta che viene alimentato un _Collegamento_ _Redstone_ della stessa frequenza di trasmissione, questo estrattore si mette in pausa.", + + "block.create.linked_transposer.tooltip": "TRASPOSITORE CONNESSO", + "block.create.linked_transposer.tooltip.summary": "_Prende_ _oggetti_ da un _Inventario_ allegato e li inserisce immediatamente nell'_Inventario_ di destinazione. Può essere assegnata una pila di oggetti come _filtro_. Può essere controllato a distanza tramite un _Collegamento_ _Redstone_.", + "block.create.linked_transposer.tooltip.condition1": "Quando il Collegamento Redstone è Attivo", + "block.create.linked_transposer.tooltip.behaviour1": "_Ferma_ il Traspositore.", + "block.create.linked_transposer.tooltip.control1": "Clic-Destro sullo Spazio del Filtro", + "block.create.linked_transposer.tooltip.action1": "Assegna la _pila_ attualmente _tenuta_ come _Filtro_. Il Traspositore estrae solo gli oggetti che corrispondono al tipo di oggetto e al conteggio della pila di filtri.", + "block.create.linked_transposer.tooltip.control2": "Clic-Destro sullo Spazio di Frequenza", + "block.create.linked_transposer.tooltip.action2": "Assegna l'_oggetto_ attualmente _tenuto_ come parte della Frequenza ascoltata. Ogni volta che viene alimentato un _Collegamento_ _Redstone_ della stessa frequenza di trasmissione, questo Traspositore si ferma.", + + "block.create.belt_funnel.tooltip": "IMBUTO", + "block.create.belt_funnel.tooltip.summary": "_Raccoglie_ _gli_ _oggetti_ _in_ _arrivo_ e li inserisce nell'_inventario_ allegato, se possibile. Può raccogliere oggetti nel _mondo_ e oggetti su un _nastro_.", + "block.create.belt_funnel.tooltip.condition1": "Tirare il Nastro passivamente", + "block.create.belt_funnel.tooltip.behaviour1": "Gli imbuti possono estrarre gli oggetti _dai_ _nastri_ quando vengono posizionati sopra di essi, lateralmente o alla fine. Quando viene eseguito il backup di un imbuto laterale, gli oggetti sul _nastro_ _non_ _si_ _arrestano_.", + + "block.create.belt_tunnel.tooltip": "TUNNEL TRASPORTATORE", + "block.create.belt_tunnel.tooltip.summary": "Un'opzione estetica per far passare i tuoi _Nastri_ _Meccanici_ attraverso i muri. I Nastri devono essere rinforzati con l'_Involucro_ _di_ _Ottone_. I tunnel possono _sincronizzarsi_ con _i_ _loro_ _vicini_, lasciando passare gli oggetti solo se tutti i tunnel del gruppo hanno uno in attesa. [Ctrl]", + "block.create.belt_tunnel.tooltip.control1": "Clic-Destro con la Chiave Inglese sul Davanti", + "block.create.belt_tunnel.tooltip.action1": "Attiva / Disattiva il _comportamento_ _sincronizzato_. I tunnel sincronizzati contengono oggetti fino a quando anche i loro vicini non ne hanno uno.", + "block.create.belt_tunnel.tooltip.control2": "Clic-Destro con la Chiave Inglese sul Lato", + "block.create.belt_tunnel.tooltip.action2": "_Regola_ _le_ _finestre_ se il tunnel ha una finestra su quella faccia.", + + "block.create.brass_casing.tooltip": "INVOLUCRO DI OTTONE", + "block.create.brass_casing.tooltip.summary": "Involucro delle macchine robusto con una varietà di usi. Di sicuro per la decorazione.", + "block.create.brass_casing.tooltip.condition1": "Se utilizzato su un Nastro Meccanico", + "block.create.brass_casing.tooltip.behaviour1": "_Rinforza_ _i_ _nastri_ con una base in ottone. I nastri rinforzati possono supportare i _Tunnel_ _Trasportatori_, _Estrattori_, _Imbuti_ e _Traspositori_ interagendo con i nastri dai lati e sotto.", + + "block.create.entity_detector.tooltip": "OSSERVATORE A CINGHIA", + "block.create.entity_detector.tooltip.summary": "Rileva oggetti ed entità che passano su un _Nastro_ _Meccanico_ di fronte. Usa una _Chiave_ _Inglese_ per scorrere il suo comportamento. I non oggetti verranno sempre gestiti in modalità rilevamento indipendentemente dall'impostazione.", + "block.create.entity_detector.tooltip.condition1": "Modalità di Rilevamento", + "block.create.entity_detector.tooltip.behaviour1": "Fornisce un segnale redstone _mentre_ un _oggetto_ _corrispondente_ si _trova_ nel segmento del nastro osservato.", + "block.create.entity_detector.tooltip.condition2": "Modalità a Impulsi", + "block.create.entity_detector.tooltip.behaviour2": "Emette un _impulso_ quando un _oggetto_ _corrispondente_ _passa_ al centro del segmento del nastro osservato.", + "block.create.entity_detector.tooltip.condition3": "Modalità di Espulsione", + "block.create.entity_detector.tooltip.behaviour3": "_Espelle_ _gli_ _oggetti_ _corrispondenti_ dal lato. Se il nastro bersaglio o lo spazio è _occupato_, l'oggetto verrà _tenuto_ _in_ _posizione_.", + "block.create.entity_detector.tooltip.condition4": "Modalità Divisa", + "block.create.entity_detector.tooltip.behaviour4": "_Divide_ una _pila_ _di_ _oggetti_ _corrispondenti_ ed _espelle_ _metà_ di essa dal lato.", + + "block.create.pulse_repeater.tooltip": "RIPETITORE DI IMPULSI", + "block.create.pulse_repeater.tooltip.summary": "Un semplice circuito per tagliare i segnali redstone di passaggio ad una lunghezza di _1_ _tick_.", + + "block.create.flexpeater.tooltip": "RIPETITORE REGOLABILE", + "block.create.flexpeater.tooltip.summary": "Un _Ripetitore_ _Redstone_ avanzato con un _Ritardo_ _configurabile_ fino a 30 minuti.", + + "block.create.flexpulsepeater.tooltip": "RIPETITORE DI IMPULSI REGOLABILE", + "block.create.flexpulsepeater.tooltip.summary": "Un _Ripetitore_ _di_ _Impulsi_ con un _Ritardo_ _configurabile_ fino a 30 minuti.", + + "block.create.analog_lever.tooltip": "LEVA ANALOGICA", + "block.create.analog_lever.tooltip.summary": "Una leva con un _controllo_ _più_ _preciso_ sulla _potenza_ _del_ _segnale_ emesso.", + + "block.create.toggle_latch.tooltip": "LEVA ALIMENTATA ALTERATA", + "block.create.toggle_latch.tooltip.summary": "Una leva che può essere attivata/disattivata da un _Impulso_ _Redstone_.", + + "block.create.redstone_latch.tooltip": "LEVA ALIMENTATA", + "block.create.redstone_latch.tooltip.summary": "Una leva che può essere controllata dai _Segnali_ _Redstone. Un segnale sul _retro_ _la_ _abilita_, un _segnale_ _laterale_ _la_ _resetterà_ .", + + "block.create.speed_gauge.tooltip": "TACHIMETRO", + "block.create.speed_gauge.tooltip.summary": "Misura e visualizza la _velocità_ _di_ _rotazione_ dei componenti cinetici collegati. Supporta _Comparatori_ _Redstone_.", + "block.create.speed_gauge.tooltip.condition1": "Quando Ruotato", + "block.create.speed_gauge.tooltip.behaviour1": "Indica un colore corrispondente al livello di velocità. Il _Verde_ indica una rotazione Lenta, _Blu_ Moderata e _Viola_ Veloce. Alcuni componenti meccanici richiedono un livello di velocità sufficiente per funzionare correttamente.", + + "block.create.stress_gauge.tooltip": "STRESSOMETRO", + "block.create.stress_gauge.tooltip.summary": "Misura e visualizza lo _stress_ _complessivo_ della rete cinetica collegata. Supporta _Comparatori_ _Redstone_.", + "block.create.stress_gauge.tooltip.condition1": "Quando Ruotato", + "block.create.stress_gauge.tooltip.behaviour1": "Indica un colore corrispondente al livello di stress. Le _reti_ _troppo_ _stressate_ cesseranno di muoversi. Lo stress può essere alleviato aggiungendo più _fonti_ _di_ _rotazione_ alla rete.", + + "tool.create.sand_paper.tooltip": "CARTA VETRATA", + "tool.create.sand_paper.tooltip.summary": "Una carta ruvida che può essere utilizzata per _levigare_ _materiali_ o affilare i tuoi _strumenti_.", + "tool.create.sand_paper.tooltip.condition1": "Quando Usata", + "tool.create.sand_paper.tooltip.behaviour1": "Applica la lucidatura agli oggetti _tenuti_ _in_ _mano_ o distesi a _terra_ quando _li_ _guardi_", + + "item.create.refined_radiance.tooltip": "RADIANCE RAFFINATA", + "item.create.refined_radiance.tooltip.summary": "Un Materiale Cromatico forgiato dalla _luce_ _assorbita_.", + + "item.create.shadow_steel.tooltip": "ACCIAIO OSCURO", + "item.create.shadow_steel.tooltip.summary": "Un Materiale Cromatico forgiato _nel_ _vuoto_.", + + "item.create.slot_cover.tooltip": "RIVESTIMENTO SLOT CREAZIONE", + "item.create.slot_cover.tooltip.summary": "Utilizzato per coprire uno slot vuoto in un _Costruttore_ _Meccanico_ in una ricetta. I Costruttori non devono necessariamente formare una griglia quadrata completa. Questo è utile quando ci sono ricette in cui gli _ingredienti_ _sono_ _in_ _diagonale_ tra loro.", + + "tool.create.shadow_steel.tooltip": "STRUMENTI DI ACCIAIO OSCURO", + "tool.create.shadow_steel.tooltip.summary": "Uno strumento veloce e potente che _distrugge_ _i_ _drop_ da qualsiasi blocco o entità. I mob uccisi possono far cadere _più_ _esperienza_ in base al modificatore di _Looting_ di questo strumento.", + + "tool.create.blazing.tooltip": "STRUMENTI FIAMMEGGIANTI", + "tool.create.blazing.tooltip.summary": "Questo strumento _scioglierà_ _i_ _blocchi_ _rotti_ e _incendirà_ _le_ _creature_ _attaccate_. Non perderà la Durabilità durante l'utilizzo nel l'_Inferno_ .", + + "tool.create.rose_quartz.tooltip": "STRUMENTI DI QUARZO ROSA", + "tool.create.rose_quartz.tooltip.summary": "Questo strumento ti offre una _maggiore_ _portata_ per _rompere_ _blocchi_ o _posizionare_ _blocchi_ dalla mano.", + + "itemGroup.create": "Create" +} diff --git a/src/main/resources/assets/create/lang/ja_jp.lang b/src/main/resources/assets/create/lang/ja_jp.json similarity index 99% rename from src/main/resources/assets/create/lang/ja_jp.lang rename to src/main/resources/assets/create/lang/ja_jp.json index 4b46d256a..e2c5476e2 100644 --- a/src/main/resources/assets/create/lang/ja_jp.lang +++ b/src/main/resources/assets/create/lang/ja_jp.json @@ -272,17 +272,17 @@ "create.recipe.milling": "製粉", "create.recipe.splashing": "一括洗浄", "create.recipe.splashing.fan": "流れる水の後ろにファンを置く", - "create.recipe.smokingViaFan": "一括燻製", - "create.recipe.smokingViaFan.fan": "炎の後ろにファンを置く", - "create.recipe.blastingViaFan": "一括製錬", - "create.recipe.blastingViaFan.fan": "溶岩の後ろにファンを置く", + "create.recipe.smoking_via_fan": "一括燻製", + "create.recipe.smoking_via_fan.fan": "炎の後ろにファンを置く", + "create.recipe.blasting_via_fan": "一括製錬", + "create.recipe.blasting_via_fan.fan": "溶岩の後ろにファンを置く", "create.recipe.pressing": "押しつぶし", "create.recipe.mixing": "混合", "create.recipe.packing": "圧縮", "create.recipe.sawing": "製材", "create.recipe.mechanical_crafting": "メカニカルクラフト", "create.recipe.block_cutting": "ブロックカット", - "create.recipe.blockzapperUpgrade": "携帯型ブロックザッパー", + "create.recipe.blockzapper_upgrade": "携帯型ブロックザッパー", "create.recipe.sandpaper_polishing": "紙やすりでの研磨", "create.recipe.mystery_conversion": "色彩変態", "create.recipe.processing.catalyst": "触媒", diff --git a/src/main/resources/assets/create/lang/ko_kr.json b/src/main/resources/assets/create/lang/ko_kr.json new file mode 100644 index 000000000..cf3f094b0 --- /dev/null +++ b/src/main/resources/assets/create/lang/ko_kr.json @@ -0,0 +1,1165 @@ + +// Korean translated by qkrehf2. +// If you noticed any problems with translation, please email to qkrehf2ggwp@gmail.com +// Please email me when you want to modify translations. :D + +// 이 번역은 qkrehf2가 번역했습니다. +// 번역에 문제가 있다면, qkrehf2ggwp@gmail.com으로 메일 보내주세요. +// 이 번역본을 수정하거나 다른 용도로 쓰고 싶다면, 역시 저에게 메일 주세요. 감사합니다. + + { + + "_comment": "-------------------------] GAME ELEMENTS [------------------------------------------------", + + "item.create.symmetry_wand": "대칭의 지팡이", + "item.create.placement_handgun": "휴대용 블럭발사기", + "item.create.terrain_zapper": "휴대용 세계편집기", + "item.create.tree_fertilizer": "나무 비료", + "item.create.empty_blueprint": "빈 청사진", + "item.create.andesite_alloy": "안산암 합금", + "item.create.chromatic_compound": "색채 혼합물", + "item.create.shadow_steel": "그림자 강철", + "item.create.blueprint_and_quill": "청사진과 깃펜", + "item.create.blueprint": "청사진", + "item.create.belt_connector": "기계식 벨트", + "item.create.goggles": "엔지니어의 고글", + "item.create.filter": "필터 틀", + "item.create.property_filter": "속성 필터 틀", + "item.create.rose_quartz": "장밋빛 석영", + "item.create.polished_rose_quartz": "윤나는 장밋빛 석영", + "item.create.refined_radiance": "정제된 광채", + "item.create.iron_sheet": "철 판", + "item.create.gold_sheet": "금 판", + "item.create.lapis_plate": "청금석 판", + "item.create.obsidian_dust": "흑요석 가루", + "item.create.propeller": "프로펠러", + "item.create.whisk": "혼합기", + "item.create.brass_hand": "황동 손", + "item.create.slot_cover": "작업대 슬롯 덮개", + "item.create.zinc_handle": "아연 도구 손잡이", + "item.create.flour": "밀가루", + "item.create.dough": "반죽", + "item.create.wrench": "렌치", + "item.create.deforester": "산림파괴자", + "item.create.crushed_iron": "분쇄된 철", + "item.create.crushed_gold": "분쇄된 금", + "item.create.sand_paper": "사포", + "item.create.red_sand_paper": "붉은 사포", + + "item.create.brass_ingot": "황동 주괴", + "item.create.brass_sheet": "황동 판", + "item.create.brass_nugget": "황동 조각", + "item.create.crushed_brass": "분쇄된 황동", + "item.create.zinc_ingot": "아연 주괴", + "item.create.zinc_nugget": "아연 조각", + "item.create.crushed_zinc": "분쇄된 아연", + "item.create.copper_sheet": "구리 판", + "item.create.copper_ingot": "구리 주괴", + "item.create.copper_nugget": "구리 조각", + "item.create.crushed_copper": "분쇄된 구리", + + "item.create.electron_tube": "전지 튜브", + "item.create.integrated_circuit": "집적 회로", + + "item.create.blazing_pickaxe": "타오르는 곡괭이", + "item.create.blazing_shovel": "타오르는 삽", + "item.create.blazing_axe": "타오르는 도끼", + "item.create.blazing_sword": "타오르는 대검", + + "item.create.shadow_steel_pickaxe": "그림자 강철 곡괭이", + "item.create.shadow_steel_mattock": "그림자 강철 야전삽", + "item.create.shadow_steel_sword": "그림자 강철 검", + + "item.create.rose_quartz_pickaxe": "화려한 석영 곡괭이", + "item.create.rose_quartz_shovel": "화려한 석영 삽", + "item.create.rose_quartz_axe": "화려한 석영 도끼", + "item.create.rose_quartz_sword": "화려한 석영 검", + + "block.create.copper_ore": "구리 광석", + "block.create.copper_block": "구리 블럭", + "block.create.copper_shingles": "구리 판자", + "block.create.zinc_ore": "아연 광석", + "block.create.zinc_block": "아연 블럭", + "block.create.brass_block": "황동 블럭", + + "block.create.andesite_casing": "안산암 케이스", + "block.create.brass_casing": "황동 케이스", + "block.create.copper_casing": "구리 케이스", + + "block.create.cogwheel": "톱나버퀴", + "block.create.large_cogwheel": "큰 톱니바퀴", + "block.create.turntable": "돌림판", + "block.create.gearbox": "기어박스", + "block.create.gearshift": "기어쉬프트", + "block.create.clutch": "클러치", + "block.create.shaft": "축", + "block.create.encased_belt": "덮힌 벨트", + "block.create.encased_shaft": "덮힌 축", + "block.create.encased_fan": "덮힌 환풍기", + "block.create.adjustable_pulley": "덮힌 벨트 변속기", + "block.create.nozzle": "노즐", + "block.create.hand_crank": "핸드 크랭크", + "block.create.cuckoo_clock": "뻐꾸기 시계", + "block.create.creative_motor": "모터", + "block.create.belt": "컨베이어 벨트", + "block.create.millstone": "맷돌", + "block.create.crushing_wheel": "분쇄 휠", + "block.create.drill": "드릴", + "block.create.portable_storage_interface": "이동식 저장소 인터페이스", + "block.create.harvester": "수확기", + "block.create.saw": "톱", + "block.create.water_wheel": "물레방아", + "block.create.mechanical_press": "압착기", + "block.create.mechanical_mixer": "믹서", + "block.create.deployer": "배포기", + "block.create.basin": "대야", + "block.create.mechanical_crafter": "기계식 조합기", + "block.create.flywheel": "플라이휠", + "block.create.furnace_engine": "화로 엔진", + "block.create.speed_gauge": "속도 계측기", + "block.create.stress_gauge": "피로도 계측기", + "block.create.cart_assembler": "카트 조립기", + "block.create.analog_lever": "아날로그 레버", + "block.create.rotation_speed_controller": "회전 속도 컨트롤러", + + "block.create.sticky_mechanical_piston": "끈끈이 기계식 피스톤", + "block.create.mechanical_piston": "기계식 피스톤", + "block.create.mechanical_piston_head": "기계식 피스톤 머리", + "block.create.piston_pole": "피스톤 연장 축", + "block.create.mechanical_bearing": "베어링", + "block.create.clockwork_bearing": "시계 베어링", + "block.create.rope_pulley": "밧줄 도르래", + "block.create.rope": "밧줄", + "block.create.pulley_magnet": "도르래 자석", + "block.create.translation_chassis": "직선 섀시", + "block.create.rotation_chassis": "원형 섀시", + + "block.create.contact": "동형 감지기", + "block.create.redstone_bridge": "레드스톤 링크", + "block.create.stockswitch": "수량 스위치", + "block.create.flexcrate": "가변 창고", + "block.create.extractor": "추출기", + "block.create.belt_funnel": "깔대기", + "block.create.linked_extractor": "무선 추출기", + "block.create.transposer": "트랜스포저", + "block.create.linked_transposer": "무선 트랜스포저", + "block.create.pulse_repeater": "펄스 리피터", + "block.create.flexpulsepeater": "가변 펄스 리피터", + "block.create.redstone_latch": "레드스톤 걸쇠", + "block.create.toggle_latch": "레드스톤 토글 걸쇠", + "block.create.flexpeater": "가변 리피터", + "block.create.entity_detector": "벨트 감지기", + "block.create.belt_tunnel": "컨베이어 벨트 터널", + "block.create.sequenced_gearshift": "순서 기어쉬프트", + + "block.create.tiled_glass": "타일 유리", + "block.create.framed_glass": "큰 유리", + "block.create.vertical_framed_glass": "수직 유리", + "block.create.horizontal_framed_glass": "수평 유리", + "block.create.oak_glass": "참나무 유리창", + "block.create.spruce_glass": "가문비나무 유리창", + "block.create.birch_glass": "자작나무 유리창", + "block.create.jungle_glass": "정글나무 유리창", + "block.create.dark_oak_glass": "짙은 참나무 유리창", + "block.create.acacia_glass": "아카시아 유리창", + "block.create.iron_glass": "화려한 금속창", + + "block.create.tiled_glass_pane": "타일 유리판", + "block.create.framed_glass_pane": "큰 유리판", + "block.create.vertical_framed_glass_pane": "수직 유리판", + "block.create.horizontal_framed_glass_pane": "수평 유리판", + "block.create.oak_glass_pane": "참나무 유리판", + "block.create.spruce_glass_pane": "가문비나무 유리판", + "block.create.birch_glass_pane": "자작나무 유리판", + "block.create.jungle_glass_pane": "정글나무 유리판", + "block.create.dark_oak_glass_pane": "짙은 참나무 유리판", + "block.create.acacia_glass_pane": "아카시아나무 유리판 ", + "block.create.iron_glass_pane": "화려한 금속 유리판", + + "block.create.window_in_a_block": "유리판이 낀 블럭", + "block.create.andesite_bricks": "안산안 벽돌", + "block.create.andesite_layers": "층이있는 안산암", + "block.create.diorite_bricks": "섬록암 벽돌", + "block.create.diorite_layers": "층이 있는 섬록암", + "block.create.granite_bricks": "화강암 벽돌", + "block.create.granite_layers": "층이 있는 화강암", + + "block.create.gabbro": "반려암", + "block.create.gabbro_stairs": "반려암 계단", + "block.create.gabbro_slab": "반려암 반 블록", + "block.create.gabbro_wall": "반려암 담장", + "block.create.polished_gabbro": "윤나는 반려암", + "block.create.gabbro_bricks": "반려암 벽돌", + "block.create.gabbro_bricks_stairs": "반려암 벽돌 계단", + "block.create.gabbro_bricks_wall": "반려암 벽돌 담장", + "block.create.paved_gabbro_bricks": "포장된 반려암 벽돌", + "block.create.paved_gabbro_bricks_slab": "포장된 반려암 벽돌 반 블록", + "block.create.indented_gabbro": "반려암 겹 타일", + "block.create.indented_gabbro_slab": "반려암 겹 반 블록", + "block.create.slightly_mossy_gabbro_bricks": "이끼 낀 반려암 벽돌", + "block.create.mossy_gabbro_bricks": "이끼로 뒤덮힌 반려암 벽돌", + "block.create.gabbro_layers": "층이 있는 반려암", + + "block.create.weathered_limestone": "풍화된 석회암", + "block.create.weathered_limestone_stairs": "풍화된 석회암 계단", + "block.create.weathered_limestone_wall": "풍화된 석회암 담장", + "block.create.weathered_limestone_slab": "풍화된 석회암 반 블록", + "block.create.polished_weathered_limestone": "윤나는 풍화된 석회암", + "block.create.polished_weathered_limestone_slab": "윤나는 풍화된 석회암 반 블록", + "block.create.weathered_limestone_bricks": "풍화된 석회암 벽돌", + "block.create.weathered_limestone_bricks_stairs": "풍화된 석회암 벽돌 계단", + "block.create.weathered_limestone_bricks_wall": "풍화된 석회암 벽돌 담장", + "block.create.weathered_limestone_bricks_slab": "풍화된 석회암 벽돌 반 블록", + "block.create.weathered_limestone_pillar": "풍화된 석회암 기둥", + "block.create.weathered_limestone_layers": "층이 있는 석회암", + + "block.create.dolomite_pillar": "백운암 기둥", + "block.create.dolomite": "백운암", + "block.create.dolomite_stairs": "백운암 계단", + "block.create.dolomite_wall": "백운암 담장", + "block.create.dolomite_slab": "백운암 반 블록", + "block.create.dolomite_bricks": "백운암 벽돌", + "block.create.dolomite_bricks_wall": "백운암 벽돌 담장", + "block.create.dolomite_bricks_stairs": "백운암 벽돌 계단", + "block.create.dolomite_bricks_slab": "백운암 벽돌 반 블록", + "block.create.polished_dolomite": "윤나는 백운암", + "block.create.dolomite_layers": "층이 있는 백운암", + + "block.create.limesand": "석회모래", + "block.create.limestone": "석회암", + "block.create.limestone_stairs": "석회암 계단", + "block.create.limestone_slab": "석회암 반 블록", + "block.create.limestone_wall": "석회암 담장", + "block.create.limestone_bricks": "석회암 벽돌", + "block.create.limestone_bricks_stairs": "석회암 벽돌 계단", + "block.create.limestone_bricks_slab": "석회암 벽돌 반 블록", + "block.create.limestone_bricks_wall": "석회암 벽돌 담장", + "block.create.polished_limestone": "윤나는 석회암", + "block.create.polished_limestone_slab": "윤나는 석회암 반 블록", + "block.create.limestone_pillar": "석회암 기둥", + "block.create.limestone_layers": "층이 있는 석회암", + + "block.create.natural_scoria": "자연 스코리아", + "block.create.scoria": "스코리아", + "block.create.scoria_stairs": "스코리아 계단", + "block.create.scoria_slab": "스코리아 반 블록", + "block.create.scoria_wall": "스코리아 담장", + "block.create.scoria_bricks": "스코리아 벽돌", + "block.create.polished_scoria": "윤나는 스코리아", + "block.create.polished_scoria_slab": "윤나는 스코리아 반 블록", + "block.create.scoria_pillar": "스코리아 기둥", + "block.create.scoria_layers": "층이 있는 스코리아", + + "block.create.dark_scoria": "짙은 스코리아", + "block.create.polished_dark_scoria": "윤나는 짙은 스코리아", + "block.create.dark_scoria_tiles": "짙은 스코리아 타일", + "block.create.dark_scoria_tiles_stairs": "짙은 스코리아 타일 계단", + "block.create.dark_scoria_tiles_slab": "짙은 스코리아 타일 반 블록", + "block.create.dark_scoria_bricks": "짙은 스코리아 벽돌", + "block.create.dark_scoria_bricks_stairs": "짙은 스코리아 벽돌 계단", + "block.create.dark_scoria_bricks_slab": "짙은 스코리아 벽돌 반 블록", + "block.create.dark_scoria_bricks_wall": "짙은 스코리아 벽돌 담장", + + "block.create.schematicannon": "청사진 대포", + "block.create.schematic_table": "청사진 테이블", + "block.create.creative_crate": "청사진 대포 지원기", + + "block.create.cocoa_log": "코코아 정글 나무 원목", + + "_comment": "-------------------------] UI & MESSAGES [------------------------------------------------", + + "death.attack.create.crush": "%1$s이(가) 분쇄 휠에 의해 가공되었습니다", + "death.attack.create.fan_fire": "%1$s이(가) 뜨거운 바람으로 타버렸습니다", + "death.attack.create.fan_lava": "%1$s이(가) 용암 바람으로 타버렸습니다", + "death.attack.create.drill": "%1$s이(가) 드릴에 관통당했습니다", + "death.attack.create.saw": "%1$s이(가) 톱날에 반으로 갈라져 죽었습니다", + "create.block.deployer.damage_source_name": "순수한 배포기", + "death.attack.create.curse_polish": "%1$s이(가) 저주받은 아이템을 닦다가 죽었습니다", + "death.attack.create.cuckoo_clock_explosion": "%1$s이(가) 조작된 뻐꾸기 시계에 의해 폭파당했습니다", + + "create.recipe.crushing": "분쇄", + "create.recipe.milling": "맷돌질", + "create.recipe.splashing": "세척", + "create.recipe.splashing.fan": "물과 환풍기", + "create.recipe.smokingViaFan": "훈연", + "create.recipe.smokingViaFan.fan": "불과 환풍기", + "create.recipe.blastingViaFan": "제련", + "create.recipe.blastingViaFan.fan": "용암과 환풍기", + "create.recipe.pressing": "압착", + "create.recipe.mixing": "혼합", + "create.recipe.packing": "압축", + "create.recipe.sawing": "제재", + "create.recipe.mechanical_crafting": "기계 조합", + "create.recipe.block_cutting": "블럭 절단", + "create.recipe.blockzapperUpgrade": "휴대용 블럭발사기 업그레이드", + "create.recipe.sandpaper_polishing": "사포 연마", + "create.recipe.mystery_conversion": "?", + "create.recipe.processing.catalyst": "촉매", + "create.recipe.processing.chance": "%1$s%% 확률", + "create.recipe.processing.chanceToReturn": "%1$s%% 확률로 반환", + + "create.generic.range": "범위", + "create.generic.radius": "반지름", + "create.generic.width": "폭", + "create.generic.height": "높이", + "create.generic.length": "길이", + "create.generic.speed": "속도", + "create.generic.delay": "딜레이", + "create.generic.unit.ticks": "틱", + "create.generic.unit.seconds": "초", + "create.generic.unit.minutes": "분", + "create.generic.unit.rpm": "RPM", + "create.generic.unit.stress": "su", + "create.generic.unit.degrees": "°", + + "create.action.scroll": "스크롤하세요", + "create.action.confirm": "확인", + "create.action.abort": "중단", + "create.action.saveToFile": "저장", + "create.action.discard": "삭제", + + "create.keyinfo.toolmenu": "메뉴 세부정보 보기", + "create.keyinfo.scrollup": "Simulate Mousewheel Up (inworld)", + "create.keyinfo.scrolldown": "Simulate Mousewheel Down (inworld)", + + "create.gui.scrollInput.defaultTitle": "옵션을 선택하세요:", + "create.gui.scrollInput.scrollToModify": "스크롤로 수정하기", + "create.gui.scrollInput.scrollToAdjustAmount": "스크롤로 수량 조절하기", + "create.gui.scrollInput.scrollToSelect": "스크롤로 선택", + "create.gui.scrollInput.shiftScrollsFaster": "쉬프트-스크롤로 빨리 수정하기", + + "create.gui.toolmenu.focusKey": "[%1$s]를 눌러 세부정보 보기", + "create.gui.toolmenu.cycle": "스크롤로 순환", + + "create.gui.symmetryWand.mirrorType": "반사", + "create.gui.symmetryWand.orientation": "방위", + "create.symmetry.mirror.plane": "거울 모드", + "create.symmetry.mirror.doublePlane": "사각형 모드", + "create.symmetry.mirror.triplePlane": "팔각형 모드", + "create.orientation.orthogonal": "수직으로", + "create.orientation.diagonal": "대각선으로", + "create.orientation.horizontal": "수평으로", + "create.orientation.alongZ": "Z좌표를 따라", + "create.orientation.alongX": "X좌표를 따라", + + "create.gui.blockzapper.title": "휴대용 블럭발사기", + "create.gui.blockzapper.replaceMode": "대체 모드", + "create.gui.blockzapper.searchDiagonal": "대각선을 따라", + "create.gui.blockzapper.searchFuzzy": "물질 경계 무시", + "create.gui.blockzapper.range": "범위", + "create.gui.blockzapper.needsUpgradedAmplifier": "업그레이드가 필요합니다", + "create.gui.blockzapper.patternSection": "패턴 설정", + "create.gui.blockzapper.pattern.solid": "원형", + "create.gui.blockzapper.pattern.checkered": "체스판", + "create.gui.blockzapper.pattern.inversecheckered": "반전된 체스판", + "create.gui.blockzapper.pattern.chance25": "램덤으로 25% 채우기", + "create.gui.blockzapper.pattern.chance50": "램덤으로 50% 채우기", + "create.gui.blockzapper.pattern.chance75": "랜덤으로 75% 채우기", + + "create.gui.terrainzapper.title": "휴대용 세계편집기", + "create.gui.terrainzapper.placement": "설치방식", + "create.gui.terrainzapper.placement.merged": "선택한 블럭에", + "create.gui.terrainzapper.placement.attached": "선택한 블럭 옆에", + "create.gui.terrainzapper.placement.inserted": "선택한 블럭 안에", + "create.gui.terrainzapper.brush": "브러쉬", + "create.gui.terrainzapper.brush.cuboid": "정육면체", + "create.gui.terrainzapper.brush.sphere": "구", + "create.gui.terrainzapper.brush.cylinder": "원통", + "create.gui.terrainzapper.tool": "도구", + "create.gui.terrainzapper.tool.fill": "채우기", + "create.gui.terrainzapper.tool.place": "설치", + "create.gui.terrainzapper.tool.replace": "대체", + "create.gui.terrainzapper.tool.clear": "지우기", + "create.gui.terrainzapper.tool.overlay": "덮어씌우기", + "create.gui.terrainzapper.tool.flatten": "평탄화", + "create.terrainzapper.shiftRightClickToSet": "쉬프트-우클릭으로 모양 설정하기", + + "create.blockzapper.usingBlock": "현재 블럭: %1$s", + "create.blockzapper.componentUpgrades": "부품 업그레이드:", + "create.blockzapper.component.body": "몸통", + "create.blockzapper.component.amplifier": "증폭기", + "create.blockzapper.component.accelerator": "가속기", + "create.blockzapper.component.retriever": "회수기", + "create.blockzapper.component.scope": "스코프", + "create.blockzapper.componentTier.none": "없음", + "create.blockzapper.componentTier.brass": "황동", + "create.blockzapper.componentTier.chromatic": "혼돈의 결정체", + "create.blockzapper.leftClickToSet": "좌클릭으로 블럭 설정하기", + "create.blockzapper.empty": "블럭이 없습니다!", + + "create.contraptions.movement_mode": "이동 설정", + "create.contraptions.movement_mode.move_place": "멈췄을때 항상 블럭 설치하기", + "create.contraptions.movement_mode.move_place_returned": "멈췄을떄 최초 위치에서만 블럭 설치하기", + "create.contraptions.movement_mode.move_never_place": "멈춰도 블럭 설치하지 않기", + "create.contraptions.movement_mode.rotate_place": "멈췄을때 항상 블럭 설치하기", + "create.contraptions.movement_mode.rotate_place_returned": "멈췄을떄 최초 각도에서만 블럭 설치하기", + "create.contraptions.movement_mode.rotate_never_place": "멈춰도 블럭 설치하지 않기", + + "create.logistics.filter": "필터", + "create.logistics.firstFrequency": "주파수. #1", + "create.logistics.secondFrequency": "주파수. #2", + + "create.gui.goggles.generator_stats": "발전 상태:", + "create.gui.goggles.kinetic_stats": "가동 상태:", + "create.gui.goggles.at_current_speed": "현재 속도", + "create.gui.goggles.base_value": "기본 수치", + + "create.gui.gauge.info_header": "게이지 정보:", + "create.gui.speed_gauge.title": "회전 속도", + "create.gui.stress_gauge.title": "네트워크 부하", + "create.gui.stress_gauge.capacity": "용량", + "create.gui.stress_gauge.overstressed": "과부하됨", + "create.gui.stress_gauge.no_rotation": "회전없음", + + "create.gui.contraptions.not_fast_enough": "이 %1$s은(는) 작동하기에 _회전 속도_가 _부족합니다_", + "create.gui.contraptions.network_overstressed": "이 장치는 _과부하_되었습니다. _높은 피로도_ 용량을 가진 발전기를 추가로 설치하거나 장치 _속도_를 _늦추세요_.", + + "create.gui.flexcrate.title": "가변 창고 ", + "create.gui.flexcrate.storageSpace": "저장 공간", + + "create.gui.stockswitch.title": "수량 스위치", + "create.gui.stockswitch.lowerLimit": "최소 신호 유지수량", + "create.gui.stockswitch.upperLimit": "최초 신호 발동수량", + "create.gui.stockswitch.startAt": "다음 수량에 신호 주기", + "create.gui.stockswitch.startAbove": "다음 수량이상일떄 신호 주기", + "create.gui.stockswitch.stopAt": "다음 수량에 신호 멈추기", + "create.gui.stockswitch.stopBelow": "다음 수량이하일때 신호 멈추기", + + "create.gui.sequenced_gearshift.title": "순서 기어쉬프트", + "create.gui.sequenced_gearshift.instruction": "설명", + "create.gui.sequenced_gearshift.instruction.turn_angle": "회전", + "create.gui.sequenced_gearshift.instruction.turn_angle.angle": "각도", + "create.gui.sequenced_gearshift.instruction.turn_distance": "피스톤", + "create.gui.sequenced_gearshift.instruction.turn_distance.distance": "거리", + "create.gui.sequenced_gearshift.instruction.wait": "정지", + "create.gui.sequenced_gearshift.instruction.wait.duration": "지속시간", + "create.gui.sequenced_gearshift.instruction.end": "마침", + "create.gui.sequenced_gearshift.speed": "속도, 방향", + "create.gui.sequenced_gearshift.speed.forward": "입력된 속도, 그대로 회전", + "create.gui.sequenced_gearshift.speed.forward_fast": "입력된 속도의 2배, 그대로 회전", + "create.gui.sequenced_gearshift.speed.back": "입력된 속도, 반대로 회전", + "create.gui.sequenced_gearshift.speed.back_fast": "입력된 속도의 2배, 반대로 회전", + + "create.schematicAndQuill.dimensions": "청사진 크기: %1$sx%2$sx%3$s", + "create.schematicAndQuill.firstPos": "첫번쨰 위치 지정됨.", + "create.schematicAndQuill.secondPos": "두번째 위치 지정됨.", + "create.schematicAndQuill.noTarget": "[Ctrl]을 눌러 공기 블럭을 선택하기.", + "create.schematicAndQuill.abort": "위치 제거됨.", + "create.schematicAndQuill.prompt": "청사진의 제목을 작성하기:", + "create.schematicAndQuill.fallbackName": "내 청사진", + "create.schematicAndQuill.saved": "%1$s로 저장됨", + + "create.schematic.invalid": "[!] 없는 아이템 - 청사진 테이블을 이용하세요", + "create.schematic.position": "위치", + "create.schematic.rotation": "회전", + "create.schematic.rotation.none": "없음", + "create.schematic.rotation.cw90": "90도 시계방향 회전", + "create.schematic.rotation.cw180": "180도 시계방향 회전", + "create.schematic.rotation.cw270": "270도 시계방향 회전", + "create.schematic.mirror": "거울", + "create.schematic.mirror.none": "없음", + "create.schematic.mirror.frontBack": "전-후", + "create.schematic.mirror.leftRight": "좌-우", + + "create.schematic.tool.deploy": "전개", + "create.schematic.tool.move": "X/Z좌표 이동", + "create.schematic.tool.movey": "Y좌표 이동", + "create.schematic.tool.rotate": "회전", + "create.schematic.tool.print": "설치", + "create.schematic.tool.flip": "뒤집기", + + "create.schematic.tool.deploy.description.0": "구조물을 해당 위치로 고정합니다.", + "create.schematic.tool.deploy.description.1": "땅에다 우클릭으로 설치합니다.", + "create.schematic.tool.deploy.description.2": "[Ctrl]을 눌러 플레이어-청사진의 거리를 설정합니다.", + "create.schematic.tool.deploy.description.3": "[Ctrl]-스크롤로 거리를 조정합니다.", + "create.schematic.tool.move.description.0": "청사진을 수평 이동시킵니다.", + "create.schematic.tool.move.description.1": "청사진을 보고 [CTRL]-스크롤로 밉니다.", + "create.schematic.tool.move.description.2": "", + "create.schematic.tool.move.description.3": "", + "create.schematic.tool.movey.description.0": "청사진을 수직 이동시킵니다.", + "create.schematic.tool.movey.description.1": "청사진을 보고 [CTRL]-스크롤로 밉니다.", + "create.schematic.tool.movey.description.2": "", + "create.schematic.tool.movey.description.3": "", + "create.schematic.tool.rotate.description.0": "청사진을 돌립니다.", + "create.schematic.tool.rotate.description.1": "[CTRL]-스크롤로 90도 돌립니다.", + "create.schematic.tool.rotate.description.2": "", + "create.schematic.tool.rotate.description.3": "", + "create.schematic.tool.print.description.0": "구조물을 즉시 설치합니다.", + "create.schematic.tool.print.description.1": "[우클릭]으로 현재 지점에 설치를 허가합니다.", + "create.schematic.tool.print.description.2": "이 도구는 크리에이티브 모드 전용입니다.", + "create.schematic.tool.print.description.3": "", + "create.schematic.tool.flip.description.0": "당신이 보는 면으로 청사진을 뒤집습니다.", + "create.schematic.tool.flip.description.1": "청사진을 보고 [CTRL]-스크롤로 뒤집습니다.", + "create.schematic.tool.flip.description.2": "", + "create.schematic.tool.flip.description.3": "", + + "create.schematics.synchronizing": "동기화 중...", + "create.schematics.uploadTooLarge": "청사진이 너무 큽니다!.", + "create.schematics.maxAllowedSize": "최대 청사진 파일 크기는:", + + "create.gui.schematicTable.title": "청사진 테이블", + "create.gui.schematicTable.availableSchematics": "이용가능한 청사진", + "create.gui.schematicTable.noSchematics": "저장된 청사진 없음", + "create.gui.schematicTable.uploading": "업로딩 중...", + "create.gui.schematicTable.finished": "업로드 완료!", + + "create.gui.schematicannon.title": "청사진 대포", + "create.gui.schematicannon.settingsTitle": "설치 설정", + "create.gui.schematicannon.listPrinter": "재료 목록 프린터", + "create.gui.schematicannon.gunpowderLevel": "화약 용량 %1$s%%", + "create.gui.schematicannon.shotsRemaining": "남은 발포 수 : %1$s", + "create.gui.schematicannon.shotsRemainingWithBackup": "화약 여분: %1$s", + "create.gui.schematicannon.optionEnabled": "현재 활성화 됨", + "create.gui.schematicannon.optionDisabled": "현재 비활성화 됨", + "create.gui.schematicannon.option.dontReplaceSolid": "온전한 블럭을 대체하지 않음", + "create.gui.schematicannon.option.replaceWithSolid": "온전한 블럭을 재료로 대체함", + "create.gui.schematicannon.option.replaceWithAny": "온전한 블럭을 아무 재료로 대체함", + "create.gui.schematicannon.option.replaceWithEmpty": "온전한 블럭을 공기로 채움", + "create.gui.schematicannon.option.skipMissing": "부족한 블럭을 무시하고 진행", + "create.gui.schematicannon.option.skipTileEntities": "타일 엔티티를 보호", + + "create.gui.schematicannon.option.skipMissing.description": "만약 대포가 설치에 필요한 블럭을 찾지 못할 경우,건너뛰고 다음 블럭 설치를 진행합니다.", + "create.gui.schematicannon.option.skipTileEntities.description": "대포가 상세정보가 든 상자같은 타일 엔티티 설치를 무시합니다.", + "create.gui.schematicannon.option.dontReplaceSolid.description": "대포가 작업구역의 온전한 블럭을 대체하지 않습니다.", + "create.gui.schematicannon.option.replaceWithSolid.description": "대포가 작업구역의 온전한 블럭을 대포가 가진 재료로 대체합니다.", + "create.gui.schematicannon.option.replaceWithAny.description": "대포가 작업구역의 온전한 블럭을 대포가 가진 어떠한 재료로든 대체합니다.", + "create.gui.schematicannon.option.replaceWithEmpty.description": "대포가 작업구역의 블럭들을 제거하고 공기로 채웁니다.", + + "create.schematicannon.status.idle": "휴식", + "create.schematicannon.status.ready": "준비됨", + "create.schematicannon.status.running": "가동 중", + "create.schematicannon.status.finished": "완료", + "create.schematicannon.status.paused": "멈춤", + "create.schematicannon.status.stopped": "중단됨", + "create.schematicannon.status.noGunpowder": "화약이 부족함", + "create.schematicannon.status.targetNotLoaded": "블럭이 준비되지 않음", + "create.schematicannon.status.targetOutsideRange": "목표가 너무 멀리 떨어져 있습니다.", + "create.schematicannon.status.searching": "검색 중", + "create.schematicannon.status.skipping": "건너뛰는 중", + "create.schematicannon.status.missingBlock": "부족한 블럭:", + "create.schematicannon.status.placing": "설치 중", + "create.schematicannon.status.clearing": "블럭을 제거하는 중", + "create.schematicannon.status.schematicInvalid": "청사진 없음", + "create.schematicannon.status.schematicNotPlaced": "청사진이 전개되지 않음", + "create.schematicannon.status.schematicExpired": "청사진 파일이 제거됨", + + "create.gui.filter.blacklist": "블랙리스트", + "create.gui.filter.blacklist.description": "위 목록에 맞지않는 아이템이면 통과합니다. 빈 블랙리스트는 모두 통과시킵니다.", + "create.gui.filter.whitelist": "화이트리스트", + "create.gui.filter.whitelist.description": "위 목록에 맞는 아이템이면 통과합니다. 빈 화이트리스트는 모두 통과시키지 않습니다.", + "create.gui.filter.respect_data": "상세정보 일치", + "create.gui.filter.respect_data.description": "위 목록 아이템의 내구도, 마법부여, 그리고 다른 NBT와 일치할 때 통과시킵니다.", + "create.gui.filter.ignore_data": "상세정보 무시", + "create.gui.filter.ignore_data.description": "상세정보와 상관없이 아이템 종류만 일치한다면 통과시킵니다.", + + "create.item_attributes.placeable": "설치할 수 있음", + "create.item_attributes.consumable": "먹을 수 있음", + "create.item_attributes.smeltable": "구워질 수 있음", + "create.item_attributes.washable": "세척될 수 있음", + "create.item_attributes.smokable": "훈연될 수 있음", + "create.item_attributes.blastable": "용광로에 녹일 수 있음", + "create.item_attributes.enchanted": "마법부여됨", + "create.item_attributes.damaged": "내구도가 닮", + "create.item_attributes.badly_damaged": "심각하게 내구도가 닮", + "create.item_attributes.not_stackable": "겹쳐질 수 없음", + "create.item_attributes.equipable": "장착할 수 있음", + "create.item_attributes.furnace_fuel": "화로 연료로 쓸 수 있음", + "create.item_attributes.in_tag": "%1$s로 등록됨", + "create.item_attributes.in_item_group": "%1$s탭에 속함", + "create.item_attributes.added_by": "%1$s가 추가함", + + "create.gui.attribute_filter.no_selected_attributes": "속성이 선택되지 않음", + "create.gui.attribute_filter.selected_attributes": "선택된 속성:", + "create.gui.attribute_filter.whitelist_disjunctive": "화이트리스트 (최소)", + "create.gui.attribute_filter.whitelist_disjunctive.description": "아이템이 선택된 속성 중 하나라도 가지고 있다면 통과시킵니다.", + "create.gui.attribute_filter.whitelist_conjunctive": "화이트리스트 (모두)", + "create.gui.attribute_filter.whitelist_conjunctive.description": "아이템이 선택된 속성 모두를 가지고 있어야 통과시킵니다.", + "create.gui.attribute_filter.blacklist": "블랙리스트", + "create.gui.attribute_filter.blacklist.description": "아이템이 선택된 속성이 없다면 통과시킵니다.", + "create.gui.attribute_filter.add_reference_item": "참고할 아이템을 추가하기", + + "create.tooltip.holdKey": "[%1$s]를 눌러 설명보기", + "create.tooltip.holdKeyOrKey": "[%1$s] 또는 [%2$s]를 눌러 설명보기", + "create.tooltip.keyShift": "Shift", + "create.tooltip.keyCtrl": "Ctrl", + + "create.tooltip.speedRequirement": "회전속도 요구: %1$s", + "create.tooltip.speedRequirement.none": "없음", + "create.tooltip.speedRequirement.medium": "보통", + "create.tooltip.speedRequirement.high": "빠름", + + "create.tooltip.stressImpact": "피로도 부하: %1$s", + "create.tooltip.stressImpact.low": "낮음", + "create.tooltip.stressImpact.medium": "보통", + "create.tooltip.stressImpact.high": "높음", + "create.tooltip.stressImpact.overstressed": "과부하됨", + + "create.tooltip.capacityProvided": "피로도 용량: %1$s", + "create.tooltip.capacityProvided.low": "적음", + "create.tooltip.capacityProvided.medium": "보통", + "create.tooltip.capacityProvided.high": "큼", + "create.tooltip.capacityProvided.asGenerator": "(발전기로써)", + "create.tooltip.generationSpeed" : "%1$s %2$s만큼 발전함", + + "create.tooltip.analogStrength": "레드스톤 출력: %1$s/15", + + "create.tooltip.wip": "WIP", + "create.tooltip.workInProgress": "Work in progress!", + + "create.tooltip.randomWipDescription0": "Please keep this item away from children.", + "create.tooltip.randomWipDescription1": "A baby panda dies every time you use this item. Every. Time.", + "create.tooltip.randomWipDescription2": "Use at your own risk.", + "create.tooltip.randomWipDescription3": "This is not the item you are looking for, *finger-wiggles* please disperse.", + "create.tooltip.randomWipDescription4": "This item will self-destruct in 10 seconds. 10, 9, 8...", + "create.tooltip.randomWipDescription5": "Believe me, it's useless.", + "create.tooltip.randomWipDescription6": "By using this item, you hereby consent to our disclaimer and agree to its terms.", + "create.tooltip.randomWipDescription7": "This one maybe isn't for you. What about that one?", + "create.tooltip.randomWipDescription8": "Use it and regret your decision immediately.", + + "create.mechanical_mixer.min_ingredients": "최소 재료 종류", + + "create.command.killTPSCommand": "killtps", + "create.command.killTPSCommand.status.slowed_by.0": "[Create]: Server tick is currently slowed by %s ms :o", + "create.command.killTPSCommand.status.slowed_by.1": "[Create]: Server tick is slowed by %s ms now >:)", + "create.command.killTPSCommand.status.slowed_by.2": "[Create]: Server tick is back to regular speed :D", + "create.command.killTPSCommand.status.usage.0": "[Create]: use /killtps stop to bring back server tick to regular speed", + "create.command.killTPSCommand.status.usage.1": "[Create]: use /killtps start to artificially slow down the server tick", + "create.command.killTPSCommand.argument.tickTime": "tickTime", + + "advancement.create:root": "처음부터 Create하기!", + "advancement.create:root.desc": "멋진 장치들을 만들 시간이야!", + "advancement.create:andesite_alloy": "이게.. 합금..?", + "advancement.create:andesite_alloy.desc": "Create모드는 조금 이상한 아이템이 있습니다. 안산암 합금이 그 중 하나죠.", + "advancement.create:andesite_casing": "안산암 시대", + "advancement.create:andesite_casing.desc": "안산암, 나무를 이용하여 기본 케이스를 만드세요.", + "advancement.create:crushing_wheel": "한 쌍의 거인들", + "advancement.create:crushing_wheel.desc": "재료들을 갈 분쇄 휠을 만드세요.", + "advancement.create:rotation": "움직인다!", + "advancement.create:rotation.desc": "당신의 첫 장치가 움직이는 것을 보세요.", + "advancement.create:overstressed": "과부화!", + "advancement.create:overstressed.desc": "직접 물리법칙을 경험해보세요.", + "advancement.create:sand_paper": "힘세고 강한 윤내기", + "advancement.create:sand_paper.desc": "사포를 만들고 재료를 윤내세요.", + "advancement.create:polished_rose_quartz": "분홍빛 다이아몬드", + "advancement.create:polished_rose_quartz.desc": "장밋빛 석영을 반대편까지 보이도록 열심히 사포질하세요.", + "advancement.create:sand_paper_secret": "사포, 사포, 사포!", + "advancement.create:sand_paper_secret.desc": "당신의 사포로 사포를 사포질 하세요!", + "advancement.create:press": "'깡!'", + "advancement.create:press.desc": "압착기를 만들고 판을 찍으세요.", + "advancement.create:mixer": "섞고 돌리고 섞고", + "advancement.create:mixer.desc": "믹서를 만드세요.", + "advancement.create:brass": "진짜 합금", + "advancement.create:brass.desc": "구리와 아연을 가지고 황동을 만드세요.", + "advancement.create:brass_casing": "황동기 시대", + "advancement.create:brass_casing.desc": "새롭게 얻은 황동과 나무를 가지고 업그레이드된 케이스를 만드세요.", + "advancement.create:deployer": "찌르고, 설치하고, 공격!", + "advancement.create:deployer.desc": "완벽한 당신의 분신, 배포기를 만드세요.", + "advancement.create:deployer_secret": "Pound It, Bro!", + "advancement.create:deployer_secret.desc": "두 배포기의 주먹을 부딫치세요.", + "advancement.create:chromatic_compound": "양극성 재료", + "advancement.create:chromatic_compound.desc": "색채 혼합물를 만드세요.", + "advancement.create:shadow_steel": "공허를 받아들여라", + "advancement.create:shadow_steel.desc": "무의 금속, 그림자 강철을 생성하세요.", + "advancement.create:refined_radiance": "빛과 질서", + "advancement.create:refined_radiance.desc": "색이 하나로 합쳐진 정제된 빛을 생성하세요.", + "advancement.create:refined_radiance_secret": "빛줄기로 제련되다", + "advancement.create:refined_radiance_secret.desc": "정제된 광채를 만들 대체제를 찾아보세요.", + "advancement.create:speed_secret": "?", + "advancement.create:speed_secret.desc": "속도 계측기가 정확히 69RPM에 도달하는걸 보세요.", + + "create.subtitle.schematicannon_launch_block": "청사진 대포가 발포함", + "create.subtitle.schematicannon_finish": "청사진 대포가 끝남", + "create.subtitle.slime_added": "슬라임이 철퍽거림", + "create.subtitle.mechanical_press_activation": "압착기가 가동됨", + "create.subtitle.mechanical_press_item_break": "금속이 부딫힘", + "create.subtitle.blockzapper_place": "블럭이 순간이동됨", + "create.subtitle.blockzapper_confirm": "확인 효과음", + "create.subtitle.blockzapper_deny": "취소 효과음", + "create.subtitle.block_funnel_eat": "깔때기가 흡입함", + + "_comment": "-------------------------] ITEM DESCRIPTIONS [------------------------------------------------", + "item.create.example_item.tooltip": "EXAMPLE ITEM (just a marker that this tooltip exists)", + "item.create.example_item.tooltip.summary": "A brief description of the item. _Underscores_ highlight a term.", + "item.create.example_item.tooltip.condition1": "When this", + "item.create.example_item.tooltip.behaviour1": "Then this item does this. (behaviours show on shift)", + "item.create.example_item.tooltip.condition2": "And When this", + "item.create.example_item.tooltip.behaviour2": "You can add as many behaviours as you like", + "item.create.example_item.tooltip.control1": "When Ctrl pressed", + "item.create.example_item.tooltip.action1": "These controls are displayed.", + + "item.create.symmetry_wand.tooltip": "SYMMETRY WAND", + "item.create.symmetry_wand.tooltip.summary": "설정된 반사 모드에 따라 블럭 설치를 똑같이 재현합니다.", + "item.create.symmetry_wand.tooltip.condition1": "단축바에 있을 때", + "item.create.symmetry_wand.tooltip.behaviour1": "활성화 유지", + "item.create.symmetry_wand.tooltip.control1": "땅에다 우클릭", + "item.create.symmetry_wand.tooltip.action1": "거울을 _생성하거나_ _옮깁니다_.", + "item.create.symmetry_wand.tooltip.control2": "공중에 우클릭", + "item.create.symmetry_wand.tooltip.action2": "활성화된 거을을 _제거합니다_.", + "item.create.symmetry_wand.tooltip.control3": "웅크린 상태에서 우클릭", + "item.create.symmetry_wand.tooltip.action3": "_설정_ _창_을 엽니다.", + + "item.create.placement_handgun.tooltip": "BLOCKZAPPER", + "item.create.placement_handgun.tooltip.summary": "멀리있는 블럭을 교체, 설치하는 놀라운 도구입니다.", + "item.create.placement_handgun.tooltip.control1": "블럭을 보고 좌클릭", + "item.create.placement_handgun.tooltip.action1": "이 도구로 설치할 블럭을 설정합니다.", + "item.create.placement_handgun.tooltip.control2": "블럭을 보고 우클릭", + "item.create.placement_handgun.tooltip.action2": "해당 위치에 설정된 블럭으로 설치하거나 교체합니다.", + "item.create.placement_handgun.tooltip.control3": "웅크린 상태에서 우클릭", + "item.create.placement_handgun.tooltip.action3": "_설정_ _창_을 엽니다.", + + "item.create.terrain_zapper.tooltip": "HANDHELD WORLDSHAPER", + "item.create.terrain_zapper.tooltip.summary": "_지형경관_을 만들 때 좋은 간편한 도구입니다.", + "item.create.terrain_zapper.tooltip.control1": "블럭을 보고 좌클릭", + "item.create.terrain_zapper.tooltip.action1": "이 도구로 설치할 블럭을 설정합니다.", + "item.create.terrain_zapper.tooltip.control2": "블럭을 보고 우클릭", + "item.create.terrain_zapper.tooltip.action2": "해당 위치에 설정된 _브러쉬_ 와 _도구_를 적용합니다.", + "item.create.terrain_zapper.tooltip.control3": "웅크린 상태에서 우클릭", + "item.create.terrain_zapper.tooltip.action3": "_설정_ _창_을 엽니다.", + + "item.create.tree_fertilizer.tooltip": "TREE FERTILIZER", + "item.create.tree_fertilizer.tooltip.summary": "일반적인 나무 종류들의 성장을 촉진시킬 강력한 미네랄의 혼합물입니다.", + "item.create.tree_fertilizer.tooltip.condition1": "묘목에 사용했을 때", + "item.create.tree_fertilizer.tooltip.behaviour1": "묘목을 주위 공간과 _상관없이_ 성장시킵니다.", + + "item.create.deforester.tooltip": "DEFORESTER", + "item.create.deforester.tooltip.summary": "수 초 만에 나무를 쓰러뜨리는 _경이로운_ _도끼_입니다.", + + "item.create.filter.tooltip": "FILTER", + "item.create.filter.tooltip.summary": "장치의 _입력_과 _출력_을 필터 _아이템_ 목록에 따라 정확하게 _조정_합니다.", + "item.create.filter.tooltip.condition1": "필터 슬롯에 있을 때", + "item.create.filter.tooltip.behaviour1": "필터 _설정_에 따라 아이템 흐름을 _조정_합니다.", + "item.create.filter.tooltip.condition2": "우클릭", + "item.create.filter.tooltip.behaviour2": "_설정_ _창_을 엽니다.", + + "item.create.property_filter.tooltip": "ATTRIBUTE FILTER", + "item.create.property_filter.tooltip.summary": "장치의 _입력_과 _출력_을 필터 _속성_ 목록에 따라 정확하게 _조정_합니다.", + "item.create.property_filter.tooltip.condition1": "필터 슬롯에 있을 때", + "item.create.property_filter.tooltip.behaviour1": "필터 _설정_에 따라 아이템 흐름을 _조정_합니다.", + "item.create.property_filter.tooltip.condition2": "우클릭", + "item.create.property_filter.tooltip.behaviour2": "_설정_ _창_을 엽니다.", + + "block.create.cocoa_log.tooltip": "COCOA LOG", + "block.create.cocoa_log.tooltip.summary": "코코아 콩 _자동화_를 더 쉽게 해줄 정글 나무 원목입니다.", + "block.create.cocoa_log.tooltip.condition1": "성장했을 때", + "block.create.cocoa_log.tooltip.behaviour1": "모든 면에 코코아 콩을 생성합니다.", + + "item.create.empty_blueprint.tooltip": "EMPTY SCHEMATIC", + "item.create.empty_blueprint.tooltip.summary": "조합 재료로 쓰이거나 청사진 테이블에서 청사진을 불러올 때 쓰입니다.", + + "item.create.blueprint.tooltip": "SCHEMATIC", + "item.create.blueprint.tooltip.summary": "세계에 구조물을 홀로그램으로 불러와 지정하고 설치합니다. 지정된 홀로그램은 청사진 대포의 작업 영역이 됩니다.", + "item.create.blueprint.tooltip.condition1": "들고 있을 떄", + "item.create.blueprint.tooltip.behaviour1": "UI의 도구로 변경/설치 할 수 있습니다.", + "item.create.blueprint.tooltip.control1": "웅크린 상태에서 우클릭", + "item.create.blueprint.tooltip.action1": "정확한 _좌표_ 입력을 위한 창을 엽니다.", + + "item.create.blueprint_and_quill.tooltip": "SCHEMATIC AND QUILL", + "item.create.blueprint_and_quill.tooltip.summary": "세계에 있는 구조물을 .nbt 파일로 저장할 때 쓰입니다.", + "item.create.blueprint_and_quill.tooltip.condition1": "1단계", + "item.create.blueprint_and_quill.tooltip.behaviour1": "두 모서리를 우클릭으로 선택하세요.", + "item.create.blueprint_and_quill.tooltip.condition2": "2단계", + "item.create.blueprint_and_quill.tooltip.behaviour2": "면을 바라보고 _Ctrl-스크롤_하여 크기를 조정하세요. 우클릭을 다시 하면 저장됩니다.", + "item.create.blueprint_and_quill.tooltip.control1": "우클릭", + "item.create.blueprint_and_quill.tooltip.action1": "모서리 선택 / 저장 확인", + "item.create.blueprint_and_quill.tooltip.control2": "Ctrl를 누르고 있을 때", + "item.create.blueprint_and_quill.tooltip.action2": "_Scroll_를 이용하여 거리를 조정합니다.", + "item.create.blueprint_and_quill.tooltip.control3": "웅크린 상태에서 우클릭", + "item.create.blueprint_and_quill.tooltip.action3": "선택 영역을 리셋하고 _삭제_합니다.", + + "block.create.creative_crate.tooltip": "CREATIVE CRATE", + "block.create.creative_crate.tooltip.summary": "옆 _청사진 대포_에 _무한한_ 재료를 공급합니다.", + + "block.create.schematicannon.tooltip": "SCHEMATICANNON", + "block.create.schematicannon.tooltip.summary": "장착된 청사진을 바탕으로 블럭들을 발포합니다. 화약을 연료로 사용하고 주변 인벤토리 공간에서 아이템을 사용합니다.", + "block.create.schematicannon.tooltip.control1": "우클릭", + "block.create.schematicannon.tooltip.action1": "창을 엽니다.", + + "block.create.schematic_table.tooltip": "SCHEMATIC TABLE", + "block.create.schematic_table.tooltip.summary": "_빈_ _청사진_에 저장된 청사진을 불러옵니다.", + "block.create.schematic_table.tooltip.condition1": "빈 청사진을 넣을 때", + "block.create.schematic_table.tooltip.behaviour1": "Schematics 폴더에서 선택한 파일을 업로드합니다.", + + "block.create.shaft.tooltip": "SHAFT", + "block.create.shaft.tooltip.summary": "_일직선_으로 _회전_을 전달합니다.", + + "block.create.cogwheel.tooltip": "COGWHEEL", + "block.create.cogwheel.tooltip.summary": " _일직선_이나 _옆_ _톱니바퀴_로 _회전_을 _전달_합니다.", + + "block.create.large_cogwheel.tooltip": "LARGE COGWHEEL", + "block.create.large_cogwheel.tooltip.summary": "큰 톱니바퀴입니다. 작은 톱니바퀴와 맞물렸을때, _회전 속도_가 _변합니다_.", + + "block.create.encased_shaft.tooltip": "ENCASED SHAFT", + "block.create.encased_shaft.tooltip.summary": "_일직선_으로 _회전_을 전달합니다. _벽을_ _넘어_ 회전을 보낼 때 유용합니다.", + + "block.create.gearbox.tooltip": "GEARBOX", + "block.create.gearbox.tooltip.summary": "_전후좌우_ / _상하전후_로 회전을 보냅니다. 한번 더 조합해서 설정을 바꿀 수 있습니다.", + + "block.create.gearshift.tooltip": "GEARSHIFT", + "block.create.gearshift.tooltip.summary": "연결된 축의 회전 방향을 _변경_합니다.", + "block.create.gearshift.tooltip.condition1": "레드스톤 신호를 받았을 때", + "block.create.gearshift.tooltip.behaviour1": "_출력_ 회전 방향을 _반전_시킵니다.", + + "block.create.clutch.tooltip": "CLUTCH", + "block.create.clutch.tooltip.summary": "연결된 축의 회전을 끄고 킬 수 있습니다.", + "block.create.clutch.tooltip.condition1": "레드스톤 신호를 받았을 때", + "block.create.clutch.tooltip.behaviour1": "출력 방향 회전을 멈춥니다.", + + "block.create.encased_belt.tooltip": "ENCASED_BELT", + "block.create.encased_belt.tooltip.summary": "연결된 다른 _덮힌 벨트_에 회전을 _연결_합니다.", + "block.create.encased_belt.tooltip.condition1": "축에 연결 되었을 때", + "block.create.encased_belt.tooltip.behaviour1": "연결된 축, 기어, 장치들은 _같은_ _회전_ _속도_와 _방향_을 가집니다. 같은 방향으로 _맞대지_ _않아도_ _됩니다_.", + + "block.create.adjustable_pulley.tooltip": "ANALOG BELT PULLEY", + "block.create.adjustable_pulley.tooltip.summary": "덮힌 벨트와 같은 역할을 가집니다. 또한 입/출력 부분에 설치하고 레드스톤 신호 세기에 따라 _회전_ _속도_를 _조정_할 수 있습니다.", + "block.create.adjustable_pulley.tooltip.condition1": "레드스톤 신호 설정", + "block.create.adjustable_pulley.tooltip.behaviour1": "_입력_ 부분에 설치하면 출력 회전 속도를 _낮추고_ (최대 0.5배), _출력_ 부분에 설치하면 출력 회전 속도를 _증가시킵니다_ (최대 2배).", + + "item.create.belt_connector.tooltip": "BELT CONNECTOR", + "item.create.belt_connector.tooltip.summary": "두 개 이상의 _축_을 벨트로 연결할 수 있습니다. 연결된 축들은 _모두_ _같은_ _속도_와 _방향_을 가집니다. 벨트는 _아이템_이나 _엔티티_를 _옮길_ _수_ _있습니다_.", + "item.create.belt_connector.tooltip.control1": "축에다 우클릭", + "item.create.belt_connector.tooltip.action1": "첫번째 벨트 끝부분을 설정합니다. 두번째 축은 반드시 _수평_이나 _수직_, _대각선_ 방향에 있는 축에 연결해야합니다.", + "item.create.belt_connector.tooltip.control2": "웅크린 상태에서 우클릭", + "item.create.belt_connector.tooltip.action2": "첫번째 벨트 설정을 초기화합니다.", + + "item.create.goggles.tooltip": "GOGGLES", + "item.create.goggles.tooltip.summary": "장치 정보를 착용자의 시야에 띄어주는 안경입니다.", + "item.create.goggles.tooltip.condition1": "장착했을 때", + "item.create.goggles.tooltip.behaviour1": "해당 장치의 _속도_, _피로도_, _용량_을 레벨에 따라 에 따라 색상 UI를 보여줍니다.", + "item.create.goggles.tooltip.condition2": "계측기를 바라볼 때", + "item.create.goggles.tooltip.behaviour2": "계측기가 연결된 네트워크의 _속도_나 _스트레스_의 자세한 정보를 보여줍니다.", + + "item.create.wrench.tooltip": "WRENCH", + "item.create.wrench.tooltip.summary": "장치 구성에 유용한 도구입니다. 장치를 _회전_, _설정_, _해체_하는 데 쓰입니다.", + "item.create.wrench.tooltip.control1": "장치에 우클릭", + "item.create.wrench.tooltip.action1": "사용자가 바라보는 _면으로_ 혹은 _반대로_ 장치를 돌립니다.", + "item.create.wrench.tooltip.control2": "웅크린 상태에서 우클릭", + "item.create.wrench.tooltip.action2": "_장치_를 _해체_하고 _즉시_ _인벤토리_로 넣습니다.", + + "block.create.creative_motor.tooltip": "CREATIVE MOTOR", + "block.create.creative_motor.tooltip.summary": "회전 속도를 _조정_할 수 있는 장치입니다.", + + "block.create.water_wheel.tooltip": "WATER WHEEL", + "block.create.water_wheel.tooltip.summary": "인접한 _물의_ _흐름_에서 얻은 회전을 제공합니다.", + + "block.create.encased_fan.tooltip": "ENCASED FAN", + "block.create.encased_fan.tooltip.summary": "회전력을 바람으로 전환합니다. 다양한 용도로 사용 가능합니다.", + "block.create.encased_fan.tooltip.condition1": "레드스톤 신호를 받을 때", + "block.create.encased_fan.tooltip.behaviour1": "장치 아래의 _열_을 _회전력_으로 _바꾸어_ 제공합니다. 날개가 아래를 바라보아야 합니다.", + "block.create.encased_fan.tooltip.condition2": "돌려질 때", + "block.create.encased_fan.tooltip.behaviour2": "들어오는 회적 속도에 따라 엔티티를 밀거나 당깁니다.", + "block.create.encased_fan.tooltip.condition3": "특정 블럭을 통해 바람을 보낼 때", + "block.create.encased_fan.tooltip.behaviour3": "공기 흐름에 _액체_ 혹은 _불꽃_ 효과가 _추가_됩니다. 이는 아이템을 _공정_하는데 쓰일 수 있습니다.", + + "block.create.nozzle.tooltip": "NOZZLE", + "block.create.nozzle.tooltip.summary": "덮힌 환풍기 _앞_에 붙여 환풍기의 효과를 _전방_으로 _확대_합니다.", + + "block.create.hand_crank.tooltip": "HAND CRANK", + "block.create.hand_crank.tooltip.summary": "간단한 회전력의 원천입니다. 플레이어의 _상호작용_이 필요합니다.", + "block.create.hand_crank.tooltip.condition1": "사용될 때", + "block.create.hand_crank.tooltip.behaviour1": "연결된 장치에 _회전력_을 _제공_합니다. 웅크리면 _반대로_ 회전시킵니다.", + + "block.create.cuckoo_clock.tooltip": "CUCKOO CLOCK", + "block.create.cuckoo_clock.tooltip.summary": "_시간의_ _흐름_을 알고 공간을 _꾸미는_ 데 좋은 공예품입니다.", + "block.create.cuckoo_clock.tooltip.condition1": "회전할 때", + "block.create.cuckoo_clock.tooltip.behaviour1": "현재 시각을 보여주고 하루에 두 번 울립니다. 점심과 플레이어가 바로 잘 수 있는 저녁에 울립니다.", + + "block.create.turntable.tooltip": "TURNTABLE", + "block.create.turntable.tooltip.summary": "_회전력_으로 _멀미_를 일으킵니다.", + + "block.create.millstone.tooltip": "MILLSTONE", + "block.create.millstone.tooltip.summary": "투입된 _재료_를 _가는_ 데 좋은 장치입니다. 측면 톱니바퀴나 바닥에 축을 이어 작동합니다. 결과물은 직접 빼내야 합니다.", + "block.create.millstone.tooltip.condition1": "회전 할 때", + "block.create.millstone.tooltip.behaviour1": "옆이나 위에서 투입된 아이템을 _맷돌질_합니다.", + "block.create.millstone.tooltip.condition2": "우클릭할때", + "block.create.millstone.tooltip.behaviour2": "결과물을 직접 꺼냅니다.", + + "block.create.crushing_wheel.tooltip": "CRUSHING WHEEL", + "block.create.crushing_wheel.tooltip.summary": "모든 것을 _부숴버리는_ 큰 바퀴입니다.", + "block.create.crushing_wheel.tooltip.condition1": "다른 분쇄 휠과 붙어있을 때", + "block.create.crushing_wheel.tooltip.behaviour1": "다양한 것을 _분쇄_하는 분쇄 기계를 형성합니다. 휠의 이빨이 _같은_ _속력_으로, _반대_ _방향_으로 맞물려야합니다.", + + "block.create.mechanical_press.tooltip": "MECHANICAL PRESS", + "block.create.mechanical_press.tooltip.summary": "아래있는 아이템을 _눌러버리는_ 힘센 피스톤입니다. _지속적인_ _회전력_이 필요합니다.", + "block.create.mechanical_press.tooltip.condition1": "레드스톤 신호를 받았을 때", + "block.create.mechanical_press.tooltip.behaviour1": "_아래 있는_ 아이템을 누르기 시작합니다.", + "block.create.mechanical_press.tooltip.condition2": "컨베이어 벨트 위에 있을 때", + "block.create.mechanical_press.tooltip.behaviour2": "_자동으로_ 벨트 위를 지나가는 아이템을 누릅니다.", + "block.create.mechanical_mixer.tooltip.condition3": "대야 위에 있을 때", + "block.create.mechanical_mixer.tooltip.behaviour3": "필요한 재료들이 _들어올_ _때마다_ 아이템을 _압축_시킵니다.", + + "block.create.basin.tooltip": "BASIN", + "block.create.basin.tooltip.summary": "믹서나 압착기와 같이 쓰이는 간편한 _아이템_ _저장소_입니다. 레드스톤 비교기와 호환됩니다.", + + "block.create.mechanical_mixer.tooltip": "MECHANICAL MIXER", + "block.create.mechanical_mixer.tooltip.summary": "아래있는 아이템을 조합할 혼합기입니다. _지속적인_ _회전력_과 한 칸 아래에 _대야_가 필요합니다.", + "block.create.mechanical_mixer.tooltip.condition1": "대야 위에 있을 때", + "block.create.mechanical_mixer.tooltip.behaviour1": "모든 필요한 아이템이 준비될 때마다 대야 안의 아이템을 섞기 시작합니다.", + "block.create.mechanical_mixer.tooltip.condition2": "렌치를 사용할 때", + "block.create.mechanical_mixer.tooltip.behaviour2": "필요한 조합법의 _최소_ _재료_ _종류_를 설정합니다. 이는 적은 재료로 _원치_ _않은_ _조합법_이 작동되는 것을 막습니다.", + + "block.create.mechanical_crafter.tooltip": "MECHANICAL CRAFTER", + "block.create.mechanical_crafter.tooltip.summary": "모든 조합법을 _자동화_할 장치입니다. 조합법대로 여러개를 _격자_로 설치하고, 화살표를 돌려 _한_ _곳으로_ _모이게_ 설정해야합니다.", + "block.create.mechanical_crafter.tooltip.condition1": "회전할 때", + "block.create.mechanical_crafter.tooltip.behaviour1": "모든 조합칸에 있는 아이템들을 조합하기 시작합니다.", + "block.create.mechanical_crafter.tooltip.control1": "전면을 렌치로 조정할 때", + "block.create.mechanical_crafter.tooltip.action1": "각 기계식 조합기의 아이템 이동 방향을 설정합니다. 모든 조합기의 방향은 _하나의_ _최종_ _조합기_로 이동해야하며, 최종 조합기는 조합기 _바깥으로_ 아이템을 운송해야합니다.", + "block.create.mechanical_crafter.tooltip.control2": "측면/후면에서 렌치로 조정할 때", + "block.create.mechanical_crafter.tooltip.action2": "인접한 조합기와 입력 공간을 _연결_합니다. 이를 통해 일일히 아이템을 넣는 노력을 줄일 수 있습니다.", + + "block.create.furnace_engine.tooltip": "FURNACE ENGINE", + "block.create.furnace_engine.tooltip.summary": "_화로의_ _작동_을 필요로 하는 강력한 회전 동력원입니다.", + "block.create.furnace_engine.tooltip.condition1": "작동하는 화로에 붙였을 때", + "block.create.furnace_engine.tooltip.behaviour1": "붙어있는(한칸 띄어져있는) _플라이휠_에 동력을 공급합니다. _용광로_는 _두_ _배_의 화력을 냅니다.", + + "block.create.flywheel.tooltip": "FLYWHEEL", + "block.create.flywheel.tooltip.summary": "붙어있는 _화로_ _엔진_에서 생산된 힘을 안정시키고 _동력화_하는 거대한 금속 바퀴입니다. 화로 엔진으로부터 _한_ _칸_ _떨어져_ 설치해야 합니다.", + "block.create.flywheel.tooltip.condition1": "작동하는 엔진에 붙었을 때", + "block.create.flywheel.tooltip.behaviour1": "엔진의 힘에 따라 연결된 장치에 _회전력_을 제공합니다.", + + "block.create.portable_storage_interface.tooltip": "PORTABLE STORAGE INTERFACE", + "block.create.portable_storage_interface.tooltip.summary": "움직이는 피스톤, 베어링, 수레, 밧줄 도르래의 인벤토리에서 _아이템을_ _교환하는_ 휴대용 장치입니다.", + "block.create.portable_storage_interface.tooltip.condition1": "움직일 때", + "block.create.portable_storage_interface.tooltip.behaviour1": "고정된 트랜스포저의 _방향에_ _따라_ 아이템을 _주거나_ _받습니다_. 아이템이 이동하는 동안 움직이는 기기는 _멈춥니다_.", + + "block.create.rotation_speed_controller.tooltip": "ROTATION SPEED CONTROLLER", + "block.create.rotation_speed_controller.tooltip.summary": "해당 톱니바퀴의 속도를 _변경_할 수 있는 컨트롤러입니다.", + "block.create.rotation_speed_controller.tooltip.condition1": "큰 톱니바퀴와 연결되었을 때", + "block.create.rotation_speed_controller.tooltip.behaviour1": "들어오는 회전력을 받아, 대상의 속도를 변경합니다. _큰_ _톱니바퀴_가 컨트롤러 위에 있어야합니다.", + + "block.create.mechanical_piston.tooltip": "MECHANICAL PISTON", + "block.create.mechanical_piston.tooltip.summary": "피스톤의 업그레이드 버전입니다. 회전력을 사용해 연결된 구조물을 옮깁니다. _피스톤_ _연장_ _축_을 후면에 붙여 이 장치의 사거리를 늘이거나 줄일 수 있습니다. 축이 없다면 움직이지 않습니다. _섀시_나 _슬라임_ _블럭_을 붙여 일직선의 블럭들을 움직일 수 있습니다.", + "block.create.mechanical_piston.tooltip.condition1": "회전될 때", + "block.create.mechanical_piston.tooltip.behaviour1": "붙어있는 구조물을 움직이기 시작합니다. 속도와 방향은 들어오는 회전 속도와 방향에 따라 달라집니다.", + + "block.create.sticky_mechanical_piston.tooltip": "STICKY MECHANICAL PISTON", + "block.create.sticky_mechanical_piston.tooltip.summary": "끈끈이 피스톤의 업그레이드 버전입니다. 회전력을 사용해 연결된 구조물을 옮깁니다. _피스톤_ _연장_ _축_을 후면에 붙여 이 장치의 사거리를 늘이거나 줄일 수 있습니다. 축이 없다면 움직이지 않습니다. _섀시_나 _슬라임_ _블럭_을 붙여 일직선의 블럭들을 움직일 수 있습니다.", + "block.create.sticky_mechanical_piston.tooltip.condition1": "회전될 때", + "block.create.sticky_mechanical_piston.tooltip.behaviour1": "붙어있는 구조물을 움직이기 시작합니다. 속도와 방향은 들어오는 회전 속도와 방향에 따라 달라집니다.", + + "block.create.piston_pole.tooltip": "PISTON POLE", + "block.create.piston_pole.tooltip.summary": "기계식 피스톤의 _사거리_를 늘려줍니다.", + "block.create.piston_pole.tooltip.condition1": "기계식 피스톤에 연결했을 때", + "block.create.piston_pole.tooltip.behaviour1": "피스톤의 사거리를 한 블럭 늘립니다.", + + "block.create.mechanical_bearing.tooltip": "MECHANICAL BEARING", + "block.create.mechanical_bearing.tooltip.summary": "큰 구조물을 _회전_시키거나 _바람으로부터_ 회전력을 얻습니다.", + "block.create.mechanical_bearing.tooltip.condition1": "회전될 때", + "block.create.mechanical_bearing.tooltip.behaviour1": "연결된 블럭들을 돌리기 시작합니다. _섀시_나 _슬라임_ _블럭_을 이용해 더 많은 블럭을 움직이세요.", + "block.create.mechanical_bearing.tooltip.condition2": "레드스톤 신호를 받을 때", + "block.create.mechanical_bearing.tooltip.behaviour2": "붙어있는 구조물의 회전을 이용하여 회전력을 제공합니다. 구조물은 _날개_에 적합한 블럭이 포함되어야합니다. (현재는 _아무_ _양털_이나 가능합니다).", + + "block.create.clockwork_bearing.tooltip": "CLOCKWORK BEARING", + "block.create.clockwork_bearing.tooltip.summary": "현재 _인게임_ _시간_을 알려주는 _시침_, _분침_을 돌리는 업그레이드된 베어링입니다.", + "block.create.clockwork_bearing.tooltip.condition1": "회전될 때", + "block.create.clockwork_bearing.tooltip.behaviour1": "현재 시간에 맞춰 연결된 구조물을 _시침_으로써 돌리기 시작합니다. _다른_ _종류의_ _섀시_가 있다면, _분침_처럼 돌립니다.", + + "block.create.sequenced_gearshift.tooltip": "SEQUENCED GEARSHIFT", + "block.create.sequenced_gearshift.tooltip.summary": "연속으로 5개의 회전 명령을 내릴 수 있는 _프로그램이_ _가능한_ 장치입니다. 이것으로 베어링, 피스톤, 도르래의 움직임과 타이밍을 정할 수 있습니다. 빠른 속력에는 부정확해질 수 있습니다.", + "block.create.sequenced_gearshift.tooltip.condition1": "레드스톤 신호를 받을 때", + "block.create.sequenced_gearshift.tooltip.behaviour1": "입력 속도에 따른 프로그램된 명령들을 수행하기 시작합니다.", + "block.create.sequenced_gearshift.tooltip.condition2": "우클릭했을 때", + "block.create.sequenced_gearshift.tooltip.behaviour2": "설정 창을 엽니다.", + + "block.create.cart_assembler.tooltip": "CART ASSEMBLER", + "block.create.cart_assembler.tooltip.summary": "지나가는 _광산_ _수레_에 연결된 구조물을 붙입니다.", + "block.create.cart_assembler.tooltip.condition1": "레드스톤 신호를 받을 때", + "block.create.cart_assembler.tooltip.behaviour1": "지나가는 광산 수레에 장착된 구조물을 분리시키고 조립기에 다시 설치합니다.", + + "block.create.rope_pulley.tooltip": "ROPE PULLEY", + "block.create.rope_pulley.tooltip.summary": "_수직으로_ 붙은 구조물을 움직입니다. _섀시_나 _슬라임_ _블럭_을 붙여 일직선의 블럭들을 움직일 수 있습니다.", + "block.create.rope_pulley.tooltip.condition1": "회전될 때", + "block.create.rope_pulley.tooltip.behaviour1": "연결된 구조물을 움직이기 시작합니다. 속도와 방향은 들어오는 회전 속도, 방향에 따라 다릅니다.", + + "block.create.translation_chassis.tooltip": "TRANSLATION CHASSIS", + "block.create.translation_chassis.tooltip.summary": "연결된 구조물의 이동을 위한 베이스 블럭입니다.", + "block.create.translation_chassis.tooltip.condition1": "움직일 때", + "block.create.translation_chassis.tooltip.behaviour1": "섀시의 _기둥_ _방향_으로 붙어있는 모든 블럭들을 같은 방향으로 옮깁니다. 블럭들은 섀시가 끈끈할 때만 당겨집니다 ([Ctrl]를 누르세요).", + "block.create.translation_chassis.tooltip.condition2": "렌치로 조정할 때", + "block.create.translation_chassis.tooltip.behaviour2": "대상 섀시의 사거리를 조정합니다. 또는 CTRL을 눌러 인접한 모든 섀시의 사거리를 조정합니다.", + "block.create.translation_chassis.tooltip.control1": "슬라임 볼로 우클릭", + "block.create.translation_chassis.tooltip.action1": "대상 면을 끈끈하게 만듭니다. 당겨질 때, 섀시는 연결된 _모든_ _블럭_을 움직이는 방향에 상관없이 당깁니다.", + + "block.create.rotation_chassis.tooltip": "ROTATION CHASSIS", + "block.create.rotation_chassis.tooltip.summary": "연결된 구조물의 이동을 위한 베이스 블럭입니다.", + "block.create.rotation_chassis.tooltip.condition1": "움직일 때", + "block.create.rotation_chassis.tooltip.behaviour1": "섀시의 _원_ _방향_으로 붙어있는 모든 블럭들을 같은 방향으로 옮깁니다. 블럭들이 섀시가 끈끈한 면에 붙어있을 때만 움직입니다 ([Ctrl]를 누르세요).", + "block.create.rotation_chassis.tooltip.condition2": "렌치로 조정할 때", + "block.create.rotation_chassis.tooltip.behaviour2": "대상 섀시의 사거리를 조정합니다. 또는 CTRL을 눌러 인접한 모든 섀시의 사거리를 조정합니다.", + "block.create.rotation_chassis.tooltip.control1": "슬라임 볼로 우클릭", + "block.create.rotation_chassis.tooltip.action1": "대상 면을 끈끈하게 만듭니다. 당겨질 때, 끈끈한 면에 붙은 _모든_ _블럭_을 움직이게 합니다", + + "block.create.drill.tooltip": "MECHANICAL DRILL", + "block.create.drill.tooltip.summary": "블럭을 _파괴하는_ 데 적합한 장치입니다. 베어링이나 기계식 피스톤으로 움직여집니다.", + "block.create.drill.tooltip.condition1": "회전될 때", + "block.create.drill.tooltip.behaviour1": "고정되어 블럭을 부숩니다. 또한 해당영역의 엔티티에게 피해를 줍니다.", + "block.create.drill.tooltip.condition2": "움직일 때", + "block.create.drill.tooltip.behaviour2": "드릴이 부딫히는 모든 블럭을 부숩니다.", + + "block.create.harvester.tooltip": "MECHANICAL HARVESTER", + "block.create.harvester.tooltip.summary": "중간 크기의 작물 자동화에 적합한 _작물_ _수확기_입니다. 베어링이나 기계식 피스톤으로 움직여집니다.", + "block.create.harvester.tooltip.condition1": "움직일 때", + "block.create.harvester.tooltip.behaviour1": "칼날에 닿는 모두 자란 작물을 수확하고 최초 성장 상태로 변경합니다.", + + "block.create.saw.tooltip": "MECHANICAL SAW", + "block.create.saw.tooltip.summary": "효율적인 _벌목_과 블럭을 _제재_하는데 적합합니다. 베어링이나 기계식 피스톤으로 움직여집니다.", + "block.create.saw.tooltip.condition1": "위를 바라볼 때", + "block.create.saw.tooltip.behaviour1": "_제재_와 _석재_ _절단_ 조합법을 떨어진/투입된 아이템에 적용합니다. 결과물이 여러 종류고 필터가 적용이 되지 않았다면, 결과물은 _목록_ _순서_대로 배출됩니다.", + "block.create.saw.tooltip.condition2": "옆을 바라볼 때", + "block.create.saw.tooltip.behaviour2": "앞에 있는 원목을 자릅니다. 나무의 원목이라면, 나무가 쓰러지면서 아이템을 떨굽니다.", + "block.create.saw.tooltip.condition3": "움직일 때", + "block.create.saw.tooltip.behaviour3": "톱이 만나는 모든 나무를 벱니다.", + + "block.create.stockswitch.tooltip": "STOCKSWITCH", + "block.create.stockswitch.tooltip.summary": "붙어있는 _저장소_에 _여유_ _공간_을 기반으로 레드스톤 신호를 보냅니다.", + "block.create.stockswitch.tooltip.condition1": "_최소_ _경계_보다 낮을 경우", + "block.create.stockswitch.tooltip.behaviour1": "레드스톤 신호를 보내지 않습니다.", + "block.create.stockswitch.tooltip.condition2": "_최초_ _경계_보다 높을 경우", + "block.create.stockswitch.tooltip.behaviour2": "최소 경계에 다시 도달할 때까지 레드스톤 신호를 보냅니다.", + "block.create.stockswitch.tooltip.control1": "우클릭했을 때", + "block.create.stockswitch.tooltip.action1": "설정 창을 엽니다.", + + "block.create.redstone_bridge.tooltip": "REDSTONE LINK", + "block.create.redstone_bridge.tooltip.summary": "_무선_ 레드스톤 단말기입니다. 아무 아이템으로 두 개의 _주파수_를 설정할 수 있습니다. 통신거리는 제한되어 있지만, 그래도 충분히 넓습니다.", + "block.create.redstone_bridge.tooltip.condition1": "신호를 줄 때", + "block.create.redstone_bridge.tooltip.behaviour1": "같은 주파주의 다른 단말기에서 레드스톤 신호를 받습니다.", + "block.create.redstone_bridge.tooltip.control1": "아이템을 들고 우클릭", + "block.create.redstone_bridge.tooltip.action1": "그 아이템으로 주파수를 설정합니다. 주파수는 최대 두가지 아이템 조합으로 이룰 수 있습니다.", + "block.create.redstone_bridge.tooltip.control2": "웅크린 상태에서 우클릭", + "block.create.redstone_bridge.tooltip.action2": "수신/발신 모드로 바꿉니다.", + + "block.create.contact.tooltip": "REDSTONE CONTACT", + "block.create.contact.tooltip.summary": "_한_ _쌍_이 _서로_ _바라보고_ 있을 때 레드스톤 신호를 보냅니다. 베어링이나 기계식 피스톤으로 움직여집니다.", + "block.create.contact.tooltip.condition1": "다른 동형 감지기를 맞댈 때", + "block.create.contact.tooltip.behaviour1": "레드스톤 신호를 보냅니다.", + "block.create.contact.tooltip.condition2": "움직일 때", + "block.create.contact.tooltip.behaviour2": "지나가는 모든 고정된 동형 감지기를 작동시킵니다.", + + "block.create.flexcrate.tooltip": "ADJUSTABLE CRATE", + "block.create.flexcrate.tooltip.summary": "이 저장소는 용량을 _직접_ _정할_ 수 있습니다. 아무아이템이나 최대 16스택씩 담을 수 있습니다. 레드스톤 비교기와 호환됩니다.", + "block.create.flexcrate.tooltip.control1": "우클릭 했을 때", + "block.create.flexcrate.tooltip.action1": "창을 엽니다.", + + "block.create.extractor.tooltip": "EXTRACTOR", + "block.create.extractor.tooltip.summary": "_연결된_ _인벤토리_로부터 아이템을 꺼내 땅에 떨어뜨립니다. 공간이 비지 않았다면 아이템을 떨어뜨리지 않습니다. 개수/필터를 설정 가능합니다.", + "block.create.extractor.tooltip.condition1": "레드스톤 신호를 받았을 때", + "block.create.extractor.tooltip.behaviour1": "추출기를 _멈춥니다_.", + "block.create.extractor.tooltip.condition2": "움직이는 벨트에 연결되었을 때", + "block.create.extractor.tooltip.behaviour2": "추출기는 _황동_ _케이스_가 장착된 _벨트_에서 아이템을 빼낼 수 있습니다. 추출기가 막혔을 때는, 벨트가 _멈춥니다_.", + "block.create.extractor.tooltip.control1": "필터 슬롯을 우클릭할 때", + "block.create.extractor.tooltip.action1": "현재 들고있는 아이템의 개수 혹은 필터 틀로 필터를 정합니다. 추출기는 필터 설정에 맞춰 아이템을 빼낼 것입니다.", + + "block.create.transposer.tooltip": "TRANSPOSER", + "block.create.transposer.tooltip.summary": "연결된 인벤토리로부터 대상 인벤토리로 아이템을 _바로_ _이동_시킵니다. 개수/필터를 설정 가능합니다.", + "block.create.transposer.tooltip.condition1": "레드스톤 신호를 받았을 때", + "block.create.transposer.tooltip.behaviour1": "트랜스포저를 _멈춥니다_.", + "block.create.transposer.tooltip.condition2": "움직이는 벨트에 연결되었을 때", + "block.create.transposer.tooltip.behaviour2": "트랜스포저는 _황동_ _케이스_가 장착된 _벨트_에서 아이템을 빼낼 수 있습니다. 추출기가 막혔을 때는, 벨트가 _멈춥니다_.", + "block.create.transposer.tooltip.control1": "필터 슬롯을 우클릭할 때", + "block.create.transposer.tooltip.action1": "현재 들고있는 아이템의 개수 혹은 필터 틀로 필터를 정합니다. 트랜스포저는 필터 설정에 맞춰 아이템을 빼낼 것입니다.", + + "block.create.deployer.tooltip": "DEPLOYER", + "block.create.deployer.tooltip.summary": " _때리고_, _사용하고_ _작동시킵니다_. 이 장치는 _플레이어_를 가능한 한 _흉내내려할_ _것입니다_. 주변 인벤토리에서 아이템을 쓰거나 넣을 수 있습니다. 필터로 사용하는 아이템을 설정할 수 있습니다.", + "block.create.deployer.tooltip.condition1": "회전될 때", + "block.create.deployer.tooltip.behaviour1": "팔을 늘려 한 칸앞에 있는 공간에서 행동합니다.", + "block.create.deployer.tooltip.condition2": "렌치로 우클릭", + "block.create.deployer.tooltip.behaviour2": "_펀치_ _모드_로 바꿉니다. 이 상태에서는 배포기가 아이템을 가지고 _부수거나_ _때리려고_ 할 것입니다.", + + "block.create.linked_extractor.tooltip": "LINKED EXTRACTOR", + "block.create.linked_extractor.tooltip.summary": "_연결된_ _인벤토리_로부터 아이템을 꺼내 땅에 떨어뜨립니다. 공간이 비지 않았다면 아이템을 떨어뜨리지 않습니다. 개수/필터를 설정 가능합니다. 레드스톤 링크를 통해 _무선으로_ 컨트롤 될 수 있습니다.", + "block.create.linked_extractor.tooltip.condition1": "레드스톤 링크 신호를 받았을 때", + "block.create.linked_extractor.tooltip.behaviour1": "추출기를 _멈춥니다_.", + "block.create.linked_extractor.tooltip.control1": "필터 슬롯을 우클릭할 때", + "block.create.linked_extractor.tooltip.action1": "현재 들고있는 아이템의 개수 혹은 필터 틀로 필터를 정합니다. 추출기는 필터 설정에 맞춰 아이템을 빼낼 것입니다.", + "block.create.linked_extractor.tooltip.control2": "아이템을 들고 주파수 슬롯을 우클릭", + "block.create.linked_extractor.tooltip.action2": "그 아이템으로 주파수를 설정합니다. _같은_ _주파수_의 레드스톤 링크가 신호를 보낸다면, 추출기는 멈출 것입니다.", + + "block.create.linked_transposer.tooltip": "LINKED TRANSPOSER", + "block.create.linked_transposer.tooltip.summary": "연결된 인벤토리로부터 대상 인벤토리로 아이템을 _바로_ _이동_시킵니다. 개수/필터를 설정 가능합니다. 레드스톤 링크를 통해 _무선으로_ 컨트롤 될 수 있습니다.", + "block.create.linked_transposer.tooltip.condition1": "레드스톤 링크 신호를 받았을 때", + "block.create.linked_transposer.tooltip.behaviour1": "트랜스포저를 _멈춥니다_.", + "block.create.linked_transposer.tooltip.control1": "필터 슬롯을 우클릭할 때", + "block.create.linked_transposer.tooltip.action1": "현재 들고있는 아이템의 개수 혹은 필터 틀로 필터를 정합니다. 트랜스포저는 필터 설정에 맞춰 아이템을 빼낼 것입니다.", + "block.create.linked_transposer.tooltip.control2": "아이템을 들고 주파수 슬롯을 우클릭", + "block.create.linked_transposer.tooltip.action2": "그 아이템으로 주파수를 설정합니다. _같은_ _주파수_의 레드스톤 링크가 신호를 보낸다면, 트랜스포저는 멈출 것입니다.", + + "block.create.belt_funnel.tooltip": "FUNNEL", + "block.create.belt_funnel.tooltip.summary": "들어오는 아이템을 가능하면 _연결된_ _인벤토리_에 넣습니다. _벨트_ _위_의 아이템도 끌어올 수 있습니다.", + "block.create.belt_funnel.tooltip.condition1": "움직이는 벨트위에 있을 때", + "block.create.belt_funnel.tooltip.behaviour1": "_벨트_의 _중간_, _끝부분_에서 아이템을 끌어올 수 있습니다. 중간에 설치된 깔때기가 _정체_되었을 땐, 벨트가 _멈춥니다_.", + + "block.create.belt_tunnel.tooltip": "BELT TUNNEL", + "block.create.belt_tunnel.tooltip.summary": "벽을 통과하는 컨베이어 벨트를 _꾸미는_ 옵션 중 하나입니다. 벨트는 _황동_ _케이스_가 장착되어 있어야합니다. 터널은 다른 벨트 라인의 터널과 _동기화_되어 모든 터널이 _같은_ _타이밍_에 아이템을 들어오게 만들 수 있습니다. [Ctrl를 누르세요]", + "block.create.belt_tunnel.tooltip.control1": "전면에 렌치로 우클릭", + "block.create.belt_tunnel.tooltip.action1": "동기화 모드를 킵니다. 동기화된 터널은 다른 동기화된 터널들이 아이템을 인식할 때까지 아이템을 통과시키지 않습니다.", + "block.create.belt_tunnel.tooltip.control2": "륵면을 우클릭", + "block.create.belt_tunnel.tooltip.action2": "터널 측면에 창문이 있다면 창문 셔터를 조절합니다.", + + "block.create.brass_casing.tooltip": "BRASS CASING", + "block.create.brass_casing.tooltip.summary": "다양한 용도가 있는 단단한 기계 케이스입니다. 꾸미는 용도로도 사용 가능합니다.", + "block.create.brass_casing.tooltip.condition1": "컨베이어 벨트에 사용할 때", + "block.create.brass_casing.tooltip.behaviour1": "벨트 밑 부분에 황동 케이스를 씌웁니다. 이 상태에선 _벨트_ _터널_, _추출기_, _깔대기_, _트랜스포저_를 벨트 _측면_, _바닥면_에 연결할 수 있습니다.", + + "block.create.entity_detector.tooltip": "BELT OBSERVER", + "block.create.entity_detector.tooltip.summary": "컨베이어 벨트위를 _지나가는_ _엔티티_나 _아이템_을 감지합니다. 렌치를 이용해 _감지시_ _행동_을 바꿉니다. 필터를 설정할 수 있습니다.", + "block.create.entity_detector.tooltip.condition1": "감지 모드", + "block.create.entity_detector.tooltip.behaviour1": "감지기 앞에 아이템이 _지나가는_ _동안_ 레드스톤 신호를 줍니다.", + "block.create.entity_detector.tooltip.condition2": "펄스 모드", + "block.create.entity_detector.tooltip.behaviour2": "감지기 앞에 아이템이 _지나갈_ _때_ 레드스톤 신호를 _1틱_ 줍니다.", + "block.create.entity_detector.tooltip.condition3": "사출 모드", + "block.create.entity_detector.tooltip.behaviour3": "옆으로 아이템을 _밀어냅니다_. 벨트나 밀어내는 공간이 _정체_되어 있다면, 아이템은 감지기 앞에서 _멈춥니다_.", + "block.create.entity_detector.tooltip.condition4": "분리 모드", + "block.create.entity_detector.tooltip.behaviour4": "아이템의 _수_를 _반으로_ _나누어_ 반은 벨트 옆으로 내보냅니다.", + + "block.create.pulse_repeater.tooltip": "PULSE REPEATER", + "block.create.pulse_repeater.tooltip.summary": "_1틱_의 레드스톤 신호를 보내는 간단한 리피터입니다.", + + "block.create.flexpeater.tooltip": "FLEX REPEATER", + "block.create.flexpeater.tooltip.summary": "최대 30분까지 _딜레이_를 설정할 수 있는 업그레이드된 _레드스톤_ _리피터_입니다.", + + "block.create.flexpulsepeater.tooltip": "FLEX PULSE REPEATER", + "block.create.flexpulsepeater.tooltip.summary": "최대 30분까지 _딜레이_를 설정할 수 있는 _펄스_ _리피터_입니다.", + + "block.create.analog_lever.tooltip": "ANALOG LEVER", + "block.create.analog_lever.tooltip.summary": "레드스톤 _신호_ _세기_를 자세히 _조정_할 수 있는 레버입니다.", + + "block.create.toggle_latch.tooltip": "POWERED TOGGLE LATCH", + "block.create.toggle_latch.tooltip.summary": "레드스톤 신호로 끄고 켤 수 있는 _레버_입니다.", + + "block.create.redstone_latch.tooltip": "POWERED LATCH", + "block.create.redstone_latch.tooltip.summary": "레드스톤 신호로 컨트롤 할 수 있는 _레버_입니다. 후면에서 들어오는 신호는 레버를 키고, 측면에서 들어오는 신호는 레버를 초기화합니다.", + + "block.create.speed_gauge.tooltip": "SPEEDOMETER", + "block.create.speed_gauge.tooltip.summary": "연결된 장치의 _회전_ _속도_를 _계측_하고 _나타냅니다_. 레드스톤 비교기와 호환됩니다.", + "block.create.speed_gauge.tooltip.condition1": "회전될 때", + "block.create.speed_gauge.tooltip.behaviour1": "속도에 따라 색깔을 나타냅니다. _초록색_은 _느림_을, _파랑색_은 _보통_, _보라색_은 _빠른_ _속도_를 나타냅니다. 몇몇 장치들은 작동하기 위해 일정수준 이상의 속도가 필요합니다.", + + "block.create.stress_gauge.tooltip": "STRESSOMETER", + "block.create.stress_gauge.tooltip.summary": "연결된 네트워크의 _전체_ _피로도_ _수치_를 _계측_하고 _나타냅니다_. 레드스톤 비교기와 호환됩니다.", + "block.create.stress_gauge.tooltip.condition1": "회전될 때", + "block.create.stress_gauge.tooltip.behaviour1": "피로도에 따라 색깔을 나타냅니다. _과부화된_ _네트워크_는 움직이는 것을 멈춥니다. 과부하는 네트워크에 _추가_ _피로도_ _용량_을 가진 장치를 설치하면 해결됩니다. ", + + "tool.create.sand_paper.tooltip": "SAND PAPER", + "tool.create.sand_paper.tooltip.summary": "재료를 _사포질_ 하기위한 거친 종이입니다. 배포기를 통해 자동으로 쓰일 수 있습니다.", + "tool.create.sand_paper.tooltip.condition1": "사용할 때", + "tool.create.sand_paper.tooltip.behaviour1": "_반대_ _손_에 있는, 혹은 _바닥에_ _있는_ 아이템을 사포질 합니다.", + + "item.create.refined_radiance.tooltip": "REFINED RADIANCE", + "item.create.refined_radiance.tooltip.summary": "_흡수된_ _빛_으로 제련된 색채 혼합물입니다.", + + "item.create.shadow_steel.tooltip": "SHADOW STEEL", + "item.create.shadow_steel.tooltip.summary": "_공허_에서 제련된 색채 혼합물입니다.", + + "item.create.slot_cover.tooltip": "SLOT COVER", + "item.create.slot_cover.tooltip.summary": "기계 조합기에서 _빈_ _슬롯_을 표시하기 위해 쓰입니다. 조합기들은 정사각형 모양을 형성할 필요는 없습니다. 재료가 서로 대각선인 조합법이있을 때 유용합니다.", + + "tool.create.shadow_steel.tooltip": "SHADOW STEEL TOOLS", + "tool.create.shadow_steel.tooltip.summary": "블럭, 엔티티에서 나오는 아이템을 _없애버리는_ 빠르고 강력한 도구입니다. _약탈_ 마법부여에 따라 몬스터은 _더_ _많은_ _경험치_를 줍니다.", + + "tool.create.blazing.tooltip": "BLAZING TOOLS", + "tool.create.blazing.tooltip.summary": "이 도구는 블럭을 _녹이고_ 몬스터에게 _불_을 붙입니다. _지옥_에서는 내구도가 닳지 않습니다.", + + "tool.create.rose_quartz.tooltip": "ROSE QUARTZ TOOLS", + "tool.create.rose_quartz.tooltip.summary": "이 도구를 사용하면 _도구의_ _사거리_와 _다른_ _손_ _사거리_가 증가합니다.", + + "itemGroup.create": "Create" +} diff --git a/src/main/resources/assets/create/lang/nl_nl.json b/src/main/resources/assets/create/lang/nl_nl.json index bd273ed69..dfb4d2ba7 100644 --- a/src/main/resources/assets/create/lang/nl_nl.json +++ b/src/main/resources/assets/create/lang/nl_nl.json @@ -191,16 +191,16 @@ "create.recipe.crushing": "Verpulveren", "create.recipe.splashing": "Bulk Wassen", "create.recipe.splashing.fan": "Ventilator achter vloeiend water", - "create.recipe.smokingViaFan": "Bulk Rook", - "create.recipe.smokingViaFan.fan": "Ventilator achter vuur", - "create.recipe.blastingViaFan": "Bulk Smelten", - "create.recipe.blastingViaFan.fan": "\"Ventilator achter Lava", + "create.recipe.smoking_via_fan": "Bulk Rook", + "create.recipe.smoking_via_fan.fan": "Ventilator achter vuur", + "create.recipe.blasting_via_fan": "Bulk Smelten", + "create.recipe.blasting_via_fan.fan": "\"Ventilator achter Lava", "create.recipe.pressing": "Persen", "create.recipe.mixing": "Mengen", "create.recipe.packing": "Compressen", "create.recipe.sawing": "Zagen", "create.recipe.block_cutting": "Blok Zagen", - "create.recipe.blockzapperUpgrade": "Blokzapper", + "create.recipe.blockzapper_upgrade": "Blokzapper", "create.recipe.processing.chance": "%1$s%% Kans", "create.generic.range": "Omvang", diff --git a/src/main/resources/assets/create/lang/pt_br.json b/src/main/resources/assets/create/lang/pt_br.json index 5363b7d59..e653e8d55 100644 --- a/src/main/resources/assets/create/lang/pt_br.json +++ b/src/main/resources/assets/create/lang/pt_br.json @@ -153,12 +153,12 @@ "create.recipe.crushing": "Moendo", "create.recipe.splashing": "Lavando em Massa", "create.recipe.splashing.fan": "Ventilador atras de Água corrente", - "create.recipe.smokingViaFan": "Fumaceando em Massa", - "create.recipe.smokingViaFan.fan": "Ventilador atras de Fogo", - "create.recipe.blastingViaFan": "Fundindo em Massa", - "create.recipe.blastingViaFan.fan": "Ventilador atras de Lava", + "create.recipe.smoking_via_fan": "Fumaceando em Massa", + "create.recipe.smoking_via_fan.fan": "Ventilador atras de Fogo", + "create.recipe.blasting_via_fan": "Fundindo em Massa", + "create.recipe.blasting_via_fan.fan": "Ventilador atras de Lava", "create.recipe.pressing": "Prensa Mecânica", - "create.recipe.blockzapperUpgrade": "Blockzapper Portátil", + "create.recipe.blockzapper_upgrade": "Blockzapper Portátil", "create.recipe.processing.chance": "%1$s%% de chance", "create.generic.range": "Área", diff --git a/src/main/resources/assets/create/lang/ru_ru.json b/src/main/resources/assets/create/lang/ru_ru.json index e53bf1079..19956c7ee 100644 --- a/src/main/resources/assets/create/lang/ru_ru.json +++ b/src/main/resources/assets/create/lang/ru_ru.json @@ -153,12 +153,12 @@ "create.recipe.crushing": "Дробление", "create.recipe.splashing": "Промывка вентилятором", "create.recipe.splashing.fan": "Вентилятор за проточной водой", - "create.recipe.smokingViaFan": "Копчение вентилятором", - "create.recipe.smokingViaFan.fan": "Вентилятор за огнём", - "create.recipe.blastingViaFan": "Плавление вентилятором", - "create.recipe.blastingViaFan.fan": "Вентелятор за лавой", + "create.recipe.smoking_via_fan": "Копчение вентилятором", + "create.recipe.smoking_via_fan.fan": "Вентилятор за огнём", + "create.recipe.blasting_via_fan": "Плавление вентилятором", + "create.recipe.blasting_via_fan.fan": "Вентелятор за лавой", "create.recipe.pressing": "Механический пресс", - "create.recipe.blockzapperUpgrade": "Портативный размещатель блоков", + "create.recipe.blockzapper_upgrade": "Портативный размещатель блоков", "create.recipe.processing.chance": "%1$s%% шанс выпадения", "create.generic.range": "Зона", diff --git a/src/main/resources/assets/create/lang/zh_cn.json b/src/main/resources/assets/create/lang/zh_cn.json index 73f4e0293..9815ec263 100644 --- a/src/main/resources/assets/create/lang/zh_cn.json +++ b/src/main/resources/assets/create/lang/zh_cn.json @@ -6,12 +6,12 @@ "item.create.placement_handgun": "手持式方块放置器", "item.create.terrain_zapper": "手持式环境塑形器", "item.create.tree_fertilizer": "树木肥料", - "item.create.empty_blueprint": "空白原理图", - "item.create.andesite_alloy": "安山合金", + "item.create.empty_blueprint": "空白蓝图", + "item.create.andesite_alloy": "安山岩合金", "item.create.chromatic_compound": "谜之化合物", "item.create.shadow_steel": "暗影金属", - "item.create.blueprint_and_quill": "原理图与笔", - "item.create.blueprint": "原理图", + "item.create.blueprint_and_quill": "蓝图与笔", + "item.create.blueprint": "蓝图", "item.create.belt_connector": "传送带", "item.create.goggles": "工程师护目镜", "item.create.filter": "过滤器", @@ -79,9 +79,9 @@ "block.create.copper_shingles": "铜瓦堆", "block.create.zinc_ore": "锌矿", - "block.create.andesite_casing": "安山箱", - "block.create.brass_casing": "黄铜箱", - "block.create.copper_casing": "铜箱", + "block.create.andesite_casing": "安山套管", + "block.create.brass_casing": "黄铜套管", + "block.create.copper_casing": "铜套管", "block.create.cogwheel": "齿轮", "block.create.large_cogwheel": "大齿轮", @@ -100,7 +100,7 @@ "block.create.creative_motor": "动力马达", "block.create.belt": "传送带", "block.create.crushing_wheel": "粉碎轮", - "block.create.drill": "动力钻头", + "block.create.drill": "钻头", "block.create.portable_storage_interface": "移动式储物接口", "block.create.harvester": "收割机", "block.create.saw": "切割机", @@ -109,7 +109,7 @@ "block.create.mechanical_mixer": "搅拌器", "block.create.deployer": "机械手", "block.create.basin": "工作盆", - "block.create.mechanical_crafter": "机械制造机", + "block.create.mechanical_crafter": "机械制造台", "block.create.flywheel": "飞轮", "block.create.furnace_engine": "熔炉引擎", "block.create.speed_gauge": "速度表", @@ -120,13 +120,13 @@ "block.create.sticky_mechanical_piston": "粘性动力活塞", "block.create.mechanical_piston": "动力活塞", - "block.create.mechanical_piston_head": "Mechanical Piston Head", + "block.create.mechanical_piston_head": "动力活塞头", "block.create.piston_pole": "活塞杆", "block.create.mechanical_bearing": "动力轴承", "block.create.clockwork_bearing": "时钟轴承", "block.create.rope_pulley": "绳索滑轮", - "block.create.rope": "Rope", - "block.create.pulley_magnet": "Pulley Magnet", + "block.create.rope": "绳子", + "block.create.pulley_magnet": "滑轮磁铁", "block.create.translation_chassis": "机壳底盘", "block.create.rotation_chassis": "旋转底盘", @@ -145,7 +145,7 @@ "block.create.toggle_latch": "T触发器", "block.create.flexpeater": "高级中继器", "block.create.entity_detector": "传送带观察者", - "block.create.logistical_casing": "Logistical Casing", + "block.create.logistical_casing": "Logistical 套管", "block.create.logistical_controller": "Logistical Controller", "block.create.logistical_index": "Logistical Index", "block.create.logisticians_table": "Logistician's Table", @@ -283,17 +283,17 @@ "create.recipe.crushing": "批量粉碎", "create.recipe.splashing": "批量洗涤", "create.recipe.splashing.fan": "在鼓风机前方倒水", - "create.recipe.smokingViaFan": "批量烟熏", - "create.recipe.smokingViaFan.fan": "在鼓风机前方点火", - "create.recipe.blastingViaFan": "批量冶炼", - "create.recipe.blastingViaFan.fan": "在鼓风机前方倒岩浆", + "create.recipe.smoking_via_fan": "批量烟熏", + "create.recipe.smoking_via_fan.fan": "在鼓风机前方点火", + "create.recipe.blasting_via_fan": "批量冶炼", + "create.recipe.blasting_via_fan.fan": "在鼓风机前方倒岩浆", "create.recipe.pressing": "金属压片", "create.recipe.mixing": "混合搅拌", "create.recipe.packing": "压块塑形", "create.recipe.sawing": "木材切割", "create.recipe.mechanical_crafting": "自动合成", "create.recipe.block_cutting": "方块切割", - "create.recipe.blockzapperUpgrade": "手持式方块放置器", + "create.recipe.blockzapper_upgrade": "手持式方块放置器", "create.recipe.sandpaper_polishing": "砂纸抛光", "create.recipe.mystery_conversion": "化合物变异", "create.recipe.processing.catalyst": "催化剂", @@ -308,8 +308,8 @@ "create.generic.speed": "速度", "create.generic.delay": "延时", "create.generic.unit.ticks": "Ticks", - "create.generic.unit.seconds": "Seconds", - "create.generic.unit.minutes": "Minutes", + "create.generic.unit.seconds": "秒", + "create.generic.unit.minutes": "分钟", "create.generic.unit.rpm": "RPM", "create.generic.unit.stress": "su", "create.generic.unit.degrees": "°", @@ -1170,4 +1170,4 @@ "item.create.logistical_filter.tooltip": "WIP", "itemGroup.create": "机械动力" -} \ No newline at end of file +} diff --git a/src/main/resources/assets/create/models/block/plough.json b/src/main/resources/assets/create/models/block/plough.json new file mode 100644 index 000000000..9c678684d --- /dev/null +++ b/src/main/resources/assets/create/models/block/plough.json @@ -0,0 +1,113 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "1": "block/anvil", + "particle": "create:block/andesite_casing_short", + "andesite_casing_short": "create:block/andesite_casing_short" + }, + "elements": [ + { + "name": "Core", + "from": [0, 2, 0], + "to": [16, 14, 2.9], + "faces": { + "north": {"uv": [0, 4, 16, 16], "texture": "#andesite_casing_short"}, + "east": {"uv": [2, 0, 14, 3], "rotation": 270, "texture": "#andesite_casing_short"}, + "south": {"uv": [0, 4, 16, 16], "texture": "#andesite_casing_short"}, + "west": {"uv": [2, 0, 14, 3], "rotation": 90, "texture": "#andesite_casing_short"}, + "up": {"uv": [0, 0, 16, 2.9], "rotation": 180, "texture": "#andesite_casing_short"}, + "down": {"uv": [0, 0, 16, 2.9], "texture": "#andesite_casing_short"} + } + }, + { + "name": "Attachment", + "from": [0.1, 4, 6], + "to": [2, 7, 15], + "rotation": {"angle": 22.5, "axis": "x", "origin": [0, 10, 3]}, + "faces": { + "north": {"uv": [0, 0, 1.9, 3], "texture": "#andesite_casing_short"}, + "east": {"uv": [0, 0, 9, 3], "texture": "#andesite_casing_short"}, + "south": {"uv": [0.1, 8, 2, 11], "texture": "#andesite_casing_short"}, + "west": {"uv": [0, 0, 9, 3], "texture": "#andesite_casing_short"}, + "up": {"uv": [0, 4, 1.9, 13], "texture": "#andesite_casing_short"}, + "down": {"uv": [0, 4, 1.9, 13], "texture": "#andesite_casing_short"} + } + }, + { + "name": "Attachment", + "from": [2.1, 5, 5], + "to": [14, 6, 17], + "rotation": {"angle": 22.5, "axis": "x", "origin": [0, 10, 3]}, + "faces": { + "north": {"uv": [0, 0, 11.9, 1], "texture": "#andesite_casing_short"}, + "east": {"uv": [0, 0, 12, 1], "texture": "#1"}, + "south": {"uv": [2, 15, 13.9, 16], "texture": "#1"}, + "west": {"uv": [0, 0, 12, 1], "texture": "#1"}, + "up": {"uv": [2, 2, 13.9, 14], "texture": "#1"}, + "down": {"uv": [2, 4, 13.9, 16], "texture": "#1"} + } + }, + { + "name": "Attachment", + "from": [14, 4, 6], + "to": [15.9, 7, 15], + "rotation": {"angle": 22.5, "axis": "x", "origin": [0, 10, 3]}, + "faces": { + "north": {"uv": [0, 0, 1.9, 3], "texture": "#andesite_casing_short"}, + "east": {"uv": [0, 0, 9, 3], "texture": "#andesite_casing_short"}, + "south": {"uv": [14, 8, 15.9, 11], "texture": "#andesite_casing_short"}, + "west": {"uv": [0, 0, 9, 3], "texture": "#andesite_casing_short"}, + "up": {"uv": [14, 4, 15.9, 13], "texture": "#andesite_casing_short"}, + "down": {"uv": [14, 4, 15.9, 13], "texture": "#andesite_casing_short"} + } + }, + { + "name": "Attachment", + "from": [0, 4, 2.9], + "to": [16, 7, 6], + "rotation": {"angle": 0, "axis": "x", "origin": [0, 10, 2]}, + "faces": { + "north": {"uv": [0, 0, 16, 3], "texture": "#andesite_casing_short"}, + "east": {"uv": [0, 0, 3.1, 3], "texture": "#andesite_casing_short"}, + "south": {"uv": [0, 0, 16, 3], "texture": "#andesite_casing_short"}, + "west": {"uv": [0, 0, 3.1, 3], "texture": "#andesite_casing_short"}, + "up": {"uv": [0, 0, 16, 3], "rotation": 180, "texture": "#andesite_casing_short"}, + "down": {"uv": [0, 0, 16, 3], "texture": "#andesite_casing_short"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, -135, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, -135, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 225, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 45, 0], + "translation": [1, 0, 0], + "scale": [0.625, 0.625, 0.625] + }, + "fixed": { + "rotation": [0, 180, 0], + "translation": [0, 0, -4], + "scale": [0.5, 0.5, 0.5] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/antioxidant.json b/src/main/resources/assets/create/models/item/antioxidant.json new file mode 100644 index 000000000..3bcae42ef --- /dev/null +++ b/src/main/resources/assets/create/models/item/antioxidant.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "create:item/antioxidant" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/furnace_minecart_contraption.json b/src/main/resources/assets/create/models/item/furnace_minecart_contraption.json new file mode 100644 index 000000000..73fb1ceca --- /dev/null +++ b/src/main/resources/assets/create/models/item/furnace_minecart_contraption.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "create:item/minecart_contraption" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/minecart_contraption.json b/src/main/resources/assets/create/models/item/minecart_contraption.json new file mode 100644 index 000000000..73fb1ceca --- /dev/null +++ b/src/main/resources/assets/create/models/item/minecart_contraption.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "create:item/minecart_contraption" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/plough.json b/src/main/resources/assets/create/models/item/plough.json new file mode 100644 index 000000000..241430659 --- /dev/null +++ b/src/main/resources/assets/create/models/item/plough.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/plough" +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/super_glue.json b/src/main/resources/assets/create/models/item/super_glue.json new file mode 100644 index 000000000..811b54649 --- /dev/null +++ b/src/main/resources/assets/create/models/item/super_glue.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "create:item/super_glue" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/oxidized/copper_block_0.png b/src/main/resources/assets/create/textures/block/oxidized/copper_block_0.png index 199f5c9f3..8488751f7 100644 Binary files a/src/main/resources/assets/create/textures/block/oxidized/copper_block_0.png and b/src/main/resources/assets/create/textures/block/oxidized/copper_block_0.png differ diff --git a/src/main/resources/assets/create/textures/block/oxidized/copper_block_1.png b/src/main/resources/assets/create/textures/block/oxidized/copper_block_1.png index 9cf60d49d..5edf2e8aa 100644 Binary files a/src/main/resources/assets/create/textures/block/oxidized/copper_block_1.png and b/src/main/resources/assets/create/textures/block/oxidized/copper_block_1.png differ diff --git a/src/main/resources/assets/create/textures/block/oxidized/copper_block_2.png b/src/main/resources/assets/create/textures/block/oxidized/copper_block_2.png index 53393dfc8..f2be5bd4f 100644 Binary files a/src/main/resources/assets/create/textures/block/oxidized/copper_block_2.png and b/src/main/resources/assets/create/textures/block/oxidized/copper_block_2.png differ diff --git a/src/main/resources/assets/create/textures/block/oxidized/copper_block_3.png b/src/main/resources/assets/create/textures/block/oxidized/copper_block_3.png index deff9d131..26dee4532 100644 Binary files a/src/main/resources/assets/create/textures/block/oxidized/copper_block_3.png and b/src/main/resources/assets/create/textures/block/oxidized/copper_block_3.png differ diff --git a/src/main/resources/assets/create/textures/block/oxidized/copper_block_4.png b/src/main/resources/assets/create/textures/block/oxidized/copper_block_4.png index 6f7ee0aae..39c727abb 100644 Binary files a/src/main/resources/assets/create/textures/block/oxidized/copper_block_4.png and b/src/main/resources/assets/create/textures/block/oxidized/copper_block_4.png differ diff --git a/src/main/resources/assets/create/textures/block/oxidized/copper_block_5.png b/src/main/resources/assets/create/textures/block/oxidized/copper_block_5.png index 8a51065cd..349cd141a 100644 Binary files a/src/main/resources/assets/create/textures/block/oxidized/copper_block_5.png and b/src/main/resources/assets/create/textures/block/oxidized/copper_block_5.png differ diff --git a/src/main/resources/assets/create/textures/block/oxidized/copper_block_6.png b/src/main/resources/assets/create/textures/block/oxidized/copper_block_6.png index 93f43dcda..48c2f7e45 100644 Binary files a/src/main/resources/assets/create/textures/block/oxidized/copper_block_6.png and b/src/main/resources/assets/create/textures/block/oxidized/copper_block_6.png differ diff --git a/src/main/resources/assets/create/textures/block/oxidized/copper_block_7.png b/src/main/resources/assets/create/textures/block/oxidized/copper_block_7.png index 8583fdc59..7b5b9643b 100644 Binary files a/src/main/resources/assets/create/textures/block/oxidized/copper_block_7.png and b/src/main/resources/assets/create/textures/block/oxidized/copper_block_7.png differ diff --git a/src/main/resources/assets/create/textures/entity/super_glue/ghostly.png b/src/main/resources/assets/create/textures/entity/super_glue/ghostly.png new file mode 100644 index 000000000..8a2efeeca Binary files /dev/null and b/src/main/resources/assets/create/textures/entity/super_glue/ghostly.png differ diff --git a/src/main/resources/assets/create/textures/entity/super_glue/slime.png b/src/main/resources/assets/create/textures/entity/super_glue/slime.png new file mode 100644 index 000000000..affbf87bc Binary files /dev/null and b/src/main/resources/assets/create/textures/entity/super_glue/slime.png differ diff --git a/src/main/resources/assets/create/textures/gui/background.png b/src/main/resources/assets/create/textures/gui/background.png index de5cde99c..e51ac3189 100644 Binary files a/src/main/resources/assets/create/textures/gui/background.png and b/src/main/resources/assets/create/textures/gui/background.png differ diff --git a/src/main/resources/assets/create/textures/gui/icons.png b/src/main/resources/assets/create/textures/gui/icons.png index 0b0183a2e..06aa1ce24 100644 Binary files a/src/main/resources/assets/create/textures/gui/icons.png and b/src/main/resources/assets/create/textures/gui/icons.png differ diff --git a/src/main/resources/assets/create/textures/gui/jei/widgets.png b/src/main/resources/assets/create/textures/gui/jei/widgets.png index fbcae5b4a..362c54398 100644 Binary files a/src/main/resources/assets/create/textures/gui/jei/widgets.png and b/src/main/resources/assets/create/textures/gui/jei/widgets.png differ diff --git a/src/main/resources/assets/create/textures/gui/widgets.png b/src/main/resources/assets/create/textures/gui/widgets.png index 8ae74f83d..335460ca9 100644 Binary files a/src/main/resources/assets/create/textures/gui/widgets.png and b/src/main/resources/assets/create/textures/gui/widgets.png differ diff --git a/src/main/resources/assets/create/textures/item/antioxidant.png b/src/main/resources/assets/create/textures/item/antioxidant.png new file mode 100644 index 000000000..67ad63c34 Binary files /dev/null and b/src/main/resources/assets/create/textures/item/antioxidant.png differ diff --git a/src/main/resources/assets/create/textures/item/blueprint_and_quill.png b/src/main/resources/assets/create/textures/item/blueprint_and_quill.png index dd13e8166..dc2f06e0a 100644 Binary files a/src/main/resources/assets/create/textures/item/blueprint_and_quill.png and b/src/main/resources/assets/create/textures/item/blueprint_and_quill.png differ diff --git a/src/main/resources/assets/create/textures/item/blueprint_empty.png b/src/main/resources/assets/create/textures/item/blueprint_empty.png index 105eeaae3..cfcaebacf 100644 Binary files a/src/main/resources/assets/create/textures/item/blueprint_empty.png and b/src/main/resources/assets/create/textures/item/blueprint_empty.png differ diff --git a/src/main/resources/assets/create/textures/item/blueprint_filled.png b/src/main/resources/assets/create/textures/item/blueprint_filled.png index 8a3103d1e..584a0e263 100644 Binary files a/src/main/resources/assets/create/textures/item/blueprint_filled.png and b/src/main/resources/assets/create/textures/item/blueprint_filled.png differ diff --git a/src/main/resources/assets/create/textures/item/minecart_contraption.png b/src/main/resources/assets/create/textures/item/minecart_contraption.png new file mode 100644 index 000000000..747ff9058 Binary files /dev/null and b/src/main/resources/assets/create/textures/item/minecart_contraption.png differ diff --git a/src/main/resources/assets/create/textures/item/super_glue.png b/src/main/resources/assets/create/textures/item/super_glue.png new file mode 100644 index 000000000..b86066bd5 Binary files /dev/null and b/src/main/resources/assets/create/textures/item/super_glue.png differ diff --git a/src/main/resources/assets/create/textures/item/whisk.png b/src/main/resources/assets/create/textures/item/whisk.png index 78761e3b8..21942753f 100644 Binary files a/src/main/resources/assets/create/textures/item/whisk.png and b/src/main/resources/assets/create/textures/item/whisk.png differ diff --git a/src/main/resources/assets/create/textures/special/blank.png b/src/main/resources/assets/create/textures/special/blank.png new file mode 100644 index 000000000..58ef6694a Binary files /dev/null and b/src/main/resources/assets/create/textures/special/blank.png differ diff --git a/src/main/resources/assets/create/textures/special/checkerboard.png b/src/main/resources/assets/create/textures/special/checkerboard.png new file mode 100644 index 000000000..b087558be Binary files /dev/null and b/src/main/resources/assets/create/textures/special/checkerboard.png differ diff --git a/src/main/resources/assets/create/textures/special/highlighted_checkerboard.png b/src/main/resources/assets/create/textures/special/highlighted_checkerboard.png new file mode 100644 index 000000000..f6d7f2376 Binary files /dev/null and b/src/main/resources/assets/create/textures/special/highlighted_checkerboard.png differ diff --git a/src/main/resources/assets/create/textures/special/selection.png b/src/main/resources/assets/create/textures/special/selection.png index 7d5539cc7..4bdb5567e 100644 Binary files a/src/main/resources/assets/create/textures/special/selection.png and b/src/main/resources/assets/create/textures/special/selection.png differ diff --git a/src/main/resources/data/create/loot_tables/blocks/plough.json b/src/main/resources/data/create/loot_tables/blocks/plough.json new file mode 100644 index 000000000..3714a2487 --- /dev/null +++ b/src/main/resources/data/create/loot_tables/blocks/plough.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "create:plough" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/create/recipes/crafting_shaped/contraptions/plough.json b/src/main/resources/data/create/recipes/crafting_shaped/contraptions/plough.json new file mode 100644 index 000000000..9547e94b5 --- /dev/null +++ b/src/main/resources/data/create/recipes/crafting_shaped/contraptions/plough.json @@ -0,0 +1,29 @@ +{ + "type": "crafting_shaped", + "pattern": [ + "III", + "AAA", + " C " + ], + "key": { + "C": { + "item": "create:andesite_casing" + }, + "I": { + "tag": "forge:plates/iron" + }, + "A": { + "item": "create:andesite_alloy" + } + }, + "result": { + "item": "create:plough", + "count": 1 + }, + "conditions": [ + { + "type": "create:module", + "module": "contraptions" + } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/create/recipes/crafting_shaped/super_glue.json b/src/main/resources/data/create/recipes/crafting_shaped/super_glue.json new file mode 100644 index 000000000..423546fe3 --- /dev/null +++ b/src/main/resources/data/create/recipes/crafting_shaped/super_glue.json @@ -0,0 +1,22 @@ +{ + "type": "crafting_shaped", + "pattern": [ + "AS", + "NA" + ], + "key": { + "A": { + "tag": "forge:slimeballs" + }, + "S": { + "tag": "forge:plates/iron" + }, + "N": { + "tag": "forge:nuggets/iron" + } + }, + "result": { + "item": "create:super_glue", + "count": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/data/create/recipes/crafting_shapeless/minecart.json b/src/main/resources/data/create/recipes/crafting_shapeless/minecart.json new file mode 100644 index 000000000..38820a23b --- /dev/null +++ b/src/main/resources/data/create/recipes/crafting_shapeless/minecart.json @@ -0,0 +1,17 @@ +{ + "type": "crafting_shapeless", + "ingredients": [ + [ + { + "item": "create:minecart_contraption" + }, + { + "item": "create:furnace_minecart_contraption" + } + ] + ], + "result": { + "item": "minecraft:minecart", + "count": 1 + } +} \ No newline at end of file diff --git a/src/main/resources/data/create/recipes/crushing/glowstone.json b/src/main/resources/data/create/recipes/crushing/glowstone.json new file mode 100644 index 000000000..3aaadcf6c --- /dev/null +++ b/src/main/resources/data/create/recipes/crushing/glowstone.json @@ -0,0 +1,20 @@ +{ + "type": "create:crushing", + "ingredients": [ + { + "item": "minecraft:glowstone" + } + ], + "results": [ + { + "item": "minecraft:glowstone_dust", + "count": 3 + }, + { + "item": "minecraft:glowstone_dust", + "count": 1, + "chance": 0.5 + } + ], + "processingTime": 150 +} \ No newline at end of file diff --git a/src/main/resources/data/create/recipes/crushing/nether_wart_block.json b/src/main/resources/data/create/recipes/crushing/nether_wart_block.json new file mode 100644 index 000000000..e91740324 --- /dev/null +++ b/src/main/resources/data/create/recipes/crushing/nether_wart_block.json @@ -0,0 +1,20 @@ +{ + "type": "create:crushing", + "ingredients": [ + { + "item": "minecraft:nether_wart_block" + } + ], + "results": [ + { + "item": "minecraft:nether_wart", + "count": 6 + }, + { + "item": "minecraft:nether_wart", + "count": 2, + "chance": 0.5 + } + ], + "processingTime": 150 +} \ No newline at end of file