mirror of
https://github.com/Creators-of-Create/Create.git
synced 2025-01-28 22:05:01 +01:00
Schematic Caching
Currently schematics are always reuploaded even if they already exist on the server, these changes make it so if they already exist on the server, a schematic pointing towards that is made instead of requiring a full reupload.
This commit is contained in:
parent
aa15182005
commit
5d2c8f281c
6 changed files with 113 additions and 24 deletions
|
@ -2,6 +2,8 @@ package com.simibubi.create;
|
|||
|
||||
import java.util.Random;
|
||||
|
||||
import net.minecraftforge.fml.loading.FMLLoader;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
@ -152,6 +154,9 @@ public class Create {
|
|||
|
||||
// FIXME: this is not thread-safe
|
||||
Mods.CURIOS.executeIfInstalled(() -> () -> Curios.init(modEventBus, forgeEventBus));
|
||||
|
||||
if (FMLLoader.getDist().isDedicatedServer())
|
||||
SCHEMATIC_RECEIVER.computeHashes();
|
||||
}
|
||||
|
||||
public static void init(final FMLCommonSetupEvent event) {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
package com.simibubi.create.content.schematics;
|
||||
|
||||
public record SchematicFile(String playerName, String schematicName) {}
|
|
@ -57,6 +57,10 @@ public class SchematicItem extends Item {
|
|||
super(properties);
|
||||
}
|
||||
|
||||
public static ItemStack create(HolderGetter<Block> lookup, SchematicFile schematicFile) {
|
||||
return create(lookup, schematicFile.schematicName(), schematicFile.playerName());
|
||||
}
|
||||
|
||||
public static ItemStack create(HolderGetter<Block> lookup, String schematic, String owner) {
|
||||
ItemStack blueprint = AllItems.SCHEMATIC.asStack();
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package com.simibubi.create.content.schematics;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
@ -24,21 +27,27 @@ import com.simibubi.create.foundation.utility.Lang;
|
|||
import com.simibubi.create.infrastructure.config.AllConfigs;
|
||||
import com.simibubi.create.infrastructure.config.CSchematics;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ServerSchematicLoader {
|
||||
|
||||
private Map<String, SchematicUploadEntry> activeUploads;
|
||||
private Map<String, SchematicUploadEntry> activeUploads = new HashMap<>();
|
||||
|
||||
public class SchematicUploadEntry {
|
||||
private Map<String, SchematicFile> sumToSchematic = new Object2ReferenceOpenHashMap<>();
|
||||
|
||||
public static class SchematicUploadEntry {
|
||||
public Level world;
|
||||
public BlockPos tablePos;
|
||||
public OutputStream stream;
|
||||
|
@ -56,19 +65,42 @@ public class ServerSchematicLoader {
|
|||
}
|
||||
}
|
||||
|
||||
public ServerSchematicLoader() {
|
||||
activeUploads = new HashMap<>();
|
||||
}
|
||||
|
||||
public String getSchematicPath() {
|
||||
return "schematics/uploaded";
|
||||
}
|
||||
|
||||
private final ObjectArrayList<String> deadEntries = ObjectArrayList.of();
|
||||
|
||||
@Nullable
|
||||
public SchematicFile getSchematicFileFromSum(String sum) {
|
||||
return sumToSchematic.get(sum);
|
||||
}
|
||||
|
||||
public void computeHashes() {
|
||||
Util.ioPool().submit(() -> {
|
||||
try (Stream<Path> filePaths = Files.find(Path.of(getSchematicPath()), 2,
|
||||
(filePath, attributes) -> filePath.toString().endsWith(".nbt"))) {
|
||||
for (Path path : filePaths.toList()) {
|
||||
try (InputStream stream = new FileInputStream(path.toFile())) {
|
||||
String[] pathSplit = path.toString()
|
||||
.replace("schematics/uploaded/", "")
|
||||
.replace(".nbt", "")
|
||||
.split("/");
|
||||
String playerName = pathSplit[0];
|
||||
String schematicName = pathSplit[1];
|
||||
String schematicMd5Hex = DigestUtils.md5Hex(stream);
|
||||
|
||||
sumToSchematic.computeIfAbsent(schematicMd5Hex, k -> new SchematicFile(playerName, schematicName));
|
||||
}
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
});
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
// Detect Timed out Uploads
|
||||
int timeout = getConfig().schematicIdleTimeout.get();
|
||||
|
||||
for (String upload : activeUploads.keySet()) {
|
||||
SchematicUploadEntry entry = activeUploads.get(upload);
|
||||
|
||||
|
@ -82,6 +114,7 @@ public class ServerSchematicLoader {
|
|||
for (String toRemove : deadEntries) {
|
||||
this.cancelUpload(toRemove);
|
||||
}
|
||||
|
||||
deadEntries.clear();
|
||||
}
|
||||
|
||||
|
@ -240,17 +273,22 @@ public class ServerSchematicLoader {
|
|||
table.finishUpload();
|
||||
}
|
||||
|
||||
// Use when the schematic already exists on the server
|
||||
public void useLocalFile(Level level, BlockPos pos, SchematicFile schematicFile) {
|
||||
SchematicTableBlockEntity table = getTable(level, pos);
|
||||
if (table != null) {
|
||||
table.finishUpload();
|
||||
table.inventory.setStackInSlot(1, SchematicItem.create(level.holderLookup(Registries.BLOCK), schematicFile));
|
||||
}
|
||||
}
|
||||
|
||||
public SchematicTableBlockEntity getTable(Level world, BlockPos pos) {
|
||||
BlockEntity be = world.getBlockEntity(pos);
|
||||
if (!(be instanceof SchematicTableBlockEntity))
|
||||
return null;
|
||||
SchematicTableBlockEntity table = (SchematicTableBlockEntity) be;
|
||||
return table;
|
||||
return world.getBlockEntity(pos) instanceof SchematicTableBlockEntity table ? table : null;
|
||||
}
|
||||
|
||||
public void handleFinishedUpload(ServerPlayer player, String schematic) {
|
||||
String playerSchematicId = player.getGameProfile()
|
||||
.getName() + "/" + schematic;
|
||||
String playerName = player.getGameProfile().getName();
|
||||
String playerSchematicId = playerName + "/" + schematic;
|
||||
|
||||
if (activeUploads.containsKey(playerSchematicId)) {
|
||||
try {
|
||||
|
@ -259,6 +297,11 @@ public class ServerSchematicLoader {
|
|||
Level world = removed.world;
|
||||
BlockPos pos = removed.tablePos;
|
||||
|
||||
// It'll be fine:tm:
|
||||
try (InputStream stream = Files.newInputStream(Path.of(playerSchematicId), StandardOpenOption.READ)) {
|
||||
sumToSchematic.computeIfAbsent(DigestUtils.md5Hex(stream), k -> new SchematicFile(playerName, schematic));
|
||||
} catch (IOException ignored) {}
|
||||
|
||||
Create.LOGGER.info("New Schematic Uploaded: " + playerSchematicId);
|
||||
if (pos == null)
|
||||
return;
|
||||
|
@ -271,9 +314,7 @@ public class ServerSchematicLoader {
|
|||
if (table == null)
|
||||
return;
|
||||
table.finishUpload();
|
||||
table.inventory.setStackInSlot(1, SchematicItem.create(world.holderLookup(Registries.BLOCK), schematic, player.getGameProfile()
|
||||
.getName()));
|
||||
|
||||
table.inventory.setStackInSlot(1, SchematicItem.create(world.holderLookup(Registries.BLOCK), schematic, playerName));
|
||||
} catch (IOException e) {
|
||||
Create.LOGGER.error("Exception Thrown when finishing Upload: " + playerSchematicId);
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -28,6 +28,8 @@ import net.minecraft.network.chat.Component;
|
|||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class ClientSchematicLoader {
|
||||
|
||||
|
@ -73,7 +75,11 @@ public class ClientSchematicLoader {
|
|||
|
||||
in = Files.newInputStream(path, StandardOpenOption.READ);
|
||||
activeUploads.put(schematic, in);
|
||||
AllPackets.getChannel().sendToServer(SchematicUploadPacket.begin(schematic, size));
|
||||
|
||||
try (InputStream stream = Files.newInputStream(path, StandardOpenOption.READ)) {
|
||||
String md5 = DigestUtils.md5Hex(stream);
|
||||
AllPackets.getChannel().sendToServer(SchematicUploadPacket.begin(schematic, size, md5));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.simibubi.create.content.schematics.packet;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.schematics.SchematicFile;
|
||||
import com.simibubi.create.content.schematics.table.SchematicTableMenu;
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
|
@ -9,6 +10,8 @@ import net.minecraft.network.FriendlyByteBuf;
|
|||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.network.NetworkEvent.Context;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class SchematicUploadPacket extends SimplePacketBase {
|
||||
|
||||
public static final int BEGIN = 0;
|
||||
|
@ -20,14 +23,17 @@ public class SchematicUploadPacket extends SimplePacketBase {
|
|||
private String schematic;
|
||||
private byte[] data;
|
||||
|
||||
private String md5Hex;
|
||||
|
||||
public SchematicUploadPacket(int code, String schematic) {
|
||||
this.code = code;
|
||||
this.schematic = schematic;
|
||||
}
|
||||
|
||||
public static SchematicUploadPacket begin(String schematic, long size) {
|
||||
public static SchematicUploadPacket begin(String schematic, long size, String md5Hex) {
|
||||
SchematicUploadPacket pkt = new SchematicUploadPacket(BEGIN, schematic);
|
||||
pkt.size = size;
|
||||
pkt.md5Hex = md5Hex;
|
||||
return pkt;
|
||||
}
|
||||
|
||||
|
@ -45,8 +51,10 @@ public class SchematicUploadPacket extends SimplePacketBase {
|
|||
code = buffer.readInt();
|
||||
schematic = buffer.readUtf(256);
|
||||
|
||||
if (code == BEGIN)
|
||||
if (code == BEGIN) {
|
||||
size = buffer.readLong();
|
||||
md5Hex = buffer.readUtf(32);
|
||||
}
|
||||
if (code == WRITE)
|
||||
data = buffer.readByteArray();
|
||||
}
|
||||
|
@ -56,8 +64,10 @@ public class SchematicUploadPacket extends SimplePacketBase {
|
|||
buffer.writeInt(code);
|
||||
buffer.writeUtf(schematic);
|
||||
|
||||
if (code == BEGIN)
|
||||
if (code == BEGIN) {
|
||||
buffer.writeLong(size);
|
||||
buffer.writeUtf(md5Hex);
|
||||
}
|
||||
if (code == WRITE)
|
||||
buffer.writeByteArray(data);
|
||||
}
|
||||
|
@ -69,9 +79,29 @@ public class SchematicUploadPacket extends SimplePacketBase {
|
|||
if (player == null)
|
||||
return;
|
||||
if (code == BEGIN) {
|
||||
BlockPos pos = ((SchematicTableMenu) player.containerMenu).contentHolder
|
||||
.getBlockPos();
|
||||
Create.SCHEMATIC_RECEIVER.handleNewUpload(player, schematic, size, pos);
|
||||
boolean usedLocalFile = false;
|
||||
|
||||
BlockPos pos = ((SchematicTableMenu) player.containerMenu).contentHolder.getBlockPos();
|
||||
|
||||
SchematicFile schematicFile = Create.SCHEMATIC_RECEIVER.getSchematicFileFromSum(md5Hex);
|
||||
|
||||
if (schematicFile != null) {
|
||||
String filePath = String.format(
|
||||
"%s/%s/%s",
|
||||
Create.SCHEMATIC_RECEIVER.getSchematicPath(),
|
||||
schematicFile.playerName(),
|
||||
schematicFile.schematicName()
|
||||
);
|
||||
|
||||
// Check if the file exists
|
||||
if (new File(filePath).isFile()) {
|
||||
Create.SCHEMATIC_RECEIVER.useLocalFile(player.level(), pos, schematicFile);
|
||||
usedLocalFile = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!usedLocalFile)
|
||||
Create.SCHEMATIC_RECEIVER.handleNewUpload(player, schematic, size, pos);
|
||||
}
|
||||
if (code == WRITE)
|
||||
Create.SCHEMATIC_RECEIVER.handleWriteRequest(player, schematic, data);
|
||||
|
|
Loading…
Reference in a new issue