Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public class BattleArenaConfig {
@ArenaOption(name = "randomized-arena-join", description = "Whether players should be randomly placed in an Arena when joining without specifying a map.", required = true)
private boolean randomizedArenaJoin;

@ArenaOption(name = "use-schematic", description = "Whether creating a dynamic arena should try to use a schematic if one is available first.", required = true)
private boolean schematicUsage;

@ArenaOption(name = "disabled-modules", description = "Modules that are disabled by default.")
private List<String> disabledModules;

Expand Down Expand Up @@ -59,6 +62,10 @@ public boolean isRandomizedArenaJoin() {
return this.randomizedArenaJoin;
}

public boolean isSchematicUsage() {
return this.schematicUsage;
}

public List<String> getDisabledModules() {
return this.disabledModules == null ? List.of() : List.copyOf(this.disabledModules);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import net.kyori.adventure.util.TriState;
import org.battleplugins.arena.Arena;
import org.battleplugins.arena.ArenaLike;
import org.battleplugins.arena.competition.Competition;
import org.battleplugins.arena.competition.LiveCompetition;
import org.battleplugins.arena.competition.map.options.Bounds;
import org.battleplugins.arena.competition.map.options.Spawns;
Expand All @@ -14,6 +13,7 @@
import org.battleplugins.arena.util.BlockUtil;
import org.battleplugins.arena.util.Util;
import org.battleplugins.arena.util.VoidChunkGenerator;
import org.battleplugins.arena.BattleArenaConfig;
import org.bukkit.Bukkit;
import org.bukkit.GameRule;
import org.bukkit.World;
Expand Down Expand Up @@ -258,8 +258,14 @@ public final LiveCompetition<?> createDynamicCompetition(Arena arena) {
world.setGameRule(GameRule.DISABLE_RAIDS, true);
world.setAutoSave(false);

if (!BlockUtil.copyToWorld(this.mapWorld, world, this.bounds)) {
return null; // Failed to copy
BattleArenaConfig config = this.getArena().getPlugin().getMainConfig();

// If schematic usage is disabled in the config OR schematic pasting fails,
// then attempt to fall back to copying the map directly from the map world.
// If that also fails, return null to indicate map setup failure.
if ((!config.isSchematicUsage() || !BlockUtil.pasteSchematic(this.name, this.getArena().getName(), world, this.bounds))
&& !BlockUtil.copyToWorld(this.mapWorld, world, this.bounds)) {
return null;
}

LiveCompetitionMap copy = arena.getMapFactory().create(this.name, arena, this.type, worldName, this.bounds, this.spawns);
Expand Down
61 changes: 61 additions & 0 deletions plugin/src/main/java/org/battleplugins/arena/util/BlockUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,24 @@
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.session.ClipboardHolder;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Locale;
import org.battleplugins.arena.BattleArena;
import org.battleplugins.arena.competition.map.options.Bounds;
import org.bukkit.Bukkit;
import org.bukkit.World;

public final class BlockUtil {
Expand Down Expand Up @@ -46,4 +56,55 @@ public static boolean copyToWorld(World oldWorld, World newWorld, Bounds bounds)

return true;
}

public static boolean pasteSchematic(String map, String arena, World world, Bounds bounds) {
Path path = BattleArena.getInstance().getDataFolder().toPath()
.resolve("schematics")
.resolve(arena.toLowerCase(Locale.ROOT))
.resolve(map.toLowerCase(Locale.ROOT) + "." +
BuiltInClipboardFormat.SPONGE_SCHEMATIC.getPrimaryFileExtension()
);

if (Files.notExists(path)) {
Bukkit.getLogger().warning("Schematic not found: " + path);
path = BattleArena.getInstance().getDataFolder().toPath()
.resolve("schematics")
.resolve(arena.toLowerCase(Locale.ROOT))
.resolve(map.toLowerCase(Locale.ROOT) + "." +
BuiltInClipboardFormat.MCEDIT_SCHEMATIC.getPrimaryFileExtension()
);
if (Files.notExists(path)) {
Bukkit.getLogger().warning("Schematic not found: " + path);
return false;
}
}

ClipboardFormat format = ClipboardFormats.findByFile(path.toFile());
if (format == null) {
Bukkit.getLogger().warning("Unknown schematic format: " + path.getFileName());
return false;
}

Clipboard clipboard;
try (ClipboardReader reader = format.getReader(Files.newInputStream(path))) {
clipboard = reader.read();
} catch (IOException e) {
Bukkit.getLogger().severe("Failed to read schematic: " + e.getMessage());
return false;
}

try (EditSession session = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(world))) {
Operation operation = new ClipboardHolder(clipboard)
.createPaste(session)
.to(BlockVector3.at(bounds.getMinX(), bounds.getMinY(), bounds.getMinZ()))
.ignoreAirBlocks(true)
.build();

Operations.complete(operation);
return true;
} catch (WorldEditException e) {
Bukkit.getLogger().severe("Failed to paste schematic: " + e.getMessage());
return false;
}
}
}
7 changes: 7 additions & 0 deletions plugin/src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ max-dynamic-maps: 5
# enabled.
randomized-arena-join: false

# Whether dynamic arenas should try to use a schematic file for the map if one is available.
# If enabled and a schematic exists for the arena, it will be pasted into the world automatically.
# If no schematic is found or pasting fails, the plugin will fall back to copying the map directly
# from the source world. Disabling this option will skip the schematic step entirely and always
# use world copying instead.
use-schematic: false

# Modules that are disabled by default. BattleArena comes pre-installed with
# multiple modules that can be disabled below if their behavior is not desired
# Example for disabling the parties module:
Expand Down