diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 86754b354..26ebed300 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -1,6 +1,8 @@ package com.simibubi.create; import com.simibubi.create.block.IJustForRendering; +import com.simibubi.create.block.SchematicTableBlock; +import com.simibubi.create.block.SchematicannonBlock; import com.simibubi.create.block.symmetry.BlockSymmetryCrossPlane; import com.simibubi.create.block.symmetry.BlockSymmetryPlane; import com.simibubi.create.block.symmetry.BlockSymmetryTriplePlane; @@ -13,6 +15,9 @@ import net.minecraftforge.registries.IForgeRegistry; public enum AllBlocks { + SCHEMATICANNON(new SchematicannonBlock()), + SCHEMATIC_TABLE(new SchematicTableBlock()), + SYMMETRY_PLANE(new BlockSymmetryPlane()), SYMMETRY_CROSSPLANE(new BlockSymmetryCrossPlane()), SYMMETRY_TRIPLEPLANE(new BlockSymmetryTriplePlane()); diff --git a/src/main/java/com/simibubi/create/AllContainers.java b/src/main/java/com/simibubi/create/AllContainers.java new file mode 100644 index 000000000..8cbffd161 --- /dev/null +++ b/src/main/java/com/simibubi/create/AllContainers.java @@ -0,0 +1,41 @@ +package com.simibubi.create; + +import com.simibubi.create.block.SchematicTableContainer; +import com.simibubi.create.gui.SchematicTableScreen; + +import net.minecraft.client.gui.ScreenManager; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.ContainerType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; + +@EventBusSubscriber(bus = Bus.MOD) +public enum AllContainers { + + SchematicTable(); + + public ContainerType type; + + private AllContainers() { + } + + @SubscribeEvent + public static void onContainerTypeRegistry(final RegistryEvent.Register> e) { + SchematicTable.type = new ContainerType<>(SchematicTableContainer::new) + .setRegistryName(SchematicTable.name().toLowerCase()); + + e.getRegistry().register(SchematicTable.type); + } + + @SuppressWarnings("unchecked") + @OnlyIn(Dist.CLIENT) + public static void registerScreenFactories() { + ScreenManager.registerFactory( + (ContainerType) SchematicTable.type, SchematicTableScreen::new); + } + +} diff --git a/src/main/java/com/simibubi/create/AllItems.java b/src/main/java/com/simibubi/create/AllItems.java index ddca40375..b6ebfa2d1 100644 --- a/src/main/java/com/simibubi/create/AllItems.java +++ b/src/main/java/com/simibubi/create/AllItems.java @@ -9,7 +9,9 @@ import net.minecraftforge.registries.IForgeRegistry; public enum AllItems { - SYMMETRY_WAND(new ItemWandSymmetry(standardProperties())); + SYMMETRY_WAND(new ItemWandSymmetry(standardProperties())), + EMPTY_BLUEPRINT(new Item(standardProperties().maxStackSize(1))), + BLUEPRINT(new Item(standardProperties().maxStackSize(1))); public Item item; diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java new file mode 100644 index 000000000..b7592d262 --- /dev/null +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -0,0 +1,49 @@ +package com.simibubi.create; + +import java.util.function.Supplier; + +import com.simibubi.create.block.SchematicTableTileEntity; +import com.simibubi.create.block.SchematicannonTileEntity; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; + +@Mod.EventBusSubscriber(bus = Bus.MOD) +public enum AllTileEntities { + + Schematicannon(SchematicannonTileEntity::new, AllBlocks.SCHEMATICANNON), + SchematicTable(SchematicTableTileEntity::new, AllBlocks.SCHEMATIC_TABLE); + + private Supplier supplier; + public TileEntityType type; + private AllBlocks block; + + private AllTileEntities(Supplier supplier, AllBlocks block) { + this.supplier = supplier; + this.block = block; + } + + @SubscribeEvent + public static void onTileEntityRegistry(final RegistryEvent.Register> event) { + + for (AllTileEntities tileEntity : values()) { + ResourceLocation resourceLocation = new ResourceLocation(Create.ID, tileEntity.name().toLowerCase()); + tileEntity.type = TileEntityType.Builder.create(tileEntity.supplier, tileEntity.block.get()).build(null) + .setRegistryName(resourceLocation); + event.getRegistry().register(tileEntity.type); + } + } + + public static void registerRenderers() { + } + +// private static void bind(Class clazz, TileEntityRenderer renderer) { +// ClientRegistry.bindTileEntitySpecialRenderer(clazz, renderer); +// } + +} diff --git a/src/main/java/com/simibubi/create/ClientSchematicLoader.java b/src/main/java/com/simibubi/create/ClientSchematicLoader.java new file mode 100644 index 000000000..8e252e43c --- /dev/null +++ b/src/main/java/com/simibubi/create/ClientSchematicLoader.java @@ -0,0 +1,148 @@ +package com.simibubi.create; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import com.simibubi.create.networking.PacketSchematicUpload; +import com.simibubi.create.networking.Packets; +import com.simibubi.create.utility.FilesHelper; + +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +@OnlyIn(Dist.CLIENT) +public class ClientSchematicLoader { + + public static final int PACKET_DELAY = 10; + public static final int PACKET_SIZE = 500; + + private List availableSchematics; + private Map activeUploads; + private Map progress; + private int packetCycle; + + public ClientSchematicLoader() { + availableSchematics = new ArrayList<>(); + activeUploads = new HashMap<>(); + progress = new HashMap<>(); + refresh(); + } + + public void tick() { + if (activeUploads.isEmpty()) + return; + if (packetCycle-- > 0) + return; + packetCycle = PACKET_DELAY; + + for (String schematic : new HashSet<>(activeUploads.keySet())) { + continueUpload(schematic); + } + } + + public float getProgress(String schematic) { + if (progress.containsKey(schematic)) { + return progress.get(schematic).getProgress(); + } + + return 0; + } + + public void startNewUpload(String schematic) { + Path path = Paths.get("schematics", schematic); + + if (!Files.exists(path)) { + Create.logger.fatal("Missing Schematic file: " + path.toString()); + return; + } + + InputStream in; + try { + in = Files.newInputStream(path, StandardOpenOption.READ); + activeUploads.put(schematic, in); + ReadProgress tracker = new ReadProgress(); + tracker.length = Files.size(path); + progress.put(schematic, tracker); + Packets.channel.sendToServer(PacketSchematicUpload.begin(schematic)); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void continueUpload(String schematic) { + if (activeUploads.containsKey(schematic)) { + byte[] data = new byte[PACKET_SIZE]; + try { + int status = activeUploads.get(schematic).read(data); + + progress.get(schematic).progress += status; + + if (status < PACKET_SIZE) { + data = Arrays.copyOf(data, status); + } + + Packets.channel.sendToServer(PacketSchematicUpload.write(schematic, data)); + + if (status < PACKET_SIZE) + finishUpload(schematic); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private void finishUpload(String schematic) { + if (activeUploads.containsKey(schematic)) { + Packets.channel.sendToServer(PacketSchematicUpload.finish(schematic)); + activeUploads.remove(schematic); + } + } + + public void refresh() { + FilesHelper.createFolderIfMissing("schematics"); + availableSchematics.clear(); + + try { + Files.list(Paths.get("schematics/")) + .forEach(path -> { + if (Files.isDirectory(path)) + return; + + availableSchematics.add(path.getFileName().toString()); + }); + } catch (NoSuchFileException e) { + // No Schematics created yet + } catch (IOException e) { + e.printStackTrace(); + } + + } + + public List getAvailableSchematics() { + return availableSchematics; + } + + public Path getPath(String name) { + return Paths.get("schematics", name + ".nbt"); + } + + public static class ReadProgress { + public long length; + public long progress; + public float getProgress() { + return (float) (progress * 1d / length); + } + } + +} diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index efdbe56e3..934de5951 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -1,5 +1,6 @@ package com.simibubi.create; +import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.simibubi.create.networking.Packets; @@ -7,12 +8,16 @@ import com.simibubi.create.networking.Packets; import net.minecraft.block.Block; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.event.RegistryEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; +import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @@ -25,9 +30,14 @@ public class Create { public static final String NAME = "Create"; public static final String VERSION = "0.0.1"; - public static Logger logger; + public static Logger logger = LogManager.getLogger(); public static ItemGroup creativeTab = new CreateItemGroup(); + + @OnlyIn(Dist.CLIENT) + public static ClientSchematicLoader cSchematicLoader; + + public static ServerSchematicLoader sSchematicLoader; public Create() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); @@ -37,12 +47,21 @@ public class Create { private void clientInit(FMLClientSetupEvent event) { AllItems.initColorHandlers(); - + AllTileEntities.registerRenderers(); + cSchematicLoader = new ClientSchematicLoader(); + sSchematicLoader = new ServerSchematicLoader(); // ScrollFixer.init(); } private void init(final FMLCommonSetupEvent event) { Packets.registerPackets(); + DistExecutor.runWhenOn(Dist.CLIENT, () -> AllContainers::registerScreenFactories); + } + + @OnlyIn(Dist.CLIENT) + @SubscribeEvent + public static void onClientTick(ClientTickEvent event) { + cSchematicLoader.tick(); } @EventBusSubscriber(bus = Bus.MOD) diff --git a/src/main/java/com/simibubi/create/ServerSchematicLoader.java b/src/main/java/com/simibubi/create/ServerSchematicLoader.java new file mode 100644 index 000000000..1f28622b4 --- /dev/null +++ b/src/main/java/com/simibubi/create/ServerSchematicLoader.java @@ -0,0 +1,102 @@ +package com.simibubi.create; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.HashMap; +import java.util.Map; + +import com.simibubi.create.block.SchematicTableContainer; +import com.simibubi.create.block.SchematicTableTileEntity; +import com.simibubi.create.networking.PacketSchematicUpload.DimensionPos; +import com.simibubi.create.utility.FilesHelper; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.util.text.TextFormatting; + +public class ServerSchematicLoader { + + private static final String PATH = "schematics/uploaded"; + private Map activeDownloads; + private Map activeTables; + + public ServerSchematicLoader() { + activeDownloads = new HashMap<>(); + activeTables = new HashMap<>(); + FilesHelper.createFolderIfMissing("schematics"); + FilesHelper.createFolderIfMissing(PATH); + } + + public void handleNewUpload(ServerPlayerEntity player, String schematic, DimensionPos dimensionPos) { + String playerPath = PATH + "/" + player.getName().getFormattedText(); + String playerSchematicId = player.getName().getFormattedText() + "/" + schematic; + + FilesHelper.createFolderIfMissing(playerPath); + + try { + Files.deleteIfExists(Paths.get(PATH, playerSchematicId)); + OutputStream writer = Files.newOutputStream(Paths.get(PATH, playerSchematicId), + StandardOpenOption.CREATE_NEW); + Create.logger.info("Receiving New Schematic: " + playerSchematicId); + activeDownloads.put(playerSchematicId, writer); + activeTables.put(playerSchematicId, dimensionPos); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void handleWriteRequest(ServerPlayerEntity player, String schematic, byte[] data) { + String playerSchematicId = player.getName().getFormattedText() + "/" + schematic; + if (activeDownloads.containsKey(playerSchematicId)) { + try { + activeDownloads.get(playerSchematicId).write(data); + Create.logger.info("Writing to Schematic: " + playerSchematicId); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void handleFinishedUpload(ServerPlayerEntity player, String schematic) { + String playerSchematicId = player.getName().getFormattedText() + "/" + schematic; + + if (activeDownloads.containsKey(playerSchematicId)) { + try { + activeDownloads.get(playerSchematicId).close(); + Create.logger.info("Finished receiving Schematic: " + playerSchematicId); + + DimensionPos dimpos = activeTables.remove(playerSchematicId); + BlockState blockState = dimpos.world.getBlockState(dimpos.pos); + if (!AllBlocks.SCHEMATIC_TABLE.typeOf(blockState)) + return; + + SchematicTableTileEntity tileEntity = (SchematicTableTileEntity) dimpos.world.getTileEntity(dimpos.pos); + if (tileEntity.inputStack.isEmpty()) + return; + if (!tileEntity.outputStack.isEmpty()) + return; + + tileEntity.inputStack = ItemStack.EMPTY; + tileEntity.outputStack = new ItemStack(AllItems.BLUEPRINT.get()); + tileEntity.outputStack + .setDisplayName(new StringTextComponent(TextFormatting.RESET + "" + TextFormatting.WHITE + + "Blueprint (" + TextFormatting.GOLD + schematic + TextFormatting.WHITE + ")")); + tileEntity.markDirty(); + dimpos.world.notifyBlockUpdate(dimpos.pos, blockState, blockState, 3); + if (player.openContainer instanceof SchematicTableContainer) { + ((SchematicTableContainer) player.openContainer).updateContent(); + player.openContainer.detectAndSendChanges(); + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + + } +} diff --git a/src/main/java/com/simibubi/create/block/SchematicTableBlock.java b/src/main/java/com/simibubi/create/block/SchematicTableBlock.java new file mode 100644 index 000000000..17d89235b --- /dev/null +++ b/src/main/java/com/simibubi/create/block/SchematicTableBlock.java @@ -0,0 +1,66 @@ +package com.simibubi.create.block; + +import net.minecraft.block.BlockRenderType; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.ContainerBlock; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.InventoryHelper; +import net.minecraft.inventory.container.INamedContainerProvider; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; + +public class SchematicTableBlock extends ContainerBlock { + + public SchematicTableBlock() { + super(Properties.from(Blocks.OAK_PLANKS)); + } + + @Override + public BlockRenderType getRenderType(BlockState state) { + return BlockRenderType.MODEL; + } + + @Override + public boolean hasTileEntity() { + return true; + } + + @Override + public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, + BlockRayTraceResult hit) { + if (worldIn.isRemote) { + return true; + } else { + INamedContainerProvider inamedcontainerprovider = this.getContainer(state, worldIn, pos); + if (inamedcontainerprovider != null) { + player.openContainer(inamedcontainerprovider); + } + + return true; + } + } + + @Override + public TileEntity createNewTileEntity(IBlockReader worldIn) { + return new SchematicTableTileEntity(); + } + + @Override + public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + if (worldIn.getTileEntity(pos) == null) + return; + + SchematicTableTileEntity te = (SchematicTableTileEntity) worldIn.getTileEntity(pos); + if (!te.inputStack.isEmpty()) + InventoryHelper.spawnItemStack(worldIn, pos.getX(), pos.getY(), pos.getZ(), te.inputStack); + if (!te.outputStack.isEmpty()) + InventoryHelper.spawnItemStack(worldIn, pos.getX(), pos.getY(), pos.getZ(), te.outputStack); + + } + +} diff --git a/src/main/java/com/simibubi/create/block/SchematicTableContainer.java b/src/main/java/com/simibubi/create/block/SchematicTableContainer.java new file mode 100644 index 000000000..7a01ba074 --- /dev/null +++ b/src/main/java/com/simibubi/create/block/SchematicTableContainer.java @@ -0,0 +1,124 @@ +package com.simibubi.create.block; + +import com.simibubi.create.AllContainers; +import com.simibubi.create.AllItems; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.Slot; +import net.minecraft.item.ItemStack; + +public class SchematicTableContainer extends Container { + + private final IInventory tableInventory = new Inventory(2) { + public void markDirty() { + super.markDirty(); + onCraftMatrixChanged(this); + } + }; + + private SchematicTableTileEntity te; + private Slot inputSlot; + private Slot outputSlot; + + public SchematicTableContainer(int id, PlayerInventory inv) { + this(id, inv, null); + } + + public SchematicTableContainer(int id, PlayerInventory inv, SchematicTableTileEntity te) { + super(AllContainers.SchematicTable.type, id); + this.te = te; + + inputSlot = new Slot(tableInventory, 0, 31, 15) { + @Override + public boolean isItemValid(ItemStack stack) { + return AllItems.EMPTY_BLUEPRINT.typeOf(stack); + } + }; + + outputSlot = new Slot(tableInventory, 1, 115, 15) { + @Override + public boolean isItemValid(ItemStack stack) { + return false; + } + }; + + addSlot(inputSlot); + addSlot(outputSlot); + + updateContent(); + + // player Slots + tableInventory.openInventory(inv.player); + for (int l = 0; l < 3; ++l) { + for (int j1 = 0; j1 < 9; ++j1) { + this.addSlot(new Slot(inv, j1 + l * 9 + 9, -8 + j1 * 18, 77 + l * 18)); + } + } + + for (int i1 = 0; i1 < 9; ++i1) { + this.addSlot(new Slot(inv, i1, -8 + i1 * 18, 135)); + } + } + + public boolean canWrite() { + return inputSlot.getHasStack() && !outputSlot.getHasStack(); + } + + @Override + public boolean canInteractWith(PlayerEntity playerIn) { + return true; + } + + @Override + public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) { + Slot clickedSlot = getSlot(index); + if (!clickedSlot.getHasStack()) + return ItemStack.EMPTY; + + ItemStack stack = clickedSlot.getStack(); + if (clickedSlot == inputSlot || clickedSlot == outputSlot) { + int indexToPut = playerIn.inventory.getFirstEmptyStack(); + + if (indexToPut == -1) + return ItemStack.EMPTY; + + playerIn.inventory.setInventorySlotContents(indexToPut, stack); + clickedSlot.putStack(ItemStack.EMPTY); + return ItemStack.EMPTY; + } + + if (AllItems.EMPTY_BLUEPRINT.typeOf(stack) && !inputSlot.getHasStack()) { + clickedSlot.putStack(ItemStack.EMPTY); + inputSlot.putStack(stack); + } + + return ItemStack.EMPTY; + } + + public void updateContent() { + if (te != null) { + inputSlot.putStack(te.inputStack); + outputSlot.putStack(te.outputStack); + } + } + + @Override + public void onContainerClosed(PlayerEntity playerIn) { + if (te != null) { + te.inputStack = inputSlot.getStack(); + te.outputStack = outputSlot.getStack(); + te.markDirty(); + } + + super.onContainerClosed(playerIn); + } + + public SchematicTableTileEntity getTileEntity() { + return te; + } + +} diff --git a/src/main/java/com/simibubi/create/block/SchematicTableTileEntity.java b/src/main/java/com/simibubi/create/block/SchematicTableTileEntity.java new file mode 100644 index 000000000..a6784191a --- /dev/null +++ b/src/main/java/com/simibubi/create/block/SchematicTableTileEntity.java @@ -0,0 +1,73 @@ +package com.simibubi.create.block; + +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.utility.TileEntitySynced; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.ItemStackHelper; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.INamedContainerProvider; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.NonNullList; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.StringTextComponent; + +public class SchematicTableTileEntity extends TileEntitySynced implements ITickableTileEntity, INamedContainerProvider { + + public ItemStack inputStack; + public ItemStack outputStack; + + public SchematicTableTileEntity() { + this(AllTileEntities.SchematicTable.type); + } + + public SchematicTableTileEntity(TileEntityType tileEntityTypeIn) { + super(tileEntityTypeIn); + inputStack = ItemStack.EMPTY; + outputStack = ItemStack.EMPTY; + } + + @Override + public void read(CompoundNBT compound) { + NonNullList stacks = NonNullList.create(); + ItemStackHelper.loadAllItems(compound, stacks); + + if (!stacks.isEmpty()) { + inputStack = stacks.get(0); + outputStack = stacks.get(1); + } + + super.read(compound); + } + + @Override + public CompoundNBT write(CompoundNBT compound) { + NonNullList stacks = NonNullList.create(); + + stacks.add(inputStack); + stacks.add(outputStack); + + ItemStackHelper.saveAllItems(compound, stacks); + return super.write(compound); + } + + @Override + public void tick() { + + } + + @Override + public Container createMenu(int p_createMenu_1_, PlayerInventory p_createMenu_2_, PlayerEntity p_createMenu_3_) { + return new SchematicTableContainer(p_createMenu_1_, p_createMenu_2_, this); + } + + @Override + public ITextComponent getDisplayName() { + return new StringTextComponent(getType().getRegistryName().toString()); + } + +} diff --git a/src/main/java/com/simibubi/create/block/SchematicannonBlock.java b/src/main/java/com/simibubi/create/block/SchematicannonBlock.java new file mode 100644 index 000000000..608b7e180 --- /dev/null +++ b/src/main/java/com/simibubi/create/block/SchematicannonBlock.java @@ -0,0 +1,45 @@ +package com.simibubi.create.block; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.text.StringTextComponent; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; + +public class SchematicannonBlock extends Block { + + public SchematicannonBlock() { + super(Properties.from(Blocks.DISPENSER)); + } + + @Override + public boolean hasTileEntity(BlockState state) { + return true; + } + + @Override + public TileEntity createTileEntity(BlockState state, IBlockReader world) { + return new SchematicannonTileEntity(); + } + + @Override + public boolean onBlockActivated(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, + BlockRayTraceResult hit) { + TileEntity tileEntity = worldIn.getTileEntity(pos); + if (worldIn.isRemote) + return true; + + if (tileEntity == null) + return false; + + player.sendMessage(new StringTextComponent("" + ((SchematicannonTileEntity) tileEntity).getTest())); + return true; + } + +} diff --git a/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java b/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java new file mode 100644 index 000000000..9c3077c46 --- /dev/null +++ b/src/main/java/com/simibubi/create/block/SchematicannonTileEntity.java @@ -0,0 +1,48 @@ +package com.simibubi.create.block; + +import com.simibubi.create.AllTileEntities; +import com.simibubi.create.utility.TileEntitySynced; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.ITickableTileEntity; +import net.minecraft.tileentity.TileEntityType; + +public class SchematicannonTileEntity extends TileEntitySynced implements ITickableTileEntity { + + private int test = 0; + + public SchematicannonTileEntity() { + super(AllTileEntities.Schematicannon.type); + } + + public SchematicannonTileEntity(TileEntityType tileEntityTypeIn) { + super(tileEntityTypeIn); + } + + @Override + public void read(CompoundNBT compound) { + super.read(compound); + test = compound.getInt("Test"); + } + + @Override + public CompoundNBT write(CompoundNBT compound) { + compound.putInt("Test", test); + return super.write(compound); + } + + public int getTest() { + return test; + } + + public void setTest(int test) { + this.test = test; + } + + @Override + public void tick() { + test++; + } + + +} diff --git a/src/main/java/com/simibubi/create/gui/GuiHandler.java b/src/main/java/com/simibubi/create/gui/GuiHandler.java new file mode 100644 index 000000000..f7fa187ab --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/GuiHandler.java @@ -0,0 +1,5 @@ +package com.simibubi.create.gui; + +public class GuiHandler { + +} diff --git a/src/main/java/com/simibubi/create/gui/GuiResources.java b/src/main/java/com/simibubi/create/gui/GuiResources.java index 8941318cc..599dbfa38 100644 --- a/src/main/java/com/simibubi/create/gui/GuiResources.java +++ b/src/main/java/com/simibubi/create/gui/GuiResources.java @@ -10,11 +10,9 @@ public enum GuiResources { // Inventories PLAYER_INVENTORY("player_inventory.png", 176, 108), - COMPOSER("composer.png", 256, 58), - PALETTES("palette_picker.png", 256, 236), - EXPORTER("design_exporter.png", 200, 111), - THEME_EDITOR("theme_editor.png", 200, 187), WAND_SYMMETRY("wand_symmetry.png", 207, 58), + SCHEMATIC_TABLE("schematic_table.png", 207, 89), + SCHEMATIC_TABLE_PROGRESS("schematic_table.png", 209, 0, 24, 17), // Widgets PALETTE_BUTTON("palette_picker.png", 0, 236, 20, 20), @@ -29,11 +27,6 @@ public enum GuiResources { INDICATOR_RED("widgets.png", 36, 23, 18, 5), GRAY("background.png", 0, 0, 16, 16), - SCROLLBAR_AXIS("widgets.png", 224, 0, 32, 256), - SCROLLBAR_CAP("widgets.png", 0, 87, 40, 6), - SCROLLBAR_INDICATOR("widgets.png", 0, 75, 40, 12), - SCROLLBAR_BACKGROUND("widgets.png", 0, 93, 40, 16), - // Icons ICON_NONE("icons.png", 16, 16, 16, 16), ICON_ADD("icons.png", 16, 16), diff --git a/src/main/java/com/simibubi/create/gui/SchematicTableScreen.java b/src/main/java/com/simibubi/create/gui/SchematicTableScreen.java new file mode 100644 index 000000000..ab60d10ca --- /dev/null +++ b/src/main/java/com/simibubi/create/gui/SchematicTableScreen.java @@ -0,0 +1,147 @@ +package com.simibubi.create.gui; + +import java.util.List; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.simibubi.create.Create; +import com.simibubi.create.block.SchematicTableContainer; +import com.simibubi.create.gui.widgets.AbstractSimiWidget; +import com.simibubi.create.gui.widgets.DynamicLabel; +import com.simibubi.create.gui.widgets.OptionScrollArea; +import com.simibubi.create.gui.widgets.ScrollArea; +import com.simibubi.create.gui.widgets.SimiButton; + +import net.minecraft.client.gui.IHasContainer; +import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraft.client.gui.widget.Widget; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.text.ITextComponent; + +public class SchematicTableScreen extends ContainerScreen + implements IHasContainer { + + private ScrollArea schematics; + private SimiButton button; + private DynamicLabel label; + + private boolean isUploading; + private String uploadingSchematic; + private float progress; + private float lastProgress; + + private int xTopLeft; + private int yTopLeft; + + private int xMainWindow; + private int yMainWindow; + + public SchematicTableScreen(SchematicTableContainer container, PlayerInventory playerInventory, + ITextComponent title) { + super(container, playerInventory, title); + } + + @Override + protected void init() { + super.init(); + xTopLeft = (width - GuiResources.SCHEMATIC_TABLE.width) / 2; + yTopLeft = (height - GuiResources.SCHEMATIC_TABLE.height) / 2; + xMainWindow = xTopLeft; + yMainWindow = yTopLeft - 80; + buttons.clear(); + + Create.cSchematicLoader.refresh(); + List availableSchematics = Create.cSchematicLoader.getAvailableSchematics(); + + if (!availableSchematics.isEmpty()) { + label = new DynamicLabel(xMainWindow + 36, yMainWindow + 26, "").withShadow(); + schematics = new OptionScrollArea(xMainWindow + 33, yMainWindow + 23, 134, 14) + .forOptions(availableSchematics).titled("Available Schematics").writingTo(label); + buttons.add(schematics); + buttons.add(label); + } else { + + } + + button = new SimiButton(xMainWindow + 69, yMainWindow + 55, GuiResources.ICON_CONFIRM); + buttons.add(button); + } + + @Override + protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) { + int x = xTopLeft; + int y = yTopLeft; + + GuiResources.SCHEMATIC_TABLE.draw(this, xMainWindow, yMainWindow); + GuiResources.PLAYER_INVENTORY.draw(this, x, y + 20); + + font.drawString("Choose a Schematic", xMainWindow + 50, yMainWindow + 10, GuiResources.FONT_COLOR); + font.drawString("Inventory", x + 7, y + 26, 0x666666); + + if (schematics == null) { + font.drawStringWithShadow(" No Schematics Saved ", xMainWindow + 39, yMainWindow + 26, 0xFFDD44); + } + } + + @Override + public void render(int mouseX, int mouseY, float pt) { + renderBackground(); + super.render(mouseX, mouseY, pt); + + minecraft.getTextureManager().bindTexture(GuiResources.SCHEMATIC_TABLE_PROGRESS.location); + int width = (int) (GuiResources.SCHEMATIC_TABLE_PROGRESS.width * MathHelper.lerp(pt, lastProgress, progress)); + int height = GuiResources.SCHEMATIC_TABLE_PROGRESS.height; + GlStateManager.disableLighting(); + blit(xMainWindow + 94, yMainWindow + 56, GuiResources.SCHEMATIC_TABLE_PROGRESS.startX, GuiResources.SCHEMATIC_TABLE_PROGRESS.startY, width, height); + + renderHoveredToolTip(mouseX, mouseY); + for (Widget w : buttons) { + if (w instanceof AbstractSimiWidget && w.isHovered()) { + List toolTip = ((AbstractSimiWidget) w).getToolTip(); + renderTooltip(toolTip, mouseX, mouseY); + } + } + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @Override + public void tick() { + super.tick(); + if (isUploading) { + lastProgress = progress; + progress = Create.cSchematicLoader.getProgress(uploadingSchematic); + } + } + + @Override + public boolean mouseClicked(double p_mouseClicked_1_, double p_mouseClicked_3_, int p_mouseClicked_5_) { + if (button.isHovered() && ((SchematicTableContainer) container).canWrite() && schematics != null) { + button.active = false; + schematics.active = false; + label.colored(0xCCDDFF); + + List availableSchematics = Create.cSchematicLoader.getAvailableSchematics(); + lastProgress = progress = 0; + uploadingSchematic = availableSchematics.get(schematics.getState()); + isUploading = true; + Create.cSchematicLoader.startNewUpload(uploadingSchematic); + } + + return super.mouseClicked(p_mouseClicked_1_, p_mouseClicked_3_, p_mouseClicked_5_); + } + + @Override + public boolean mouseScrolled(double p_mouseScrolled_1_, double p_mouseScrolled_3_, double p_mouseScrolled_5_) { + boolean b = false; + for (Widget w : buttons) { + if (w.mouseScrolled(p_mouseScrolled_1_, p_mouseScrolled_3_, p_mouseScrolled_5_)) + b = true; + } + return b || super.mouseScrolled(p_mouseScrolled_1_, p_mouseScrolled_3_, p_mouseScrolled_5_); + } + +} diff --git a/src/main/java/com/simibubi/create/gui/widgets/SimiButton.java b/src/main/java/com/simibubi/create/gui/widgets/SimiButton.java index 33de77bd4..bdca7aea9 100644 --- a/src/main/java/com/simibubi/create/gui/widgets/SimiButton.java +++ b/src/main/java/com/simibubi/create/gui/widgets/SimiButton.java @@ -24,7 +24,7 @@ public class SimiButton extends AbstractSimiWidget { this.isHovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height; GuiResources button = - (pressed) ? button = GuiResources.BUTTON_DOWN : + (pressed || !active) ? button = GuiResources.BUTTON_DOWN : (isHovered) ? GuiResources.BUTTON_HOVER : GuiResources.BUTTON; diff --git a/src/main/java/com/simibubi/create/networking/PacketSchematicUpload.java b/src/main/java/com/simibubi/create/networking/PacketSchematicUpload.java new file mode 100644 index 000000000..60c9bc7ce --- /dev/null +++ b/src/main/java/com/simibubi/create/networking/PacketSchematicUpload.java @@ -0,0 +1,86 @@ +package com.simibubi.create.networking; + +import java.util.function.Supplier; + +import com.simibubi.create.Create; +import com.simibubi.create.block.SchematicTableContainer; + +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.ServerWorld; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class PacketSchematicUpload { + + public static final int BEGIN = 0; + public static final int WRITE = 1; + public static final int FINISH = 2; + + private int code; + private String schematic; + private byte[] data; + + public PacketSchematicUpload(int code, String schematic) { + this.code = code; + this.schematic = schematic; + } + + public static PacketSchematicUpload begin(String schematic) { + PacketSchematicUpload pkt = new PacketSchematicUpload(BEGIN, schematic); + return pkt; + } + + public static PacketSchematicUpload write(String schematic, byte[] data) { + PacketSchematicUpload pkt = new PacketSchematicUpload(WRITE, schematic); + pkt.data = data; + return pkt; + } + + public static PacketSchematicUpload finish(String schematic) { + return new PacketSchematicUpload(FINISH, schematic); + } + + public PacketSchematicUpload(PacketBuffer buffer) { + code = buffer.readInt(); + schematic = buffer.readString(); + + if (code == WRITE) + data = buffer.readByteArray(); + } + + public void toBytes(PacketBuffer buffer) { + buffer.writeInt(code); + buffer.writeString(schematic); + + if (code == WRITE) + buffer.writeByteArray(data); + } + + public void handle(Supplier context) { + context.get().enqueueWork(() -> { + ServerPlayerEntity player = context.get().getSender(); + if (code == BEGIN) { + BlockPos pos = ((SchematicTableContainer) player.openContainer).getTileEntity().getPos(); + Create.sSchematicLoader.handleNewUpload(player, schematic, new DimensionPos(player, pos)); + } + if (code == WRITE) { + Create.sSchematicLoader.handleWriteRequest(player, schematic, data); + } + if (code == FINISH) { + Create.sSchematicLoader.handleFinishedUpload(player, schematic); + } + }); + } + + public static class DimensionPos { + public ServerWorld world; + public BlockPos pos; + + public DimensionPos(ServerPlayerEntity player, BlockPos pos) { + this.world = player.getServerWorld(); + this.pos = pos; + } + } + +} diff --git a/src/main/java/com/simibubi/create/networking/Packets.java b/src/main/java/com/simibubi/create/networking/Packets.java index 7ca507cf5..233a9dda5 100644 --- a/src/main/java/com/simibubi/create/networking/Packets.java +++ b/src/main/java/com/simibubi/create/networking/Packets.java @@ -8,14 +8,19 @@ import net.minecraftforge.fml.network.simple.SimpleChannel; public class Packets { - public static final SimpleChannel channel = NetworkRegistry.newSimpleChannel( - new ResourceLocation(Create.ID, "simple_channel"), () -> "1", v -> v.equals("1"), v -> v.equals("1")); + private static final String PROTOCOL_VERSION = "1"; + public static final SimpleChannel channel = NetworkRegistry.newSimpleChannel( + new ResourceLocation(Create.ID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, + PROTOCOL_VERSION::equals); + public static void registerPackets() { int i = 0; channel.registerMessage(i++, PacketNbt.class, PacketNbt::toBytes, PacketNbt::new, PacketNbt::handle); + channel.registerMessage(i++, PacketSchematicUpload.class, PacketSchematicUpload::toBytes, PacketSchematicUpload::new, + PacketSchematicUpload::handle); channel.registerMessage(i++, PacketSymmetryEffect.class, PacketSymmetryEffect::toBytes, PacketSymmetryEffect::new, PacketSymmetryEffect::handle); } diff --git a/src/main/java/com/simibubi/create/utility/FilesHelper.java b/src/main/java/com/simibubi/create/utility/FilesHelper.java new file mode 100644 index 000000000..b61f1bc6a --- /dev/null +++ b/src/main/java/com/simibubi/create/utility/FilesHelper.java @@ -0,0 +1,109 @@ +package com.simibubi.create.utility; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.internal.Streams; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.simibubi.create.Create; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.JsonToNBT; + +public class FilesHelper { + + public static void createFolderIfMissing(String name) { + if (!Files.isDirectory(Paths.get(name))) { + try { + Files.createDirectory(Paths.get(name)); + } catch (IOException e) { + Create.logger.warn("Could not create Folder: " + name); + } + } + } + + public static String findFirstValidFilename(String name, String folderPath, String extension) { + int index = 0; + String filename; + String filepath; + do { + filename = slug(name) + ((index == 0) ? "" : "_" + index) + "." + extension; + index++; + filepath = folderPath + "/" + filename; + } while (Files.exists(Paths.get(filepath))); + return filename; + } + + public static String slug(String name) { + return name.toLowerCase().replace(' ', '_'); + } + + public static boolean saveTagCompoundAsJson(CompoundNBT compound, String path) { + try { + Files.deleteIfExists(Paths.get(path)); + JsonWriter writer = new JsonWriter(Files.newBufferedWriter(Paths.get(path), StandardOpenOption.CREATE)); + writer.setIndent(" "); + Streams.write(new JsonParser().parse(compound.toString()), writer); + writer.close(); + return true; + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + + public static boolean saveTagCompoundAsJsonCompact(CompoundNBT compound, String path) { + try { + Files.deleteIfExists(Paths.get(path)); + JsonWriter writer = new JsonWriter(Files.newBufferedWriter(Paths.get(path), StandardOpenOption.CREATE)); + Streams.write(new JsonParser().parse(compound.toString()), writer); + writer.close(); + return true; + } catch (IOException e) { + e.printStackTrace(); + } + return false; + + } + + public static CompoundNBT loadJsonNBT(InputStream inputStream) { + try { + JsonReader reader = new JsonReader(new BufferedReader(new InputStreamReader(inputStream))); + reader.setLenient(true); + JsonElement element = Streams.parse(reader); + reader.close(); + inputStream.close(); + return JsonToNBT.getTagFromJson(element.toString()); + } catch (IOException e) { + e.printStackTrace(); + } catch (CommandSyntaxException e) { + e.printStackTrace(); + } + return null; + } + + public static CompoundNBT loadJsonResourceAsNBT(String filepath) { + return loadJsonNBT(Create.class.getClassLoader().getResourceAsStream(filepath)); + } + + public static CompoundNBT loadJsonAsNBT(String filepath) { + try { + return loadJsonNBT(Files.newInputStream(Paths.get(filepath), StandardOpenOption.READ)); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + +} diff --git a/src/main/java/com/simibubi/create/utility/TileEntitySynced.java b/src/main/java/com/simibubi/create/utility/TileEntitySynced.java new file mode 100644 index 000000000..7386b0734 --- /dev/null +++ b/src/main/java/com/simibubi/create/utility/TileEntitySynced.java @@ -0,0 +1,35 @@ +package com.simibubi.create.utility; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.play.server.SUpdateTileEntityPacket; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityType; + +public abstract class TileEntitySynced extends TileEntity { + + public TileEntitySynced(TileEntityType tileEntityTypeIn) { + super(tileEntityTypeIn); + } + + @Override + public CompoundNBT getUpdateTag() { + return write(new CompoundNBT()); + } + + @Override + public void handleUpdateTag(CompoundNBT tag) { + read(tag); + } + + @Override + public SUpdateTileEntityPacket getUpdatePacket(){ + return new SUpdateTileEntityPacket(getPos(), 1, write(new CompoundNBT())); + } + + @Override + public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt){ + read(pkt.getNbtCompound()); + } + +} diff --git a/src/main/resources/assets/create/blockstates/schematic_table.json b/src/main/resources/assets/create/blockstates/schematic_table.json new file mode 100644 index 000000000..2e05aae19 --- /dev/null +++ b/src/main/resources/assets/create/blockstates/schematic_table.json @@ -0,0 +1,6 @@ +{ + "forgemarker": 1, + "variants": { + "": { "model": "block/crafting_table" } + } +} diff --git a/src/main/resources/assets/create/blockstates/schematicannon.json b/src/main/resources/assets/create/blockstates/schematicannon.json new file mode 100644 index 000000000..c51526246 --- /dev/null +++ b/src/main/resources/assets/create/blockstates/schematicannon.json @@ -0,0 +1,6 @@ +{ + "forgemarker": 1, + "variants": { + "": { "model": "block/dropper_vertical" } + } +} diff --git a/src/main/resources/assets/create/lang/en_us.json b/src/main/resources/assets/create/lang/en_us.json index 248e40894..92c0fbb5e 100644 --- a/src/main/resources/assets/create/lang/en_us.json +++ b/src/main/resources/assets/create/lang/en_us.json @@ -1,4 +1,8 @@ { "item.create.symmetry_wand": "Staff of Symmetry", + "item.create.empty_blueprint": "Empty Blueprint", + "item.create.blueprint": "Blueprint", + "block.create.schematicannon": "SchematiCannon 9000", + "block.create.schematic_table": "Schematic Planner", "itemGroup.create": "Create" } diff --git a/src/main/resources/assets/create/models/item/blueprint.json b/src/main/resources/assets/create/models/item/blueprint.json new file mode 100644 index 000000000..a4e80c0b2 --- /dev/null +++ b/src/main/resources/assets/create/models/item/blueprint.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "create:item/blueprint_filled" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/empty_blueprint.json b/src/main/resources/assets/create/models/item/empty_blueprint.json new file mode 100644 index 000000000..fc08c7945 --- /dev/null +++ b/src/main/resources/assets/create/models/item/empty_blueprint.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "create:item/blueprint_empty" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/schematic_table.json b/src/main/resources/assets/create/models/item/schematic_table.json new file mode 100644 index 000000000..6f5f75bc4 --- /dev/null +++ b/src/main/resources/assets/create/models/item/schematic_table.json @@ -0,0 +1,3 @@ +{ + "parent": "block/crafting_table" +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/item/schematicannon.json b/src/main/resources/assets/create/models/item/schematicannon.json new file mode 100644 index 000000000..c02389b9c --- /dev/null +++ b/src/main/resources/assets/create/models/item/schematicannon.json @@ -0,0 +1,3 @@ +{ + "parent": "block/dropper_vertical" +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/gui/schematic_table.png b/src/main/resources/assets/create/textures/gui/schematic_table.png new file mode 100644 index 000000000..06ae3203c Binary files /dev/null and b/src/main/resources/assets/create/textures/gui/schematic_table.png differ