Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sponge schematic format v3 #48

Merged
merged 9 commits into from
Sep 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions src/main/java/net/countercraft/movecraft/repair/RepairSign.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.countercraft.movecraft.repair;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
Expand Down Expand Up @@ -149,7 +151,7 @@ private void createProtoRepair(@NotNull Sign sign, UUID uuid, Player player, Pla
RepairState state;
try {
state = new RepairState(uuid, stateName);
} catch (IOException e) {
} catch (FileNotFoundException e) {
player.sendMessage(I18nSupport.getInternationalisedComponent("Repair - State not found"));
return;
}
Expand All @@ -158,15 +160,13 @@ private void createProtoRepair(@NotNull Sign sign, UUID uuid, Player player, Pla
ProtoRepair protoRepair;
try {
protoRepair = state.execute(sign);
} catch (WorldEditException e) {
player.sendMessage(I18nSupport.getInternationalisedComponent("Repair - State not found"));
return;
} catch (RepairState.ProtoRepairCancelledException e) {
player.sendMessage(e.getFailMessage());
return;
}
if (protoRepair == null) {
} catch (WorldEditException e) {
player.sendMessage(I18nSupport.getInternationalisedComponent("Repair - State not found"));
MovecraftRepair.getInstance().getLogger().info("WorldEdit error parsing repair state.");
e.printStackTrace();
return;
}

Expand Down Expand Up @@ -209,7 +209,12 @@ public void onLeftClick(Sign sign, Player player, PlayerCraft craft) {
}
}

if (!WEUtils.saveCraftSchematic(craft, sign)) {
File repairDirectory = new File(MovecraftRepair.getInstance().getDataFolder(), "RepairStates");
File playerDirectory = new File(repairDirectory, craft.getPilot().getUniqueId().toString());
if (!playerDirectory.exists())
playerDirectory.mkdirs();
String repairName = ChatColor.stripColor(sign.getLine(1));
if (!WEUtils.saveCraftSchematic(playerDirectory, repairName, craft.getWorld(), craft.getHitBox(), sign.getLocation())) {
player.sendMessage(I18nSupport.getInternationalisedComponent("Repair - Could not save file"));
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command
}

if (schemList != null) {
String primaryExtension = "." + WEUtils.SCHEMATIC_FORMATS.getFirst().getPrimaryFileExtension();
for (File schemFile : schemList) {
String name = schemFile.getName();
if (!name.endsWith(WEUtils.SCHEMATIC_FORMAT.getPrimaryFileExtension()))
continue; // Don't display other format files
if (name.endsWith(primaryExtension))
name = name.replace(primaryExtension, "");

name = name.replace("." + WEUtils.SCHEMATIC_FORMAT.getPrimaryFileExtension(), "");
paginator.addLine(Component.text(name));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.countercraft.movecraft.repair.types;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -52,7 +53,7 @@ public class RepairState {
private final BlockVector3 schematicSignOffset;
private final BlockVector3 size;

public RepairState(@NotNull UUID playerUUID, String name) throws IOException, IllegalStateException {
public RepairState(@NotNull UUID playerUUID, String name) throws FileNotFoundException, IllegalStateException {
this.playerUUID = playerUUID;
this.name = name;
File dataDirectory = new File(MovecraftRepair.getInstance().getDataFolder(), "RepairStates");
Expand Down Expand Up @@ -90,7 +91,7 @@ private Clipboard rotate(@NotNull Sign sign) throws WorldEditException {
return ClipboardUtils.transform(schematic, new AffineTransform().rotateY(angle));
}

@Nullable
@NotNull
public ProtoRepair execute(@NotNull Sign sign) throws WorldEditException, ProtoRepairCancelledException {
// Rotate repair around the sign
Clipboard clipboard = schematic;
Expand Down
111 changes: 76 additions & 35 deletions src/main/java/net/countercraft/movecraft/repair/util/WEUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@
import com.sk89q.worldedit.EditSession;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Sign;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.sign.Side;
import org.enginehub.linbus.tree.*;
Expand Down Expand Up @@ -42,15 +41,14 @@
import com.sk89q.worldedit.world.item.ItemTypes;

import net.countercraft.movecraft.MovecraftLocation;
import net.countercraft.movecraft.craft.PilotedCraft;
import net.countercraft.movecraft.repair.MovecraftRepair;
import net.countercraft.movecraft.util.Counter;
import net.countercraft.movecraft.util.hitboxes.BitmapHitBox;
import net.countercraft.movecraft.util.hitboxes.HitBox;
import net.countercraft.movecraft.util.hitboxes.SolidHitBox;

public class WEUtils {
public static final ClipboardFormat SCHEMATIC_FORMAT = BuiltInClipboardFormat.SPONGE_V2_SCHEMATIC;
// Default format is the first one of the list, previous formats follow
public static final List<ClipboardFormat> SCHEMATIC_FORMATS = List.of(BuiltInClipboardFormat.SPONGE_V3_SCHEMATIC, BuiltInClipboardFormat.SPONGE_V2_SCHEMATIC, BuiltInClipboardFormat.MCEDIT_SCHEMATIC);

/**
* Load a schematic from disk
Expand All @@ -59,43 +57,88 @@ public class WEUtils {
* @param name Name of the schematic file (without the extension)
* @return A clipboard containing the schematic
* @throws FileNotFoundException Schematic file not found
* @throws IOException Other I/O exception
*/
@NotNull
public static Clipboard loadSchematic(File directory, String name) throws FileNotFoundException, IOException {
name += "." + SCHEMATIC_FORMAT.getPrimaryFileExtension();
public static Clipboard loadSchematic(File directory, String name) throws FileNotFoundException {
Clipboard result = null;
for (ClipboardFormat format : SCHEMATIC_FORMATS) {
Clipboard temp;
try {
temp = loadSchematic(directory, name, format);
} catch (FileNotFoundException e) {
continue; // normal operation
} catch (IOException e) {
// Abnormal, but report to console and continue reading
e.printStackTrace();
continue;
}
if (temp == null)
continue;

result = temp;
break;
}

if (result == null)
throw new FileNotFoundException();

return result;
}

@Nullable
private static Clipboard loadSchematic(File directory, String name, @NotNull ClipboardFormat format) throws IOException {
name += "." + format.getPrimaryFileExtension();
File file = new File(directory, name);
if (!format.isFormat(file))
return null;
Clipboard clipboard;
try {
ClipboardReader reader = SCHEMATIC_FORMAT.getReader(new FileInputStream(file));
try (FileInputStream inputStream = new FileInputStream(file)) {
ClipboardReader reader = format.getReader(inputStream);
clipboard = reader.read();
} catch (FileNotFoundException e) {
// Normal operation, pass the exception up
throw e;
} catch (IOException e) {
throw new IOException("Failed to load schematic", e);
// Abnormal, add more logging info
throw new IOException("Failed to load " + directory.getName() + "/" + name + " as format " + format.getName(), e);
}
return clipboard;
}

/**
* Save a schematic
*
* @param directory Directory for the schematic file
* @param name Name of the schematic file (without the extension)
* @param clipboard The clipboard to save from
*/
public static boolean saveSchematic(File directory, String name, Clipboard clipboard) {
File file = new File(directory, name + "." + SCHEMATIC_FORMATS.getFirst().getPrimaryFileExtension());
try (FileOutputStream outputStream = new FileOutputStream(file, false)) {
ClipboardWriter writer = SCHEMATIC_FORMATS.getFirst().getWriter(outputStream);
writer.write(clipboard);
writer.close();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}

/**
* Save a schematic from a craft
*
* @param craft The craft to save
* @param directory Directory to save in
* @param name Name to save as
* @param world World to save from
* @param hitbox Hitbox to save from
* @param origin Origin point to save from
* @return true on success
*/
public static boolean saveCraftSchematic(@NotNull PilotedCraft craft, @NotNull Sign sign) {
File repairDirectory = new File(MovecraftRepair.getInstance().getDataFolder(), "RepairStates");
File playerDirectory = new File(repairDirectory, craft.getPilot().getUniqueId().toString());
if (!playerDirectory.exists())
playerDirectory.mkdirs();
String repairName = ChatColor.stripColor(sign.getLine(1));
repairName += "." + SCHEMATIC_FORMAT.getPrimaryFileExtension();
File repairFile = new File(playerDirectory, repairName);

HitBox hitbox = craft.getHitBox();
public static boolean saveCraftSchematic(File directory, String name, World world, @NotNull HitBox hitbox, @NotNull Location origin) {
BlockVector3 minPos = BlockVector3.at(hitbox.getMinX(), hitbox.getMinY(), hitbox.getMinZ());
BlockVector3 maxPos = BlockVector3.at(hitbox.getMaxX(), hitbox.getMaxY(), hitbox.getMaxZ());
BlockVector3 origin = BlockVector3.at(sign.getX(), sign.getY(), sign.getZ());
BlockVector3 weOrigin = BlockVector3.at(origin.getBlockX(), origin.getBlockY(), origin.getBlockZ());
CuboidRegion region = new CuboidRegion(minPos, maxPos);
// Calculate a hitbox of all blocks within the cuboid region but not within the
// hitbox (so we don't save them)
Expand All @@ -104,16 +147,16 @@ public static boolean saveCraftSchematic(@NotNull PilotedCraft craft, @NotNull S
new MovecraftLocation(hitbox.getMaxX(), hitbox.getMaxY(), hitbox.getMaxZ()));
surrounding = new BitmapHitBox(surrounding).difference(hitbox);

World bukkitWorld = craft.getWorld();
com.sk89q.worldedit.world.World world = new BukkitWorld(bukkitWorld);
com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world);

Set<BaseBlock> blocks = getWorldEditBlocks(craft.getHitBox(), bukkitWorld);
Set<BaseBlock> blocks = getWorldEditBlocks(hitbox, world);

Clipboard clipboard;
try {
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(origin);
EditSession source = WorldEdit.getInstance().newEditSession(world);
ForwardExtentCopy copy = new ForwardExtentCopy(source, region, origin, clipboard, origin);
clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(weOrigin);
EditSession source = WorldEdit.getInstance().newEditSession(weWorld);
ForwardExtentCopy copy = new ForwardExtentCopy(source, region, weOrigin, clipboard, weOrigin);
BlockMask mask = new BlockMask(source, blocks);
copy.setSourceMask(mask);
Operations.complete(copy);
Expand All @@ -122,15 +165,13 @@ public static boolean saveCraftSchematic(@NotNull PilotedCraft craft, @NotNull S
BlockVector3.at(location.getX(), location.getY(), location.getZ()),
BlockTypes.AIR.getDefaultState().toBaseBlock());
}
ClipboardWriter writer = SCHEMATIC_FORMAT.getWriter(new FileOutputStream(repairFile, false));
writer.write(clipboard);
writer.close();
source.close();
} catch (IOException | NullPointerException | WorldEditException e) {
} catch (WorldEditException e) {
e.printStackTrace();
return false;
}
return true;

return saveSchematic(directory, name, clipboard);
}

@NotNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Mask2D;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
Expand All @@ -25,26 +24,23 @@
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import java.util.function.Supplier;

public class WarfareUtils {
public boolean repairChunk(Chunk chunk, File directory, Predicate<MovecraftLocation> check) {
public boolean repairChunk(@NotNull Chunk chunk, File directory, Predicate<MovecraftLocation> check) {
// Load schematic from disk
File file = new File(directory,
chunk.getX() + "_" + chunk.getZ() + "." + WEUtils.SCHEMATIC_FORMAT.getPrimaryFileExtension());
Clipboard clipboard;
World world = chunk.getWorld();
try {
clipboard = WEUtils.SCHEMATIC_FORMAT.getReader(new FileInputStream(file)).read();
clipboard = WEUtils.loadSchematic(directory, chunk.getX() + "_" + chunk.getZ());
} catch (IOException e) {
e.printStackTrace();
return false;
Expand Down Expand Up @@ -79,7 +75,7 @@ public boolean repairChunk(Chunk chunk, File directory, Predicate<MovecraftLocat
return true;
}

public boolean saveChunk(Chunk c, File directory, @Nullable Set<Material> materialMask) {
public boolean saveChunk(Chunk c, @NotNull File directory, @Nullable Set<Material> materialMask) {
if (!directory.exists())
directory.mkdirs();

Expand Down Expand Up @@ -111,9 +107,9 @@ public boolean saveChunk(Chunk c, File directory, @Nullable Set<Material> materi
}

// Save chunk to disk
File file = new File(directory, c.getX() + "_" + c.getZ() + "." + WEUtils.SCHEMATIC_FORMAT.getPrimaryFileExtension());
Clipboard clipboard;
try {
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard = new BlockArrayClipboard(region);
EditSession source = WorldEdit.getInstance().newEditSessionBuilder().world(world).maxBlocks(16 * 16 * (world.getMaxY() - world.getMinY() + 2)).build(); // Get enough space for the chunk, with a little extra wiggle room
ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard.getOrigin(), clipboard, minPos);
if (materialMask != null) {
Expand All @@ -122,15 +118,12 @@ public boolean saveChunk(Chunk c, File directory, @Nullable Set<Material> materi
copy.setSourceMask(mask);
}
Operations.completeLegacy(copy);
ClipboardWriter writer = WEUtils.SCHEMATIC_FORMAT.getWriter(new FileOutputStream(file, false));
writer.write(clipboard);
writer.close();
source.close();
return true;
} catch (MaxChangedBlocksException | IOException e) {
} catch (MaxChangedBlocksException e) {
e.printStackTrace();
return false;
}
return WEUtils.saveSchematic(directory, c.getX() + "_" + c.getZ(), clipboard);
}

private static class BlockTask implements Supplier<Effect> {
Expand Down