diff --git a/src/main/java/com/simibubi/create/content/schematics/SchematicProcessor.java b/src/main/java/com/simibubi/create/content/schematics/SchematicProcessor.java new file mode 100644 index 000000000..f6d1a61d3 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/schematics/SchematicProcessor.java @@ -0,0 +1,59 @@ +package com.simibubi.create.content.schematics; + +import com.mojang.datafixers.Dynamic; +import com.mojang.datafixers.types.DynamicOps; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorldReader; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.IStructureProcessorType; +import net.minecraft.world.gen.feature.template.PlacementSettings; +import net.minecraft.world.gen.feature.template.StructureProcessor; +import net.minecraft.world.gen.feature.template.Template; + +import javax.annotation.Nullable; +import java.util.Optional; + +public class SchematicProcessor extends StructureProcessor { + public static final SchematicProcessor INSTANCE = new SchematicProcessor(); + + @Nullable + @Override + public Template.BlockInfo process(IWorldReader world, BlockPos pos, Template.BlockInfo rawInfo, Template.BlockInfo info, PlacementSettings settings, @Nullable Template template) { + if (info.nbt != null) { + TileEntity te = info.state.createTileEntity(world); + if (te != null && te.onlyOpsCanSetNbt()) { + return new Template.BlockInfo(info.pos, info.state, null); + } + } + return info; + } + + @Nullable + @Override + public Template.EntityInfo processEntity(IWorldReader world, BlockPos pos, Template.EntityInfo rawInfo, Template.EntityInfo info, PlacementSettings settings, Template template) { + return EntityType.readEntityType(info.nbt) + .flatMap(type -> { + if (world instanceof World) { + Entity e = type.create((World) world); + if (e != null && !e.ignoreItemEntityData()) { + return Optional.of(info); + } + } + return Optional.empty(); + }) + .orElse(null); + } + + @Override + protected IStructureProcessorType getType() { + return dynamic -> INSTANCE; + } + + @Override + protected Dynamic serialize0(DynamicOps ops) { + return new Dynamic<>(ops, ops.emptyMap()); + } +} diff --git a/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java b/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java index 8c8e117fa..743cc5a3b 100644 --- a/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java +++ b/src/main/java/com/simibubi/create/content/schematics/ServerSchematicLoader.java @@ -91,10 +91,8 @@ public class ServerSchematicLoader { } public void handleNewUpload(ServerPlayerEntity player, String schematic, long size, BlockPos pos) { - String playerPath = getSchematicPath() + "/" + player.getName() - .getFormattedText(); - String playerSchematicId = player.getName() - .getFormattedText() + "/" + schematic; + String playerPath = getSchematicPath() + "/" + player.getGameProfile().getName(); + String playerSchematicId = player.getGameProfile().getName() + "/" + schematic; FilesHelper.createFolderIfMissing(playerPath); // Unsupported Format @@ -103,6 +101,14 @@ public class ServerSchematicLoader { return; } + Path playerSchematicsPath = Paths.get(getSchematicPath(), player.getGameProfile().getName()).toAbsolutePath(); + + Path uploadPath = playerSchematicsPath.resolve(schematic).normalize(); + if (!uploadPath.startsWith(playerSchematicsPath)) { + Create.logger.warn("Attempted Schematic Upload with directory escape: {}", playerSchematicId); + return; + } + // Too big if (!validateSchematicSizeOnServer(player, size)) return; @@ -118,11 +124,15 @@ public class ServerSchematicLoader { return; // Delete schematic with same name - Files.deleteIfExists(Paths.get(getSchematicPath(), playerSchematicId)); + Files.deleteIfExists(uploadPath); // Too many Schematics - Stream list = Files.list(Paths.get(playerPath)); - if (list.count() >= getConfig().maxSchematics.get()) { + long count; + try (Stream list = Files.list(Paths.get(playerPath))) { + count = list.count(); + } + + if (count >= getConfig().maxSchematics.get()) { Stream list2 = Files.list(Paths.get(playerPath)); Optional lastFilePath = list2.filter(f -> !Files.isDirectory(f)) .min(Comparator.comparingLong(f -> f.toFile() @@ -132,11 +142,9 @@ public class ServerSchematicLoader { Files.deleteIfExists(lastFilePath.get()); } } - list.close(); // Open Stream - OutputStream writer = - Files.newOutputStream(Paths.get(getSchematicPath(), playerSchematicId), StandardOpenOption.CREATE_NEW); + OutputStream writer = Files.newOutputStream(uploadPath); activeUploads.put(playerSchematicId, new SchematicUploadEntry(writer, size, player.getServerWorld(), pos)); // Notify Tile Entity @@ -165,8 +173,7 @@ public class ServerSchematicLoader { } public void handleWriteRequest(ServerPlayerEntity player, String schematic, byte[] data) { - String playerSchematicId = player.getName() - .getFormattedText() + "/" + schematic; + String playerSchematicId = player.getGameProfile().getName() + "/" + schematic; if (activeUploads.containsKey(playerSchematicId)) { SchematicUploadEntry entry = activeUploads.get(playerSchematicId); @@ -236,8 +243,7 @@ public class ServerSchematicLoader { } public void handleFinishedUpload(ServerPlayerEntity player, String schematic) { - String playerSchematicId = player.getName() - .getFormattedText() + "/" + schematic; + String playerSchematicId = player.getGameProfile().getName() + "/" + schematic; if (activeUploads.containsKey(playerSchematicId)) { try { @@ -258,8 +264,7 @@ public class ServerSchematicLoader { if (table == null) return; table.finishUpload(); - table.inventory.setStackInSlot(1, SchematicItem.create(schematic, player.getName() - .getFormattedText())); + table.inventory.setStackInSlot(1, SchematicItem.create(schematic, player.getGameProfile().getName())); } catch (IOException e) { Create.logger.error("Exception Thrown when finishing Upload: " + playerSchematicId); @@ -270,15 +275,21 @@ public class ServerSchematicLoader { public void handleInstantSchematic(ServerPlayerEntity player, String schematic, World world, BlockPos pos, BlockPos bounds) { - String playerPath = getSchematicPath() + "/" + player.getName() - .getFormattedText(); - String playerSchematicId = player.getName() - .getFormattedText() + "/" + schematic; + String playerPath = getSchematicPath() + "/" + player.getGameProfile().getName(); + String playerSchematicId = player.getGameProfile().getName() + "/" + schematic; FilesHelper.createFolderIfMissing(playerPath); // Unsupported Format if (!schematic.endsWith(".nbt")) { - Create.logger.warn("Attempted Schematic Upload with non-supported Format: " + playerSchematicId); + Create.logger.warn("Attempted Schematic Upload with non-supported Format: {}", playerSchematicId); + return; + } + + Path schematicPath = Paths.get(getSchematicPath()).toAbsolutePath(); + + Path path = schematicPath.resolve(playerSchematicId).normalize(); + if (!path.startsWith(schematicPath)) { + Create.logger.warn("Attempted Schematic Upload with directory escape: {}", playerSchematicId); return; } @@ -288,38 +299,34 @@ public class ServerSchematicLoader { try { // Delete schematic with same name - Path path = Paths.get(getSchematicPath(), playerSchematicId); Files.deleteIfExists(path); // Too many Schematics - Stream list = Files.list(Paths.get(playerPath)); - if (list.count() >= getConfig().maxSchematics.get()) { + long count; + try (Stream list = Files.list(Paths.get(playerPath))) { + count = list.count(); + } + + if (count >= getConfig().maxSchematics.get()) { Stream list2 = Files.list(Paths.get(playerPath)); Optional lastFilePath = list2.filter(f -> !Files.isDirectory(f)) .min(Comparator.comparingLong(f -> f.toFile() .lastModified())); list2.close(); - if (lastFilePath.isPresent()) + if (lastFilePath.isPresent()) Files.deleteIfExists(lastFilePath.get()); } - list.close(); Template t = new Template(); t.takeBlocksFromWorld(world, pos, bounds, true, Blocks.AIR); - OutputStream outputStream = null; - try { - outputStream = Files.newOutputStream(path, StandardOpenOption.CREATE); + try (OutputStream outputStream = Files.newOutputStream(path)) { CompoundNBT nbttagcompound = t.writeToNBT(new CompoundNBT()); CompressedStreamTools.writeCompressed(nbttagcompound, outputStream); - player.setHeldItem(Hand.MAIN_HAND, SchematicItem.create(schematic, player.getName() - .getFormattedText())); + player.setHeldItem(Hand.MAIN_HAND, SchematicItem.create(schematic, player.getGameProfile().getName())); } catch (IOException e) { e.printStackTrace(); - } finally { - if (outputStream != null) - IOUtils.closeQuietly(outputStream); } } catch (IOException e) { Create.logger.error("Exception Thrown in direct Schematic Upload: " + playerSchematicId); diff --git a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java index acfd3d176..2747e3897 100644 --- a/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java +++ b/src/main/java/com/simibubi/create/content/schematics/block/SchematicannonScreen.java @@ -422,8 +422,7 @@ public class SchematicannonScreen extends AbstractSimiContainerScreen context) { context.get().enqueueWork(() -> { ServerPlayerEntity player = context.get().getSender(); - if (player == null) - return; - World world = player.world; - if (world == null || !world.isBlockPresent(pos)) + if (player == null || !(player.openContainer instanceof SchematicannonContainer)) return; - TileEntity tileEntity = world.getTileEntity(pos); - if (!(tileEntity instanceof SchematicannonTileEntity)) - return; - - SchematicannonTileEntity te = (SchematicannonTileEntity) tileEntity; + SchematicannonTileEntity te = ((SchematicannonContainer) player.openContainer).getTileEntity(); switch (option) { case DONT_REPLACE: case REPLACE_ANY: diff --git a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java index 94222fb36..cbb4345bf 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -38,47 +38,51 @@ import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.minecraftforge.fml.network.NetworkDirection; import net.minecraftforge.fml.network.NetworkEvent.Context; import net.minecraftforge.fml.network.NetworkRegistry; import net.minecraftforge.fml.network.PacketDistributor; import net.minecraftforge.fml.network.PacketDistributor.TargetPoint; import net.minecraftforge.fml.network.simple.SimpleChannel; +import static net.minecraftforge.fml.network.NetworkDirection.PLAY_TO_SERVER; +import static net.minecraftforge.fml.network.NetworkDirection.PLAY_TO_CLIENT; + public enum AllPackets { // Client to Server - NBT(NbtPacket.class, NbtPacket::new), - CONFIGURE_SCHEMATICANNON(ConfigureSchematicannonPacket.class, ConfigureSchematicannonPacket::new), - CONFIGURE_FLEXCRATE(ConfigureFlexcratePacket.class, ConfigureFlexcratePacket::new), - CONFIGURE_STOCKSWITCH(ConfigureStockswitchPacket.class, ConfigureStockswitchPacket::new), - CONFIGURE_SEQUENCER(ConfigureSequencedGearshiftPacket.class, ConfigureSequencedGearshiftPacket::new), - PLACE_SCHEMATIC(SchematicPlacePacket.class, SchematicPlacePacket::new), - UPLOAD_SCHEMATIC(SchematicUploadPacket.class, SchematicUploadPacket::new), - CONFIGURE_FILTER(FilterScreenPacket.class, FilterScreenPacket::new), - CONFIGURE_FILTERING_AMOUNT(FilteringCountUpdatePacket.class, FilteringCountUpdatePacket::new), - CONFIGURE_SCROLLABLE(ScrollValueUpdatePacket.class, ScrollValueUpdatePacket::new), - EXTENDO_INTERACT(ExtendoGripInteractionPacket.class, ExtendoGripInteractionPacket::new), - CONTRAPTION_INTERACT(ContraptionInteractionPacket.class, ContraptionInteractionPacket::new), - CLIENT_MOTION(ClientMotionPacket.class, ClientMotionPacket::new), - PLACE_ARM(ArmPlacementPacket.class, ArmPlacementPacket::new), - MINECART_COUPLING_CREATION(CouplingCreationPacket.class, CouplingCreationPacket::new), - INSTANT_SCHEMATIC(InstantSchematicPacket.class, InstantSchematicPacket::new), - SYNC_SCHEMATIC(SchematicSyncPacket.class, SchematicSyncPacket::new), - LEFT_CLICK(LeftClickPacket.class, LeftClickPacket::new), + NBT(NbtPacket.class, NbtPacket::new, PLAY_TO_SERVER), + CONFIGURE_SCHEMATICANNON(ConfigureSchematicannonPacket.class, ConfigureSchematicannonPacket::new, PLAY_TO_SERVER), + CONFIGURE_FLEXCRATE(ConfigureFlexcratePacket.class, ConfigureFlexcratePacket::new, PLAY_TO_SERVER), + CONFIGURE_STOCKSWITCH(ConfigureStockswitchPacket.class, ConfigureStockswitchPacket::new, PLAY_TO_SERVER), + CONFIGURE_SEQUENCER(ConfigureSequencedGearshiftPacket.class, ConfigureSequencedGearshiftPacket::new, PLAY_TO_SERVER), + PLACE_SCHEMATIC(SchematicPlacePacket.class, SchematicPlacePacket::new, PLAY_TO_SERVER), + UPLOAD_SCHEMATIC(SchematicUploadPacket.class, SchematicUploadPacket::new, PLAY_TO_SERVER), + CONFIGURE_FILTER(FilterScreenPacket.class, FilterScreenPacket::new, PLAY_TO_SERVER), + CONFIGURE_FILTERING_AMOUNT(FilteringCountUpdatePacket.class, FilteringCountUpdatePacket::new, PLAY_TO_SERVER), + CONFIGURE_SCROLLABLE(ScrollValueUpdatePacket.class, ScrollValueUpdatePacket::new, PLAY_TO_SERVER), + EXTENDO_INTERACT(ExtendoGripInteractionPacket.class, ExtendoGripInteractionPacket::new, PLAY_TO_SERVER), + CONTRAPTION_INTERACT(ContraptionInteractionPacket.class, ContraptionInteractionPacket::new, PLAY_TO_SERVER), + CLIENT_MOTION(ClientMotionPacket.class, ClientMotionPacket::new, PLAY_TO_SERVER), + PLACE_ARM(ArmPlacementPacket.class, ArmPlacementPacket::new, PLAY_TO_SERVER), + MINECART_COUPLING_CREATION(CouplingCreationPacket.class, CouplingCreationPacket::new, PLAY_TO_SERVER), + INSTANT_SCHEMATIC(InstantSchematicPacket.class, InstantSchematicPacket::new, PLAY_TO_SERVER), + SYNC_SCHEMATIC(SchematicSyncPacket.class, SchematicSyncPacket::new, PLAY_TO_SERVER), + LEFT_CLICK(LeftClickPacket.class, LeftClickPacket::new, PLAY_TO_SERVER), // Server to Client - SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new), - SERVER_SPEED(ServerSpeedProvider.Packet.class, ServerSpeedProvider.Packet::new), - BEAM_EFFECT(ZapperBeamPacket.class, ZapperBeamPacket::new), - CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new), - CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new), - CONTRAPTION_DISASSEMBLE(ContraptionDisassemblyPacket.class, ContraptionDisassemblyPacket::new), - GLUE_EFFECT(GlueEffectPacket.class, GlueEffectPacket::new), - CONTRAPTION_SEAT_MAPPING(ContraptionSeatMappingPacket.class, ContraptionSeatMappingPacket::new), - LIMBSWING_UPDATE(LimbSwingUpdatePacket.class, LimbSwingUpdatePacket::new), - MINECART_CONTROLLER(MinecartControllerUpdatePacket.class, MinecartControllerUpdatePacket::new), - FLUID_SPLASH(FluidSplashPacket.class, FluidSplashPacket::new), - CONTRAPTION_FLUID(ContraptionFluidPacket.class, ContraptionFluidPacket::new), + SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT), + SERVER_SPEED(ServerSpeedProvider.Packet.class, ServerSpeedProvider.Packet::new, PLAY_TO_CLIENT), + BEAM_EFFECT(ZapperBeamPacket.class, ZapperBeamPacket::new, PLAY_TO_CLIENT), + CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_DISASSEMBLE(ContraptionDisassemblyPacket.class, ContraptionDisassemblyPacket::new, PLAY_TO_CLIENT), + GLUE_EFFECT(GlueEffectPacket.class, GlueEffectPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_SEAT_MAPPING(ContraptionSeatMappingPacket.class, ContraptionSeatMappingPacket::new, PLAY_TO_CLIENT), + LIMBSWING_UPDATE(LimbSwingUpdatePacket.class, LimbSwingUpdatePacket::new, PLAY_TO_CLIENT), + MINECART_CONTROLLER(MinecartControllerUpdatePacket.class, MinecartControllerUpdatePacket::new, PLAY_TO_CLIENT), + FLUID_SPLASH(FluidSplashPacket.class, FluidSplashPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_FLUID(ContraptionFluidPacket.class, ContraptionFluidPacket::new, PLAY_TO_CLIENT), ; @@ -88,14 +92,14 @@ public enum AllPackets { private LoadedPacket packet; - private AllPackets(Class type, Function factory) { - packet = new LoadedPacket<>(type, factory); + private AllPackets(Class type, Function factory, NetworkDirection direction) { + packet = new LoadedPacket<>(type, factory, direction); } public static void registerPackets() { channel = NetworkRegistry.ChannelBuilder.named(CHANNEL_NAME) - .serverAcceptedVersions(s -> true) - .clientAcceptedVersions(s -> true) + .serverAcceptedVersions(NETWORK_VERSION::equals) + .clientAcceptedVersions(NETWORK_VERSION::equals) .networkProtocolVersion(() -> NETWORK_VERSION) .simpleChannel(); for (AllPackets packet : values()) @@ -115,16 +119,18 @@ public enum AllPackets { Function decoder; BiConsumer> handler; Class type; + NetworkDirection direction; - private LoadedPacket(Class type, Function factory) { + private LoadedPacket(Class type, Function factory, NetworkDirection direction) { encoder = T::write; decoder = factory; handler = T::handle; this.type = type; + this.direction = direction; } private void register() { - channel.messageBuilder(type, index++) + channel.messageBuilder(type, index++, direction) .encoder(encoder) .decoder(decoder) .consumer(handler) diff --git a/src/main/java/com/simibubi/create/foundation/utility/FilesHelper.java b/src/main/java/com/simibubi/create/foundation/utility/FilesHelper.java index 67bc3f1fa..e59a45521 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/FilesHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/FilesHelper.java @@ -21,17 +21,10 @@ import net.minecraft.nbt.CompoundNBT; public class FilesHelper { public static void createFolderIfMissing(String name) { - Path path = Paths.get(name); - if (path.getParent() != null) - createFolderIfMissing(path.getParent() - .toString()); - - if (!Files.isDirectory(path)) { - try { - Files.createDirectory(path); - } catch (IOException e) { - Create.logger.warn("Could not create Folder: " + name); - } + try { + Files.createDirectories(Paths.get(name)); + } catch (IOException e) { + Create.logger.warn("Could not create Folder: {}", name); } }