Schematicannon and Holograms

- Uploaded Blueprints can be previewed by the owner
- The Schematicannon prints the schematic from blocks in attached inventories
This commit is contained in:
simibubi 2019-07-12 12:13:05 +02:00
parent 550b477d8d
commit b66aa4c4d3
15 changed files with 1002 additions and 66 deletions

View file

@ -1,5 +1,6 @@
package com.simibubi.create;
import com.simibubi.create.item.ItemBlueprint;
import com.simibubi.create.item.ItemWandSymmetry;
import net.minecraft.item.Item;
@ -11,7 +12,7 @@ public enum AllItems {
SYMMETRY_WAND(new ItemWandSymmetry(standardProperties())),
EMPTY_BLUEPRINT(new Item(standardProperties().maxStackSize(1))),
BLUEPRINT(new Item(standardProperties().maxStackSize(1)));
BLUEPRINT(new ItemBlueprint(standardProperties()));
public Item item;

View file

@ -66,7 +66,7 @@ public class ClientSchematicLoader {
Create.logger.fatal("Missing Schematic file: " + path.toString());
return;
}
InputStream in;
try {
in = Files.newInputStream(path, StandardOpenOption.READ);
@ -108,7 +108,7 @@ public class ClientSchematicLoader {
activeUploads.remove(schematic);
}
}
public void refresh() {
FilesHelper.createFolderIfMissing("schematics");
availableSchematics.clear();

View file

@ -4,6 +4,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.simibubi.create.networking.Packets;
import com.simibubi.create.schematic.SchematicHologram;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
@ -50,6 +51,7 @@ public class Create {
AllTileEntities.registerRenderers();
cSchematicLoader = new ClientSchematicLoader();
sSchematicLoader = new ServerSchematicLoader();
new SchematicHologram();
// ScrollFixer.init();
}

View file

@ -21,7 +21,7 @@ import net.minecraft.util.text.TextFormatting;
public class ServerSchematicLoader {
private static final String PATH = "schematics/uploaded";
public static final String PATH = "schematics/uploaded";
private Map<String, OutputStream> activeDownloads;
private Map<String, DimensionPos> activeTables;
@ -38,6 +38,9 @@ public class ServerSchematicLoader {
FilesHelper.createFolderIfMissing(playerPath);
if (activeDownloads.containsKey(playerSchematicId))
return;
try {
Files.deleteIfExists(Paths.get(PATH, playerSchematicId));
OutputStream writer = Files.newOutputStream(Paths.get(PATH, playerSchematicId),
@ -45,6 +48,15 @@ public class ServerSchematicLoader {
Create.logger.info("Receiving New Schematic: " + playerSchematicId);
activeDownloads.put(playerSchematicId, writer);
activeTables.put(playerSchematicId, dimensionPos);
if (player.openContainer instanceof SchematicTableContainer) {
SchematicTableContainer c = (SchematicTableContainer) player.openContainer;
c.schematicUploading = schematic;
c.isUploading = true;
c.sendSchematicUpdate = true;
player.openContainer.detectAndSendChanges();
}
} catch (IOException e) {
e.printStackTrace();
}
@ -53,11 +65,14 @@ public class ServerSchematicLoader {
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();
activeDownloads.remove(playerSchematicId);
activeTables.remove(playerSchematicId);
}
}
}
@ -68,13 +83,27 @@ public class ServerSchematicLoader {
if (activeDownloads.containsKey(playerSchematicId)) {
try {
activeDownloads.get(playerSchematicId).close();
activeDownloads.remove(playerSchematicId);
Create.logger.info("Finished receiving Schematic: " + playerSchematicId);
DimensionPos dimpos = activeTables.remove(playerSchematicId);
if (dimpos == null)
return;
BlockState blockState = dimpos.world.getBlockState(dimpos.pos);
if (!AllBlocks.SCHEMATIC_TABLE.typeOf(blockState))
return;
if (player.openContainer instanceof SchematicTableContainer) {
SchematicTableContainer c = (SchematicTableContainer) player.openContainer;
c.isUploading = false;
c.schematicUploading = null;
c.progress = 0;
c.sendSchematicUpdate = true;
c.detectAndSendChanges();
}
SchematicTableTileEntity tileEntity = (SchematicTableTileEntity) dimpos.world.getTileEntity(dimpos.pos);
if (tileEntity.inputStack.isEmpty())
return;
@ -82,15 +111,19 @@ public class ServerSchematicLoader {
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();
ItemStack blueprint = new ItemStack(AllItems.BLUEPRINT.get());
blueprint.setDisplayName(new StringTextComponent(TextFormatting.RESET + "" + TextFormatting.WHITE
+ "Blueprint (" + TextFormatting.GOLD + schematic + TextFormatting.WHITE + ")"));
blueprint.getTag().putString("Owner", player.getName().getFormattedText());
blueprint.getTag().putString("File", schematic);
tileEntity.outputStack = blueprint;
dimpos.world.notifyBlockUpdate(dimpos.pos, blockState, blockState, 3);
if (player.openContainer instanceof SchematicTableContainer) {
((SchematicTableContainer) player.openContainer).updateContent();
player.openContainer.detectAndSendChanges();
SchematicTableContainer c = (SchematicTableContainer) player.openContainer;
c.updateContent();
}
} catch (IOException e) {

View file

@ -2,14 +2,20 @@ package com.simibubi.create.block;
import com.simibubi.create.AllContainers;
import com.simibubi.create.AllItems;
import com.simibubi.create.networking.PacketSchematicTableContainer;
import com.simibubi.create.networking.Packets;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.player.ServerPlayerEntity;
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;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.network.PacketDistributor;
public class SchematicTableContainer extends Container {
@ -23,13 +29,20 @@ public class SchematicTableContainer extends Container {
private SchematicTableTileEntity te;
private Slot inputSlot;
private Slot outputSlot;
private PlayerEntity player;
public String schematicUploading;
public boolean isUploading;
public float progress;
public boolean sendSchematicUpdate;
public SchematicTableContainer(int id, PlayerInventory inv) {
this(id, inv, null);
}
public SchematicTableContainer(int id, PlayerInventory inv, SchematicTableTileEntity te) {
super(AllContainers.SchematicTable.type, id);
this.player = inv.player;
this.te = te;
inputSlot = new Slot(tableInventory, 0, 31, 15) {
@ -51,6 +64,10 @@ public class SchematicTableContainer extends Container {
updateContent();
if (te != null) {
this.addListener(te);
}
// player Slots
tableInventory.openInventory(inv.player);
for (int l = 0; l < 3; ++l) {
@ -63,6 +80,12 @@ public class SchematicTableContainer extends Container {
this.addSlot(new Slot(inv, i1, -8 + i1 * 18, 135));
}
}
@Override
public void detectAndSendChanges() {
super.detectAndSendChanges();
sendSchematicInfo();
}
public boolean canWrite() {
return inputSlot.getHasStack() && !outputSlot.getHasStack();
@ -98,14 +121,41 @@ public class SchematicTableContainer extends Container {
return ItemStack.EMPTY;
}
public void updateContent() {
if (te != null) {
inputSlot.putStack(te.inputStack);
outputSlot.putStack(te.outputStack);
schematicUploading = te.uploadingSchematic;
progress = te.uploadingProgress;
sendSchematicUpdate = true;
}
}
public void sendSchematicInfo() {
if (player instanceof ServerPlayerEntity) {
if (sendSchematicUpdate) {
Packets.channel.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player),
new PacketSchematicTableContainer(schematicUploading, progress));
sendSchematicUpdate = false;
}
}
}
@OnlyIn(Dist.CLIENT)
public void receiveSchematicInfo(String schematic, float progress) {
if (schematic.isEmpty()) {
this.schematicUploading = null;
this.isUploading = false;
this.progress = 0;
return;
}
this.isUploading = true;
this.schematicUploading = schematic;
this.progress = .5f;
}
@Override
public void onContainerClosed(PlayerEntity playerIn) {
if (te != null) {
@ -113,10 +163,10 @@ public class SchematicTableContainer extends Container {
te.outputStack = outputSlot.getStack();
te.markDirty();
}
super.onContainerClosed(playerIn);
}
public SchematicTableTileEntity getTileEntity() {
return te;
}

View file

@ -7,6 +7,7 @@ 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.IContainerListener;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
@ -16,11 +17,14 @@ 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 class SchematicTableTileEntity extends TileEntitySynced implements ITickableTileEntity, INamedContainerProvider, IContainerListener {
public ItemStack inputStack;
public ItemStack outputStack;
public String uploadingSchematic;
public float uploadingProgress;
public SchematicTableTileEntity() {
this(AllTileEntities.SchematicTable.type);
}
@ -69,5 +73,25 @@ public class SchematicTableTileEntity extends TileEntitySynced implements ITicka
public ITextComponent getDisplayName() {
return new StringTextComponent(getType().getRegistryName().toString());
}
@Override
public void sendAllContents(Container containerToSend, NonNullList<ItemStack> itemsList) {
inputStack = itemsList.get(0);
outputStack = itemsList.get(1);
}
@Override
public void sendSlotContents(Container containerToSend, int slotInd, ItemStack stack) {
if (slotInd == 0) {
inputStack = stack;
}
if (slotInd == 1) {
outputStack = stack;
}
}
@Override
public void sendWindowProperty(Container containerIn, int varToUpdate, int newValue) {
}
}

View file

@ -3,14 +3,12 @@ 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.Direction;
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;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
public class SchematicannonBlock extends Block {
@ -29,17 +27,16 @@ public class SchematicannonBlock extends Block {
}
@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;
public BlockState updatePostPlacement(BlockState stateIn, Direction facing, BlockState facingState, IWorld worldIn,
BlockPos currentPos, BlockPos facingPos) {
((SchematicannonTileEntity) worldIn.getTileEntity(currentPos)).findInventories();
return stateIn;
}
@Override
public void onNeighborChange(BlockState state, IWorldReader world, BlockPos pos, BlockPos neighbor) {
((SchematicannonTileEntity) world.getTileEntity(pos)).findInventories();
super.onNeighborChange(state, world, pos, neighbor);
}
}

View file

@ -1,48 +1,155 @@
package com.simibubi.create.block;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.ServerSchematicLoader;
import com.simibubi.create.schematic.Cuboid;
import com.simibubi.create.schematic.SchematicWorld;
import com.simibubi.create.utility.TileEntitySynced;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.gen.feature.template.PlacementSettings;
import net.minecraft.world.gen.feature.template.Template;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
public class SchematicannonTileEntity extends TileEntitySynced implements ITickableTileEntity {
private int test = 0;
public static final int PLACEMENT_DELAY = 2;
private SchematicWorld reader;
private BlockPos currentPos;
public BlockPos anchor;
public String schematicToPrint;
public boolean missingBlock;
public List<IItemHandler> attachedInventories;
private int cooldown;
public SchematicannonTileEntity() {
super(AllTileEntities.Schematicannon.type);
this(AllTileEntities.Schematicannon.type);
}
public SchematicannonTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
attachedInventories = new LinkedList<>();
}
public void findInventories() {
for (Direction facing : Direction.values()) {
TileEntity tileEntity = world.getTileEntity(pos.offset(facing));
if (tileEntity != null) {
LazyOptional<IItemHandler> capability = tileEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, facing.getOpposite());
if (capability.isPresent()) {
attachedInventories.add(capability.orElse(null));
}
}
}
}
@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++;
if (world.isRemote)
return;
if (schematicToPrint == null)
return;
if (cooldown-- > 0)
return;
cooldown = PLACEMENT_DELAY;
if (reader == null) {
currentPos = BlockPos.ZERO;
currentPos = currentPos.offset(Direction.WEST);
String filepath = ServerSchematicLoader.PATH + "/" + schematicToPrint;
Template activeTemplate = new Template();
InputStream stream = null;
try {
stream = Files.newInputStream(Paths.get(filepath), StandardOpenOption.READ);
CompoundNBT nbt = CompressedStreamTools.readCompressed(stream);
activeTemplate.read(nbt);
reader = new SchematicWorld(new HashMap<>(), new Cuboid(BlockPos.ZERO, 0, 0, 0), anchor);
activeTemplate.addBlocksToWorld(reader, anchor, new PlacementSettings());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (stream != null)
IOUtils.closeQuietly(stream);
}
return;
}
BlockPos size = reader.getBounds().getSize();
BlockState state;
do {
if (!missingBlock)
currentPos = currentPos.offset(Direction.EAST);
if (currentPos.getX() > size.getX()) {
currentPos = new BlockPos(0, currentPos.getY(), currentPos.getZ() + 1);
}
if (currentPos.getZ() > size.getZ()) {
currentPos = new BlockPos(currentPos.getX(), currentPos.getY() + 1, 0);
}
if (currentPos.getY() > size.getY()) {
schematicToPrint = null;
currentPos = null;
anchor = null;
reader = null;
missingBlock = false;
return;
}
state = reader.getBlockState(anchor.add(currentPos));
} while (state.getBlock() == Blocks.AIR);
missingBlock = true;
ItemStack requiredItem = new ItemStack(BlockItem.BLOCK_TO_ITEM.getOrDefault(state.getBlock(), Items.AIR));
for (IItemHandler iItemHandler : attachedInventories) {
for (int slot = 0; slot < iItemHandler.getSlots(); slot++) {
ItemStack stackInSlot = iItemHandler.getStackInSlot(slot);
if (!stackInSlot.isItemEqual(requiredItem))
continue;
iItemHandler.extractItem(slot, 1, false);
world.setBlockState(currentPos.add(anchor), state);
missingBlock = false;
return;
}
}
}
}

View file

@ -25,8 +25,6 @@ public class SchematicTableScreen extends ContainerScreen<SchematicTableContaine
private SimiButton button;
private DynamicLabel label;
private boolean isUploading;
private String uploadingSchematic;
private float progress;
private float lastProgress;
@ -75,7 +73,10 @@ public class SchematicTableScreen extends ContainerScreen<SchematicTableContaine
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);
if (container.isUploading)
font.drawString("Uploading...", xMainWindow + 76, yMainWindow + 10, GuiResources.FONT_COLOR);
else
font.drawString("Choose a Schematic", xMainWindow + 50, yMainWindow + 10, GuiResources.FONT_COLOR);
font.drawString("Inventory", x + 7, y + 26, 0x666666);
if (schematics == null) {
@ -111,9 +112,17 @@ public class SchematicTableScreen extends ContainerScreen<SchematicTableContaine
@Override
public void tick() {
super.tick();
if (isUploading) {
if (container.isUploading) {
lastProgress = progress;
progress = Create.cSchematicLoader.getProgress(uploadingSchematic);
progress = Create.cSchematicLoader.getProgress(container.schematicUploading);
label.colored(0xCCDDFF);
button.active = false;
} else {
progress = 0;
lastProgress = 0;
label.colored(0xFFFFFF);
button.active = true;
}
}
@ -126,9 +135,8 @@ public class SchematicTableScreen extends ContainerScreen<SchematicTableContaine
List<String> availableSchematics = Create.cSchematicLoader.getAvailableSchematics();
lastProgress = progress = 0;
uploadingSchematic = availableSchematics.get(schematics.getState());
isUploading = true;
Create.cSchematicLoader.startNewUpload(uploadingSchematic);
String schematic = availableSchematics.get(schematics.getState());
Create.cSchematicLoader.startNewUpload(schematic);
}
return super.mouseClicked(p_mouseClicked_1_, p_mouseClicked_3_, p_mouseClicked_5_);

View file

@ -0,0 +1,102 @@
package com.simibubi.create.item;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import org.apache.commons.io.IOUtils;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.block.SchematicannonTileEntity;
import com.simibubi.create.schematic.SchematicHologram;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template;
public class ItemBlueprint extends Item {
public ItemBlueprint(Properties properties) {
super(properties.maxStackSize(1));
}
@Override
public ActionResultType onItemUse(ItemUseContext context) {
World world = context.getWorld();
CompoundNBT tag = context.getItem().getTag();
if (tag.contains("File")) {
BlockPos pos = context.getPos();
BlockState blockState = world.getBlockState(pos);
if (AllBlocks.SCHEMATICANNON.typeOf(blockState)) {
if (world.isRemote) {
SchematicHologram.reset();
return ActionResultType.SUCCESS;
}
if (!tag.contains("Anchor"))
return ActionResultType.FAIL;
SchematicannonTileEntity te = (SchematicannonTileEntity) world.getTileEntity(pos);
te.schematicToPrint = tag.getString("Owner") + "/" + tag.getString("File");
te.anchor = NBTUtil.readBlockPos(tag.getCompound("Anchor"));
context.getPlayer().setItemStackToSlot(EquipmentSlotType.MAINHAND, ItemStack.EMPTY);
return ActionResultType.SUCCESS;
}
tag.put("Anchor", NBTUtil.writeBlockPos(pos.offset(context.getFace())));
if (!world.isRemote) {
return ActionResultType.SUCCESS;
}
if (!(context.getPlayer().getName().getFormattedText().equals(tag.getString("Owner")))) {
context.getPlayer()
.sendStatusMessage(new StringTextComponent("You are not the Owner of this Schematic."), true);
}
String filepath = "schematics/" + tag.getString("File");
Template t = new Template();
InputStream stream = null;
try {
stream = Files.newInputStream(Paths.get(filepath), StandardOpenOption.READ);
CompoundNBT nbt = CompressedStreamTools.readCompressed(stream);
t.read(nbt);
new SchematicHologram().startHologram(t, pos.offset(context.getFace()));
} catch (IOException e) {
e.printStackTrace();
} finally {
if (stream != null)
IOUtils.closeQuietly(stream);
}
}
context.getPlayer().getCooldownTracker().setCooldown(this, 10);
return ActionResultType.SUCCESS;
}
@Override
public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand handIn) {
return super.onItemRightClick(worldIn, playerIn, handIn);
}
}

View file

@ -0,0 +1,48 @@
package com.simibubi.create.networking;
import java.util.function.Supplier;
import com.simibubi.create.block.SchematicTableContainer;
import net.minecraft.client.Minecraft;
import net.minecraft.inventory.container.Container;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.network.NetworkEvent.Context;
public class PacketSchematicTableContainer {
public String schematic;
public float progress;
public PacketSchematicTableContainer(String schematicToUpload, float progress) {
this.schematic = schematicToUpload;
if (this.schematic == null)
this.schematic = "";
this.progress = progress;
}
public PacketSchematicTableContainer(PacketBuffer buffer) {
this.schematic = buffer.readString();
this.progress = buffer.readFloat();
}
public void toBytes(PacketBuffer buffer) {
buffer.writeString(schematic);
buffer.writeFloat(progress);
}
@OnlyIn(Dist.CLIENT)
public void handle(Supplier<Context> context) {
context.get().enqueueWork(() -> {
Container c = Minecraft.getInstance().player.openContainer;
if (c != null && c instanceof SchematicTableContainer) {
((SchematicTableContainer) c).receiveSchematicInfo(schematic, progress);
}
});
}
}

View file

@ -13,16 +13,17 @@ public class Packets {
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);
channel.registerMessage(i++, PacketNbt.class, PacketNbt::toBytes, PacketNbt::new, PacketNbt::handle);
channel.registerMessage(i++, PacketSchematicTableContainer.class, PacketSchematicTableContainer::toBytes,
PacketSchematicTableContainer::new, PacketSchematicTableContainer::handle);
channel.registerMessage(i++, PacketSchematicUpload.class, PacketSchematicUpload::toBytes,
PacketSchematicUpload::new, PacketSchematicUpload::handle);
channel.registerMessage(i++, PacketSymmetryEffect.class, PacketSymmetryEffect::toBytes,
PacketSymmetryEffect::new, PacketSymmetryEffect::handle);
}
}

View file

@ -0,0 +1,71 @@
package com.simibubi.create.schematic;
import net.minecraft.util.math.BlockPos;
public class Cuboid {
public int x;
public int y;
public int z;
public int width;
public int height;
public int length;
public Cuboid(BlockPos origin, BlockPos size) {
this(origin, size.getX(), size.getY(), size.getZ());
}
public Cuboid(BlockPos origin, int width, int height, int length) {
this.x = origin.getX() + ((width < 0) ? width : 0);
this.y = origin.getY() + ((height < 0) ? height : 0);
this.z = origin.getZ() + ((length < 0) ? length : 0);
this.width = Math.abs(width);
this.height = Math.abs(height);
this.length = Math.abs(length);
}
public BlockPos getOrigin() {
return new BlockPos(x, y, z);
}
public BlockPos getSize() {
return new BlockPos(width, height, length);
}
public Cuboid clone() {
return new Cuboid(new BlockPos(x, y, z), width, height, length);
}
public void move(int x, int y, int z) {
this.x += x;
this.y += y;
this.z += z;
}
public void centerHorizontallyOn(BlockPos pos) {
x = pos.getX() - (width / 2);
y = pos.getY();
z = pos.getZ() - (length / 2);
}
public boolean intersects(Cuboid other) {
return !(other.x >= x + width || other.z >= z + length || other.x + other.width <= x
|| other.z + other.length <= z);
}
public boolean contains(BlockPos pos) {
return (pos.getX() >= x && pos.getX() < x + width) && (pos.getY() >= y && pos.getY() < y + height)
&& (pos.getZ() >= z && pos.getZ() < z + length);
}
public BlockPos getCenter() {
return getOrigin().add(width / 2, height / 2, length / 2);
}
@Override
public boolean equals(Object obj) {
return obj instanceof Cuboid && ((Cuboid) obj).getOrigin().equals(getOrigin())
&& ((Cuboid) obj).getSize().equals(getSize());
}
}

View file

@ -0,0 +1,210 @@
package com.simibubi.create.schematic;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.lwjgl.opengl.GL11;
import com.mojang.blaze3d.platform.GlStateManager;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ActiveRenderInfo;
import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.RegionRenderCacheBuilder;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.client.renderer.vertex.VertexFormatElement.Usage;
import net.minecraft.entity.Entity;
import net.minecraft.util.BlockRenderLayer;
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.api.distmarker.Dist;
import net.minecraftforge.client.ForgeHooksClient;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent;
@EventBusSubscriber(Dist.CLIENT)
public class SchematicHologram {
// These buffers are large enough for an entire chunk, consider using
// smaller buffers
private static final RegionRenderCacheBuilder bufferCache = new RegionRenderCacheBuilder();
private static final boolean[] usedBlockRenderLayers = new boolean[BlockRenderLayer.values().length];
private static final boolean[] startedBufferBuilders = new boolean[BlockRenderLayer.values().length];
private static SchematicHologram instance;
private boolean active;
private boolean changed;
private SchematicWorld schematic;
private BlockPos anchor;
public SchematicHologram() {
instance = this;
changed = false;
}
public void startHologram(Template schematic, BlockPos anchor) {
this.schematic = new SchematicWorld(new HashMap<>(), new Cuboid(BlockPos.ZERO, BlockPos.ZERO), anchor);
this.anchor = anchor;
schematic.addBlocksToWorld(this.schematic, anchor, new PlacementSettings());
active = true;
changed = true;
}
public static SchematicHologram getInstance() {
return instance;
}
// public static void display(Schematic schematic) {
// instance = new SchematicHologram();
// instance.startHologram(schematic);
// }
public static void reset() {
instance = null;
}
public void schematicChanged() {
changed = true;
}
@SubscribeEvent
public static void onClientTickEvent(final ClientTickEvent event) {
if (instance != null && instance.active) {
final Minecraft minecraft = Minecraft.getInstance();
if (event.phase != TickEvent.Phase.END)
return;
if (minecraft.world == null)
return;
if (minecraft.player == null)
return;
if (instance.changed) {
redraw(minecraft);
instance.changed = false;
}
}
}
private static void redraw(final Minecraft minecraft) {
Arrays.fill(usedBlockRenderLayers, false);
Arrays.fill(startedBufferBuilders, false);
final SchematicWorld blockAccess = instance.schematic;
final BlockRendererDispatcher blockRendererDispatcher = minecraft.getBlockRendererDispatcher();
List<BlockState> blockstates = new LinkedList<>();
for (BlockPos localPos : BlockPos.getAllInBoxMutable(blockAccess.getBounds().getOrigin(),
blockAccess.getBounds().getOrigin().add(blockAccess.getBounds().getSize()))) {
BlockPos pos = localPos.add(instance.anchor);
final BlockState state = blockAccess.getBlockState(pos);
for (BlockRenderLayer blockRenderLayer : BlockRenderLayer.values()) {
if (!state.getBlock().canRenderInLayer(state, blockRenderLayer)) {
continue;
}
ForgeHooksClient.setRenderLayer(blockRenderLayer);
final int blockRenderLayerId = blockRenderLayer.ordinal();
final BufferBuilder bufferBuilder = bufferCache.getBuilder(blockRenderLayerId);
if (!startedBufferBuilders[blockRenderLayerId]) {
startedBufferBuilders[blockRenderLayerId] = true;
// Copied from RenderChunk
{
bufferBuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
}
}
// OptiFine Shaders compatibility
// if (Config.isShaders()) SVertexBuilder.pushEntity(state, pos,
// blockAccess, bufferBuilder);
usedBlockRenderLayers[blockRenderLayerId] |= blockRendererDispatcher.renderBlock(state, pos,
blockAccess, bufferBuilder, minecraft.world.rand, EmptyModelData.INSTANCE);
blockstates.add(state);
// if (Config.isShaders())
// SVertexBuilder.popEntity(bufferBuilder);
}
ForgeHooksClient.setRenderLayer(null);
}
// finishDrawing
for (int blockRenderLayerId = 0; blockRenderLayerId < usedBlockRenderLayers.length; blockRenderLayerId++) {
if (!startedBufferBuilders[blockRenderLayerId]) {
continue;
}
bufferCache.getBuilder(blockRenderLayerId).finishDrawing();
}
}
@SubscribeEvent
public static void onRenderWorldLastEvent(final RenderWorldLastEvent event) {
if (instance != null && instance.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;
GlStateManager.enableAlphaTest();
GlStateManager.enableBlend();
Minecraft.getInstance().getTextureManager().bindTexture(AtlasTexture.LOCATION_BLOCKS_TEXTURE);
for (int blockRenderLayerId = 0; blockRenderLayerId < usedBlockRenderLayers.length; blockRenderLayerId++) {
if (!usedBlockRenderLayers[blockRenderLayerId]) {
continue;
}
final BufferBuilder bufferBuilder = bufferCache.getBuilder(blockRenderLayerId);
GlStateManager.pushMatrix();
GlStateManager.translated(-renderPosX, -renderPosY, -renderPosZ);
drawBuffer(bufferBuilder);
GlStateManager.popMatrix();
}
GlStateManager.disableAlphaTest();
GlStateManager.disableBlend();
}
}
// Coppied from the Tesselator's vboUploader - Draw everything but don't
// reset the buffer
private static void drawBuffer(final BufferBuilder bufferBuilder) {
if (bufferBuilder.getVertexCount() > 0) {
VertexFormat vertexformat = bufferBuilder.getVertexFormat();
int size = vertexformat.getSize();
ByteBuffer bytebuffer = bufferBuilder.getByteBuffer();
List<VertexFormatElement> list = vertexformat.getElements();
for (int index = 0; index < list.size(); ++index) {
VertexFormatElement vertexformatelement = list.get(index);
Usage usage = vertexformatelement.getUsage();
bytebuffer.position(vertexformat.getOffset(index));
usage.preDraw(vertexformat, index, size, bytebuffer);
}
GlStateManager.drawArrays(bufferBuilder.getDrawMode(), 0, bufferBuilder.getVertexCount());
for (int index = 0; index < list.size(); ++index) {
VertexFormatElement vertexformatelement = list.get(index);
Usage usage = vertexformatelement.getUsage();
usage.postDraw(vertexformat, index, size, bytebuffer);
}
}
}
}

View file

@ -0,0 +1,282 @@
package com.simibubi.create.schematic;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.function.Predicate;
import com.google.common.collect.ImmutableMap;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.particles.IParticleData;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.EmptyTickList;
import net.minecraft.world.ITickList;
import net.minecraft.world.IWorld;
import net.minecraft.world.LightType;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.Biomes;
import net.minecraft.world.border.WorldBorder;
import net.minecraft.world.chunk.AbstractChunkProvider;
import net.minecraft.world.chunk.ChunkStatus;
import net.minecraft.world.chunk.IChunk;
import net.minecraft.world.dimension.Dimension;
import net.minecraft.world.gen.Heightmap.Type;
import net.minecraft.world.storage.WorldInfo;
public class SchematicWorld implements IWorld {
private Map<BlockPos, BlockState> blocks;
private Cuboid bounds;
private BlockPos anchor;
public SchematicWorld(Map<BlockPos, BlockState> blocks, Cuboid bounds, BlockPos anchor) {
this.blocks = blocks;
this.setBounds(bounds);
this.anchor = anchor;
updateBlockstates();
}
private void updateBlockstates() {
Set<BlockPos> keySet = new HashSet<>(blocks.keySet());
keySet.forEach(pos -> {
BlockState blockState = blocks.get(pos);
if (blockState == null)
return;
blockState.updateNeighbors(this, pos.add(anchor), 16);
});
}
public Set<BlockPos> getAllPositions() {
return blocks.keySet();
}
@Override
public TileEntity getTileEntity(BlockPos pos) {
return null;
}
@Override
public BlockState getBlockState(BlockPos globalPos) {
BlockPos pos = globalPos.subtract(anchor);
if (getBounds().contains(pos) && blocks.containsKey(pos)) {
return blocks.get(pos);
} else {
return Blocks.AIR.getDefaultState();
}
}
public Map<BlockPos, BlockState> getBlockMap() {
return blocks;
}
@Override
public IFluidState getFluidState(BlockPos pos) {
return new FluidState(Fluids.EMPTY, ImmutableMap.of());
}
@Override
public Biome getBiome(BlockPos pos) {
return Biomes.THE_VOID;
}
@Override
public int getLightFor(LightType type, BlockPos pos) {
return 10;
}
@Override
public List<Entity> getEntitiesInAABBexcluding(Entity arg0, AxisAlignedBB arg1, Predicate<? super Entity> arg2) {
return Collections.emptyList();
}
@Override
public <T extends Entity> List<T> getEntitiesWithinAABB(Class<? extends T> arg0, AxisAlignedBB arg1,
Predicate<? super T> arg2) {
return Collections.emptyList();
}
@Override
public List<? extends PlayerEntity> getPlayers() {
return Collections.emptyList();
}
@Override
public int getLightSubtracted(BlockPos pos, int amount) {
return 0;
}
@Override
public IChunk getChunk(int x, int z, ChunkStatus requiredStatus, boolean nonnull) {
return null;
}
@Override
public BlockPos getHeight(Type heightmapType, BlockPos pos) {
return BlockPos.ZERO;
}
@Override
public int getHeight(Type heightmapType, int x, int z) {
return 0;
}
@Override
public int getSkylightSubtracted() {
return 0;
}
@Override
public WorldBorder getWorldBorder() {
return null;
}
@Override
public boolean isRemote() {
return false;
}
@Override
public int getSeaLevel() {
return 0;
}
@Override
public Dimension getDimension() {
return null;
}
@Override
public boolean hasBlockState(BlockPos pos, Predicate<BlockState> predicate) {
return predicate.test(getBlockState(pos));
}
@Override
public boolean destroyBlock(BlockPos arg0, boolean arg1) {
return setBlockState(arg0, Blocks.AIR.getDefaultState(), 3);
}
@Override
public boolean removeBlock(BlockPos arg0, boolean arg1) {
return setBlockState(arg0, Blocks.AIR.getDefaultState(), 3);
}
@Override
public boolean setBlockState(BlockPos pos, BlockState arg1, int arg2) {
pos = pos.subtract(anchor);
if (pos.getX() < bounds.x) {
bounds.width += bounds.x - pos.getX();
bounds.x = pos.getX();
}
if (pos.getY() < bounds.y) {
bounds.height += bounds.y - pos.getY();
bounds.y = pos.getY();
}
if (pos.getZ() < bounds.z) {
bounds.length += bounds.z - pos.getZ();
bounds.z = pos.getZ();
}
BlockPos boundsMax = bounds.getOrigin().add(bounds.getSize());
if (boundsMax.getX() <= pos.getX()) {
bounds.width += pos.getX() - boundsMax.getX() + 1;
}
if (boundsMax.getY() <= pos.getY()) {
bounds.height += pos.getY() - boundsMax.getY() + 1;
}
if (boundsMax.getZ() <= pos.getZ()) {
bounds.length += pos.getZ() - boundsMax.getZ() + 1;
}
blocks.put(pos, arg1);
return true;
}
@Override
public long getSeed() {
return 0;
}
@Override
public ITickList<Block> getPendingBlockTicks() {
return EmptyTickList.get();
}
@Override
public ITickList<Fluid> getPendingFluidTicks() {
return EmptyTickList.get();
}
@Override
public World getWorld() {
return null;
}
@Override
public WorldInfo getWorldInfo() {
return null;
}
@Override
public DifficultyInstance getDifficultyForLocation(BlockPos pos) {
return null;
}
@Override
public AbstractChunkProvider getChunkProvider() {
return null;
}
@Override
public Random getRandom() {
return new Random();
}
@Override
public void notifyNeighbors(BlockPos pos, Block blockIn) {
}
@Override
public BlockPos getSpawnPoint() {
return null;
}
@Override
public void playSound(PlayerEntity player, BlockPos pos, SoundEvent soundIn, SoundCategory category, float volume,
float pitch) {
}
@Override
public void addParticle(IParticleData particleData, double x, double y, double z, double xSpeed, double ySpeed,
double zSpeed) {
}
@Override
public void playEvent(PlayerEntity player, int type, BlockPos pos, int data) {
}
public Cuboid getBounds() {
return bounds;
}
public void setBounds(Cuboid bounds) {
this.bounds = bounds;
}
}