Skip to content

Commit

Permalink
Sponge schematic format v3 (#48)
Browse files Browse the repository at this point in the history
* Add more debug info

* Default to SPONGE_V3

Also attempts to load previous SPONGE_V2 files or even MCEDIT

* Update RepairListCommand.java

* Update WEUtils.java

* Update WEUtils.java

* Update loading of chunks for warfare

* Split out save schematic

* Split out repair sign logic

* Clean up
  • Loading branch information
TylerS1066 authored Sep 15, 2024
1 parent c7f3db0 commit 5fa5389
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 62 deletions.
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

0 comments on commit 5fa5389

Please sign in to comment.