Various major
Implement virtual worlds New schematic commands: //schem show <directory> //schem delete * - Deletes the files associated with your currently loaded schematic //schem move <directory> - Moves your currently loaded schematics to this directory //download -> supports downloading multiple schematics at once
This commit is contained in:
parent
b1f8bbddfa
commit
6968e66ad8
@ -167,15 +167,21 @@ public class FaweBukkit implements IFawe, Listener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerPacketListener() {
|
||||||
|
PluginManager manager = Bukkit.getPluginManager();
|
||||||
|
if (packetListener == null && manager.getPlugin("ProtocolLib") != null) {
|
||||||
|
packetListener = new CFIPacketListener(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized ImageViewer getImageViewer(FawePlayer fp) {
|
public synchronized ImageViewer getImageViewer(FawePlayer fp) {
|
||||||
if (listeningImages && imageListener == null) return null;
|
if (listeningImages && imageListener == null) return null;
|
||||||
try {
|
try {
|
||||||
listeningImages = true;
|
listeningImages = true;
|
||||||
|
registerPacketListener();
|
||||||
PluginManager manager = Bukkit.getPluginManager();
|
PluginManager manager = Bukkit.getPluginManager();
|
||||||
if (manager.getPlugin("ProtocolLib") != null) {
|
|
||||||
packetListener = new CFIPacketListener(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (manager.getPlugin("PacketListenerApi") == null) {
|
if (manager.getPlugin("PacketListenerApi") == null) {
|
||||||
File output = new File(plugin.getDataFolder().getParentFile(), "PacketListenerAPI_v3.6.0-SNAPSHOT.jar");
|
File output = new File(plugin.getDataFolder().getParentFile(), "PacketListenerAPI_v3.6.0-SNAPSHOT.jar");
|
||||||
|
@ -2,11 +2,11 @@ package com.boydti.fawe.bukkit.listener;
|
|||||||
|
|
||||||
import com.boydti.fawe.FaweCache;
|
import com.boydti.fawe.FaweCache;
|
||||||
import com.boydti.fawe.command.CFICommands;
|
import com.boydti.fawe.command.CFICommands;
|
||||||
import com.boydti.fawe.jnbt.anvil.HeightMapMCAGenerator;
|
|
||||||
import com.boydti.fawe.object.FaweChunk;
|
import com.boydti.fawe.object.FaweChunk;
|
||||||
import com.boydti.fawe.object.FawePlayer;
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
import com.boydti.fawe.object.FaweQueue;
|
import com.boydti.fawe.object.FaweQueue;
|
||||||
import com.boydti.fawe.object.RunnableVal3;
|
import com.boydti.fawe.object.RunnableVal3;
|
||||||
|
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
||||||
import com.boydti.fawe.util.SetQueue;
|
import com.boydti.fawe.util.SetQueue;
|
||||||
import com.comphenix.protocol.PacketType;
|
import com.comphenix.protocol.PacketType;
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
@ -42,7 +42,7 @@ import org.bukkit.inventory.PlayerInventory;
|
|||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The CFIPacketListener handles packets for editing the HeightMapMCAGenerator
|
* The CFIPacketListener handles packets for editing the VirtualWorld
|
||||||
* The generator is a virtual world which only the creator can see
|
* The generator is a virtual world which only the creator can see
|
||||||
* - The virtual world is displayed inside the current world
|
* - The virtual world is displayed inside the current world
|
||||||
* - Block/Chunk/Movement packets need to be handled properly
|
* - Block/Chunk/Movement packets need to be handled properly
|
||||||
@ -57,9 +57,9 @@ public class CFIPacketListener implements Listener {
|
|||||||
this.protocolmanager = ProtocolLibrary.getProtocolManager();
|
this.protocolmanager = ProtocolLibrary.getProtocolManager();
|
||||||
|
|
||||||
// Direct digging to the virtual world
|
// Direct digging to the virtual world
|
||||||
registerBlockEvent(PacketType.Play.Client.BLOCK_DIG, false, new RunnableVal3<PacketEvent, HeightMapMCAGenerator, Vector>() {
|
registerBlockEvent(PacketType.Play.Client.BLOCK_DIG, false, new RunnableVal3<PacketEvent, VirtualWorld, Vector>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(PacketEvent event, HeightMapMCAGenerator gen, Vector pt) {
|
public void run(PacketEvent event, VirtualWorld gen, Vector pt) {
|
||||||
try {
|
try {
|
||||||
Player plr = event.getPlayer();
|
Player plr = event.getPlayer();
|
||||||
Vector realPos = pt.add(gen.getOrigin());
|
Vector realPos = pt.add(gen.getOrigin());
|
||||||
@ -73,9 +73,9 @@ public class CFIPacketListener implements Listener {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Direct placing to the virtual world
|
// Direct placing to the virtual world
|
||||||
RunnableVal3<PacketEvent, HeightMapMCAGenerator, Vector> placeTask = new RunnableVal3<PacketEvent, HeightMapMCAGenerator, Vector>() {
|
RunnableVal3<PacketEvent, VirtualWorld, Vector> placeTask = new RunnableVal3<PacketEvent, VirtualWorld, Vector>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(PacketEvent event, HeightMapMCAGenerator gen, Vector pt) {
|
public void run(PacketEvent event, VirtualWorld gen, Vector pt) {
|
||||||
try {
|
try {
|
||||||
Player plr = event.getPlayer();
|
Player plr = event.getPlayer();
|
||||||
List<EnumWrappers.Hand> hands = event.getPacket().getHands().getValues();
|
List<EnumWrappers.Hand> hands = event.getPacket().getHands().getValues();
|
||||||
@ -99,9 +99,9 @@ public class CFIPacketListener implements Listener {
|
|||||||
registerBlockEvent(PacketType.Play.Client.USE_ITEM, true, placeTask);
|
registerBlockEvent(PacketType.Play.Client.USE_ITEM, true, placeTask);
|
||||||
|
|
||||||
// Cancel block change packets where the real world overlaps with the virtual one
|
// Cancel block change packets where the real world overlaps with the virtual one
|
||||||
registerBlockEvent(PacketType.Play.Server.BLOCK_CHANGE, false, new RunnableVal3<PacketEvent, HeightMapMCAGenerator, Vector>() {
|
registerBlockEvent(PacketType.Play.Server.BLOCK_CHANGE, false, new RunnableVal3<PacketEvent, VirtualWorld, Vector>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(PacketEvent event, HeightMapMCAGenerator gen, Vector pt) {
|
public void run(PacketEvent event, VirtualWorld gen, Vector pt) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -112,7 +112,7 @@ public class CFIPacketListener implements Listener {
|
|||||||
public void onPacketSending(PacketEvent event) {
|
public void onPacketSending(PacketEvent event) {
|
||||||
if (!event.isServerPacket()) return;
|
if (!event.isServerPacket()) return;
|
||||||
|
|
||||||
HeightMapMCAGenerator gen = getGenerator(event);
|
VirtualWorld gen = getGenerator(event);
|
||||||
if (gen != null) {
|
if (gen != null) {
|
||||||
Vector origin = gen.getOrigin();
|
Vector origin = gen.getOrigin();
|
||||||
PacketContainer packet = event.getPacket();
|
PacketContainer packet = event.getPacket();
|
||||||
@ -123,7 +123,7 @@ public class CFIPacketListener implements Listener {
|
|||||||
int ocx = origin.getBlockX() >> 4;
|
int ocx = origin.getBlockX() >> 4;
|
||||||
int ocz = origin.getBlockZ() >> 4;
|
int ocz = origin.getBlockZ() >> 4;
|
||||||
|
|
||||||
if (gen.contain(new Vector((cx - ocx) << 4, 0, (cz - ocz) << 4))) {
|
if (gen.contains(new Vector((cx - ocx) << 4, 0, (cz - ocz) << 4))) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
|
||||||
Player plr = event.getPlayer();
|
Player plr = event.getPlayer();
|
||||||
@ -147,7 +147,7 @@ public class CFIPacketListener implements Listener {
|
|||||||
|
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
Location pos = player.getLocation();
|
Location pos = player.getLocation();
|
||||||
HeightMapMCAGenerator gen = getGenerator(event);
|
VirtualWorld gen = getGenerator(event);
|
||||||
if (gen != null) {
|
if (gen != null) {
|
||||||
Vector origin = gen.getOrigin();
|
Vector origin = gen.getOrigin();
|
||||||
Vector pt = new Vector(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ());
|
Vector pt = new Vector(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ());
|
||||||
@ -158,7 +158,7 @@ public class CFIPacketListener implements Listener {
|
|||||||
int my = ints.read(2);
|
int my = ints.read(2);
|
||||||
int mz = ints.read(3);
|
int mz = ints.read(3);
|
||||||
|
|
||||||
if (gen.contain(pt.subtract(origin)) && mx == 0 && my == 0 && mz == 0) {
|
if (gen.contains(pt.subtract(origin)) && mx == 0 && my == 0 && mz == 0) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -172,7 +172,7 @@ public class CFIPacketListener implements Listener {
|
|||||||
|
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
Location pos = player.getLocation();
|
Location pos = player.getLocation();
|
||||||
HeightMapMCAGenerator gen = getGenerator(event);
|
VirtualWorld gen = getGenerator(event);
|
||||||
if (gen != null) {
|
if (gen != null) {
|
||||||
Vector origin = gen.getOrigin();
|
Vector origin = gen.getOrigin();
|
||||||
Vector from = new Vector(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ());
|
Vector from = new Vector(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ());
|
||||||
@ -180,7 +180,7 @@ public class CFIPacketListener implements Listener {
|
|||||||
PacketContainer packet = event.getPacket();
|
PacketContainer packet = event.getPacket();
|
||||||
StructureModifier<Double> doubles = packet.getDoubles();
|
StructureModifier<Double> doubles = packet.getDoubles();
|
||||||
Vector to = new Vector(doubles.read(0), doubles.read(1), doubles.read(2));
|
Vector to = new Vector(doubles.read(0), doubles.read(1), doubles.read(2));
|
||||||
if (gen.contain(to.subtract(origin)) && from.distanceSq(to) < 8) {
|
if (gen.contains(to.subtract(origin)) && from.distanceSq(to) < 8) {
|
||||||
int id = packet.getIntegers().read(0);
|
int id = packet.getIntegers().read(0);
|
||||||
PacketContainer reply = new PacketContainer(PacketType.Play.Client.TELEPORT_ACCEPT);
|
PacketContainer reply = new PacketContainer(PacketType.Play.Client.TELEPORT_ACCEPT);
|
||||||
reply.getIntegers().write(0, id);
|
reply.getIntegers().write(0, id);
|
||||||
@ -202,14 +202,14 @@ public class CFIPacketListener implements Listener {
|
|||||||
public void onPacketSending(PacketEvent event) {
|
public void onPacketSending(PacketEvent event) {
|
||||||
if (!event.isServerPacket()) return;
|
if (!event.isServerPacket()) return;
|
||||||
|
|
||||||
HeightMapMCAGenerator gen = getGenerator(event);
|
VirtualWorld gen = getGenerator(event);
|
||||||
if (gen != null) {
|
if (gen != null) {
|
||||||
PacketContainer packet = event.getPacket();
|
PacketContainer packet = event.getPacket();
|
||||||
ChunkCoordIntPair chunk = packet.getChunkCoordIntPairs().read(0);
|
ChunkCoordIntPair chunk = packet.getChunkCoordIntPairs().read(0);
|
||||||
Vector origin = gen.getOrigin();
|
Vector origin = gen.getOrigin();
|
||||||
int cx = chunk.getChunkX() - (origin.getBlockX() >> 4);
|
int cx = chunk.getChunkX() - (origin.getBlockX() >> 4);
|
||||||
int cz = chunk.getChunkZ() - (origin.getBlockX() >> 4);
|
int cz = chunk.getChunkZ() - (origin.getBlockX() >> 4);
|
||||||
if (gen.contain(new Vector(cx << 4, 0, cz << 4))) {
|
if (gen.contains(new Vector(cx << 4, 0, cz << 4))) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,7 +220,7 @@ public class CFIPacketListener implements Listener {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void onTeleport(PlayerTeleportEvent event) {
|
public void onTeleport(PlayerTeleportEvent event) {
|
||||||
final Player player = event.getPlayer();
|
final Player player = event.getPlayer();
|
||||||
HeightMapMCAGenerator gen = getGenerator(player);
|
VirtualWorld gen = getGenerator(player);
|
||||||
if (gen != null) {
|
if (gen != null) {
|
||||||
Location from = event.getFrom();
|
Location from = event.getFrom();
|
||||||
Location to = event.getTo();
|
Location to = event.getTo();
|
||||||
@ -232,7 +232,7 @@ public class CFIPacketListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean sendBlockChange(Player plr, HeightMapMCAGenerator gen, Vector pt, Interaction action) {
|
private boolean sendBlockChange(Player plr, VirtualWorld gen, Vector pt, Interaction action) {
|
||||||
PlatformManager platform = WorldEdit.getInstance().getPlatformManager();
|
PlatformManager platform = WorldEdit.getInstance().getPlatformManager();
|
||||||
com.sk89q.worldedit.entity.Player actor = FawePlayer.wrap(plr).getPlayer();
|
com.sk89q.worldedit.entity.Player actor = FawePlayer.wrap(plr).getPlayer();
|
||||||
com.sk89q.worldedit.util.Location location = new com.sk89q.worldedit.util.Location(actor.getWorld(), pt);
|
com.sk89q.worldedit.util.Location location = new com.sk89q.worldedit.util.Location(actor.getWorld(), pt);
|
||||||
@ -261,19 +261,22 @@ public class CFIPacketListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private HeightMapMCAGenerator getGenerator(PacketEvent event) {
|
private VirtualWorld getGenerator(PacketEvent event) {
|
||||||
return getGenerator(event.getPlayer());
|
return getGenerator(event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
private HeightMapMCAGenerator getGenerator(Player player) {
|
private VirtualWorld getGenerator(Player player) {
|
||||||
CFICommands.CFISettings settings = FawePlayer.wrap(player).getMeta("CFISettings");
|
FawePlayer<Object> fp = FawePlayer.wrap(player);
|
||||||
|
VirtualWorld vw = fp.getSession().getVirtualWorld();
|
||||||
|
if (vw != null) return vw;
|
||||||
|
CFICommands.CFISettings settings = fp.getMeta("CFISettings");
|
||||||
if (settings != null && settings.hasGenerator() && settings.getGenerator().hasPacketViewer()) {
|
if (settings != null && settings.hasGenerator() && settings.getGenerator().hasPacketViewer()) {
|
||||||
return settings.getGenerator();
|
return settings.getGenerator();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector getRelPos(PacketEvent event, HeightMapMCAGenerator generator) {
|
private Vector getRelPos(PacketEvent event, VirtualWorld generator) {
|
||||||
PacketContainer packet = event.getPacket();
|
PacketContainer packet = event.getPacket();
|
||||||
StructureModifier<BlockPosition> position = packet.getBlockPositionModifier();
|
StructureModifier<BlockPosition> position = packet.getBlockPositionModifier();
|
||||||
BlockPosition loc = position.readSafely(0);
|
BlockPosition loc = position.readSafely(0);
|
||||||
@ -283,13 +286,13 @@ public class CFIPacketListener implements Listener {
|
|||||||
return pt;
|
return pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleBlockEvent(PacketEvent event, boolean relative, RunnableVal3<PacketEvent, HeightMapMCAGenerator, Vector> task) {
|
private void handleBlockEvent(PacketEvent event, boolean relative, RunnableVal3<PacketEvent, VirtualWorld, Vector> task) {
|
||||||
HeightMapMCAGenerator gen = getGenerator(event);
|
VirtualWorld gen = getGenerator(event);
|
||||||
if (gen != null) {
|
if (gen != null) {
|
||||||
Vector pt = getRelPos(event, gen);
|
Vector pt = getRelPos(event, gen);
|
||||||
if (pt != null) {
|
if (pt != null) {
|
||||||
if (relative) pt = getRelative(event, pt);
|
if (relative) pt = getRelative(event, pt);
|
||||||
if (gen.contain(pt)) {
|
if (gen.contains(pt)) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
task.run(event, gen, pt);
|
task.run(event, gen, pt);
|
||||||
}
|
}
|
||||||
@ -297,7 +300,7 @@ public class CFIPacketListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerBlockEvent(PacketType type, boolean relative, RunnableVal3<PacketEvent, HeightMapMCAGenerator, Vector> task) {
|
private void registerBlockEvent(PacketType type, boolean relative, RunnableVal3<PacketEvent, VirtualWorld, Vector> task) {
|
||||||
protocolmanager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.NORMAL, type) {
|
protocolmanager.addPacketListener(new PacketAdapter(plugin, ListenerPriority.NORMAL, type) {
|
||||||
@Override
|
@Override
|
||||||
public void onPacketReceiving(final PacketEvent event) {
|
public void onPacketReceiving(final PacketEvent event) {
|
||||||
|
@ -15,11 +15,7 @@ import com.boydti.fawe.object.RunnableVal;
|
|||||||
import com.boydti.fawe.object.brush.visualization.VisualChunk;
|
import com.boydti.fawe.object.brush.visualization.VisualChunk;
|
||||||
import com.boydti.fawe.object.queue.LazyFaweChunk;
|
import com.boydti.fawe.object.queue.LazyFaweChunk;
|
||||||
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
import com.boydti.fawe.object.visitor.FaweChunkVisitor;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.*;
|
||||||
import com.boydti.fawe.util.MathMan;
|
|
||||||
import com.boydti.fawe.util.ReflectionUtils;
|
|
||||||
import com.boydti.fawe.util.SetQueue;
|
|
||||||
import com.boydti.fawe.util.TaskManager;
|
|
||||||
import com.comphenix.protocol.PacketType;
|
import com.comphenix.protocol.PacketType;
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
import com.comphenix.protocol.ProtocolManager;
|
import com.comphenix.protocol.ProtocolManager;
|
||||||
@ -36,49 +32,9 @@ import java.lang.reflect.Constructor;
|
|||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.atomic.LongAdder;
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
import net.minecraft.server.v1_12_R1.BiomeBase;
|
import net.minecraft.server.v1_12_R1.*;
|
||||||
import net.minecraft.server.v1_12_R1.BiomeCache;
|
|
||||||
import net.minecraft.server.v1_12_R1.Block;
|
|
||||||
import net.minecraft.server.v1_12_R1.BlockPosition;
|
|
||||||
import net.minecraft.server.v1_12_R1.ChunkProviderGenerate;
|
|
||||||
import net.minecraft.server.v1_12_R1.ChunkProviderServer;
|
|
||||||
import net.minecraft.server.v1_12_R1.ChunkSection;
|
|
||||||
import net.minecraft.server.v1_12_R1.DataPaletteBlock;
|
|
||||||
import net.minecraft.server.v1_12_R1.Entity;
|
|
||||||
import net.minecraft.server.v1_12_R1.EntityPlayer;
|
|
||||||
import net.minecraft.server.v1_12_R1.EntityTracker;
|
|
||||||
import net.minecraft.server.v1_12_R1.EntityTypes;
|
|
||||||
import net.minecraft.server.v1_12_R1.EnumDifficulty;
|
|
||||||
import net.minecraft.server.v1_12_R1.EnumGamemode;
|
|
||||||
import net.minecraft.server.v1_12_R1.EnumSkyBlock;
|
|
||||||
import net.minecraft.server.v1_12_R1.IBlockData;
|
|
||||||
import net.minecraft.server.v1_12_R1.IDataManager;
|
|
||||||
import net.minecraft.server.v1_12_R1.MinecraftServer;
|
|
||||||
import net.minecraft.server.v1_12_R1.NBTTagCompound;
|
|
||||||
import net.minecraft.server.v1_12_R1.NibbleArray;
|
|
||||||
import net.minecraft.server.v1_12_R1.PacketDataSerializer;
|
|
||||||
import net.minecraft.server.v1_12_R1.PacketPlayOutMapChunk;
|
|
||||||
import net.minecraft.server.v1_12_R1.PacketPlayOutMultiBlockChange;
|
|
||||||
import net.minecraft.server.v1_12_R1.PlayerChunk;
|
|
||||||
import net.minecraft.server.v1_12_R1.PlayerChunkMap;
|
|
||||||
import net.minecraft.server.v1_12_R1.RegionFile;
|
|
||||||
import net.minecraft.server.v1_12_R1.RegionFileCache;
|
|
||||||
import net.minecraft.server.v1_12_R1.ServerNBTManager;
|
|
||||||
import net.minecraft.server.v1_12_R1.TileEntity;
|
|
||||||
import net.minecraft.server.v1_12_R1.WorldChunkManager;
|
|
||||||
import net.minecraft.server.v1_12_R1.WorldData;
|
|
||||||
import net.minecraft.server.v1_12_R1.WorldManager;
|
|
||||||
import net.minecraft.server.v1_12_R1.WorldServer;
|
|
||||||
import net.minecraft.server.v1_12_R1.WorldSettings;
|
|
||||||
import net.minecraft.server.v1_12_R1.WorldType;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
@ -583,6 +539,7 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
|||||||
for (int i = 0; i < players.length; i++) {
|
for (int i = 0; i < players.length; i++) {
|
||||||
CraftPlayer bukkitPlayer = ((CraftPlayer) ((BukkitPlayer) players[i]).parent);
|
CraftPlayer bukkitPlayer = ((CraftPlayer) ((BukkitPlayer) players[i]).parent);
|
||||||
EntityPlayer player = bukkitPlayer.getHandle();
|
EntityPlayer player = bukkitPlayer.getHandle();
|
||||||
|
|
||||||
if (playerManager.a(player, chunk.getX(), chunk.getZ())) {
|
if (playerManager.a(player, chunk.getX(), chunk.getZ())) {
|
||||||
if (packet == null) {
|
if (packet == null) {
|
||||||
byte[] data;
|
byte[] data;
|
||||||
@ -662,6 +619,15 @@ public class BukkitQueue_1_12 extends BukkitQueue_0<net.minecraft.server.v1_12_R
|
|||||||
sendChunk(fc.getX(), fc.getZ(), fc.getBitMask());
|
sendChunk(fc.getX(), fc.getZ(), fc.getBitMask());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendPacket(int cx, int cz, Packet packet) {
|
||||||
|
PlayerChunk chunk = getPlayerChunk(nmsWorld, cx, cz);
|
||||||
|
if (chunk != null) {
|
||||||
|
for (EntityPlayer player : chunk.c) {
|
||||||
|
player.playerConnection.sendPacket(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private PlayerChunk getPlayerChunk(WorldServer w, int cx, int cz) {
|
private PlayerChunk getPlayerChunk(WorldServer w, int cx, int cz) {
|
||||||
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
||||||
PlayerChunk playerChunk = chunkMap.getChunk(cx, cz);
|
PlayerChunk playerChunk = chunkMap.getChunk(cx, cz);
|
||||||
|
@ -13,7 +13,9 @@ commands:
|
|||||||
aliases: [fawecancel,/fcancel,/cancel,/fawecancel]
|
aliases: [fawecancel,/fcancel,/cancel,/fawecancel]
|
||||||
permissions:
|
permissions:
|
||||||
fawe.plotsquared:
|
fawe.plotsquared:
|
||||||
default: true
|
default: true
|
||||||
|
children:
|
||||||
|
fawe.plotsquared.trusted: true
|
||||||
fawe.plotme:
|
fawe.plotme:
|
||||||
default: true
|
default: true
|
||||||
fawe.bypass:
|
fawe.bypass:
|
||||||
|
@ -628,30 +628,32 @@ public class Fawe {
|
|||||||
debug(" - https://discord.gg/ngZCzbU");
|
debug(" - https://discord.gg/ngZCzbU");
|
||||||
debug("=======================================");
|
debug("=======================================");
|
||||||
}
|
}
|
||||||
try {
|
if (!Settings.IMP.EXPERIMENTAL.DISABLE_NATIVES) {
|
||||||
com.github.luben.zstd.util.Native.load();
|
try {
|
||||||
} catch (Throwable e) {
|
com.github.luben.zstd.util.Native.load();
|
||||||
if (Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL > 6 || Settings.IMP.HISTORY.COMPRESSION_LEVEL > 6) {
|
} catch (Throwable e) {
|
||||||
Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL = Math.min(6, Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL);
|
if (Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL > 6 || Settings.IMP.HISTORY.COMPRESSION_LEVEL > 6) {
|
||||||
Settings.IMP.HISTORY.COMPRESSION_LEVEL = Math.min(6, Settings.IMP.HISTORY.COMPRESSION_LEVEL);
|
Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL = Math.min(6, Settings.IMP.CLIPBOARD.COMPRESSION_LEVEL);
|
||||||
debug("====== ZSTD COMPRESSION BINDING NOT FOUND ======");
|
Settings.IMP.HISTORY.COMPRESSION_LEVEL = Math.min(6, Settings.IMP.HISTORY.COMPRESSION_LEVEL);
|
||||||
|
debug("====== ZSTD COMPRESSION BINDING NOT FOUND ======");
|
||||||
|
debug(e);
|
||||||
|
debug("===============================================");
|
||||||
|
debug("FAWE will work but won't compress data as much");
|
||||||
|
debug("===============================================");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
net.jpountz.util.Native.load();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
debug("====== LZ4 COMPRESSION BINDING NOT FOUND ======");
|
||||||
debug(e);
|
debug(e);
|
||||||
debug("===============================================");
|
debug("===============================================");
|
||||||
debug("FAWE will work but won't compress data as much");
|
debug("FAWE will work but compression will be slower");
|
||||||
|
debug(" - Try updating your JVM / OS");
|
||||||
|
debug(" - Report this issue if you cannot resolve it");
|
||||||
debug("===============================================");
|
debug("===============================================");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
net.jpountz.util.Native.load();
|
|
||||||
} catch (Throwable e) {
|
|
||||||
debug("====== LZ4 COMPRESSION BINDING NOT FOUND ======");
|
|
||||||
debug(e);
|
|
||||||
debug("===============================================");
|
|
||||||
debug("FAWE will work but compression will be slower");
|
|
||||||
debug(" - Try updating your JVM / OS");
|
|
||||||
debug(" - Report this issue if you cannot resolve it");
|
|
||||||
debug("===============================================");
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
String arch = System.getenv("PROCESSOR_ARCHITECTURE");
|
String arch = System.getenv("PROCESSOR_ARCHITECTURE");
|
||||||
String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
|
String wow64Arch = System.getenv("PROCESSOR_ARCHITEW6432");
|
||||||
|
@ -40,6 +40,8 @@ public interface IFawe {
|
|||||||
|
|
||||||
default ImageViewer getImageViewer(FawePlayer player) { return null; }
|
default ImageViewer getImageViewer(FawePlayer player) { return null; }
|
||||||
|
|
||||||
|
public default void registerPacketListener() {}
|
||||||
|
|
||||||
default int getPlayerCount() {
|
default int getPlayerCount() {
|
||||||
return Fawe.get().getCachedPlayers().size();
|
return Fawe.get().getCachedPlayers().size();
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,7 @@ import com.boydti.fawe.jnbt.anvil.HeightMapMCAGenerator;
|
|||||||
import com.boydti.fawe.object.FawePlayer;
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.object.clipboard.MultiClipboardHolder;
|
import com.boydti.fawe.object.clipboard.MultiClipboardHolder;
|
||||||
import com.boydti.fawe.util.CleanTextureUtil;
|
import com.boydti.fawe.util.*;
|
||||||
import com.boydti.fawe.util.FilteredTextureUtil;
|
|
||||||
import com.boydti.fawe.util.ImgurUtility;
|
|
||||||
import com.boydti.fawe.util.StringMan;
|
|
||||||
import com.boydti.fawe.util.TaskManager;
|
|
||||||
import com.boydti.fawe.util.TextureUtil;
|
|
||||||
import com.boydti.fawe.util.chat.Message;
|
import com.boydti.fawe.util.chat.Message;
|
||||||
import com.boydti.fawe.util.image.ImageUtil;
|
import com.boydti.fawe.util.image.ImageUtil;
|
||||||
import com.intellectualcrafters.plot.PS;
|
import com.intellectualcrafters.plot.PS;
|
||||||
@ -33,11 +28,8 @@ import com.sk89q.minecraft.util.commands.Command;
|
|||||||
import com.sk89q.minecraft.util.commands.CommandContext;
|
import com.sk89q.minecraft.util.commands.CommandContext;
|
||||||
import com.sk89q.minecraft.util.commands.CommandException;
|
import com.sk89q.minecraft.util.commands.CommandException;
|
||||||
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||||
import com.sk89q.worldedit.EmptyClipboardException;
|
import com.sk89q.worldedit.*;
|
||||||
import com.sk89q.worldedit.LocalSession;
|
|
||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import com.sk89q.worldedit.command.MethodCommands;
|
import com.sk89q.worldedit.command.MethodCommands;
|
||||||
import com.sk89q.worldedit.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
@ -63,10 +55,9 @@ import java.io.File;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayDeque;
|
import java.text.DateFormat;
|
||||||
import java.util.HashSet;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Set;
|
import java.util.*;
|
||||||
import java.util.UUID;
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
@Command(aliases = {"/cfi"}, desc = "Create a world from images: [More Info](https://git.io/v5iDy)")
|
@Command(aliases = {"/cfi"}, desc = "Create a world from images: [More Info](https://git.io/v5iDy)")
|
||||||
@ -95,7 +86,7 @@ public class CFICommands extends MethodCommands {
|
|||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.cfi")
|
@CommandPermissions("worldedit.anvil.cfi")
|
||||||
public void heightmap(FawePlayer fp, BufferedImage image) {
|
public void heightmap(FawePlayer fp, BufferedImage image) {
|
||||||
HeightMapMCAGenerator generator = new HeightMapMCAGenerator(image, getFolder("CFI-" + UUID.randomUUID()));
|
HeightMapMCAGenerator generator = new HeightMapMCAGenerator(image, getFolder(generateName()));
|
||||||
setup(generator, fp);
|
setup(generator, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,14 +97,20 @@ public class CFICommands extends MethodCommands {
|
|||||||
)
|
)
|
||||||
@CommandPermissions("worldedit.anvil.cfi")
|
@CommandPermissions("worldedit.anvil.cfi")
|
||||||
public void heightmap(FawePlayer fp, int width, int length) {
|
public void heightmap(FawePlayer fp, int width, int length) {
|
||||||
HeightMapMCAGenerator generator = new HeightMapMCAGenerator(width, length, getFolder("CFI-" + UUID.randomUUID()));
|
HeightMapMCAGenerator generator = new HeightMapMCAGenerator(width, length, getFolder(generateName()));
|
||||||
setup(generator, fp);
|
setup(generator, fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String generateName() {
|
||||||
|
DateFormat df = new SimpleDateFormat("dd.MM.yyyy HH.mm.ss");
|
||||||
|
String data = df.format(new Date());
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
private void setup(HeightMapMCAGenerator generator, FawePlayer fp) {
|
private void setup(HeightMapMCAGenerator generator, FawePlayer fp) {
|
||||||
CFISettings settings = getSettings(fp);
|
CFISettings settings = getSettings(fp).remove();
|
||||||
settings.remove().setGenerator(generator).bind();
|
|
||||||
generator.setPacketViewer(fp);
|
generator.setPacketViewer(fp);
|
||||||
|
settings.setGenerator(generator).bind();
|
||||||
generator.setImageViewer(Fawe.imp().getImageViewer(fp));
|
generator.setImageViewer(Fawe.imp().getImageViewer(fp));
|
||||||
generator.update();
|
generator.update();
|
||||||
mainMenu(fp);
|
mainMenu(fp);
|
||||||
@ -1021,6 +1018,8 @@ public class CFICommands extends MethodCommands {
|
|||||||
|
|
||||||
protected String category;
|
protected String category;
|
||||||
|
|
||||||
|
private boolean bound;
|
||||||
|
|
||||||
public CFISettings(FawePlayer player) {
|
public CFISettings(FawePlayer player) {
|
||||||
this.fp = player;
|
this.fp = player;
|
||||||
}
|
}
|
||||||
@ -1078,10 +1077,13 @@ public class CFICommands extends MethodCommands {
|
|||||||
|
|
||||||
public CFISettings setGenerator(HeightMapMCAGenerator generator) {
|
public CFISettings setGenerator(HeightMapMCAGenerator generator) {
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
|
if (bound) fp.getSession().setVirtualWorld(generator);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CFISettings bind() {
|
public CFISettings bind() {
|
||||||
|
if (generator != null) fp.getSession().setVirtualWorld(generator);
|
||||||
|
bound = true;
|
||||||
fp.setMeta("CFISettings", this);
|
fp.setMeta("CFISettings", this);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -1099,11 +1101,10 @@ public class CFICommands extends MethodCommands {
|
|||||||
fp.deleteMeta("CFISettings");
|
fp.deleteMeta("CFISettings");
|
||||||
HeightMapMCAGenerator gen = this.generator;
|
HeightMapMCAGenerator gen = this.generator;
|
||||||
if (gen != null) {
|
if (gen != null) {
|
||||||
gen.close();
|
fp.getSession().setVirtualWorld(null);
|
||||||
LocalSession session = fp.getSession();
|
|
||||||
session.clearHistory();
|
|
||||||
}
|
}
|
||||||
popMessages(fp);
|
popMessages(fp);
|
||||||
|
bound = false;
|
||||||
generator = null;
|
generator = null;
|
||||||
image = null;
|
image = null;
|
||||||
imageArg = null;
|
imageArg = null;
|
||||||
|
@ -4,6 +4,7 @@ import com.boydti.fawe.config.BBC;
|
|||||||
import com.boydti.fawe.object.FaweCommand;
|
import com.boydti.fawe.object.FaweCommand;
|
||||||
import com.boydti.fawe.object.FawePlayer;
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
import com.boydti.fawe.object.FaweQueue;
|
import com.boydti.fawe.object.FaweQueue;
|
||||||
|
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
||||||
import com.boydti.fawe.util.SetQueue;
|
import com.boydti.fawe.util.SetQueue;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -35,6 +36,10 @@ public class Cancel extends FaweCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
VirtualWorld world = player.getSession().getVirtualWorld();
|
||||||
|
if (world != null) {
|
||||||
|
world.clear();
|
||||||
|
}
|
||||||
BBC.WORLDEDIT_CANCEL_COUNT.send(player, cancelled);
|
BBC.WORLDEDIT_CANCEL_COUNT.send(player, cancelled);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +185,15 @@ public enum BBC {
|
|||||||
NOTHING_CONFIRMED("You have no actions pending confirmation.", "WorldEdit.Utility"),
|
NOTHING_CONFIRMED("You have no actions pending confirmation.", "WorldEdit.Utility"),
|
||||||
|
|
||||||
|
|
||||||
|
SCHEMATIC_PROMPT_CLEAR("&7You may want to use &c%s0 &7to clear your current clipboard first", "Worldedit.Schematic"),
|
||||||
|
SCHEMATIC_SHOW("&7Displaying &a%s0&7 schematics from &a%s1&7:\n" +
|
||||||
|
"&8 - &aLeft click &7a structure to set your clipboard\n" +
|
||||||
|
"&8 - &aRight click &7to add a structure to your multi-clipboard\n" +
|
||||||
|
"&8 - &7Use &a%s2&7 to go back to the world", "Worldedit.Schematic"),
|
||||||
SCHEMATIC_FORMAT("Available formats (Name: Lookup names)", "Worldedit.Schematic"),
|
SCHEMATIC_FORMAT("Available formats (Name: Lookup names)", "Worldedit.Schematic"),
|
||||||
|
SCHEMATIC_MOVE_EXISTS("&c%s0 already exists", "Worldedit.Schematic"),
|
||||||
|
SCHEMATIC_MOVE_SUCCESS("&a%s0 -> %s1", "Worldedit.Schematic"),
|
||||||
|
SCHEMATIC_MOVE_FAILED("&a%s0 no moved: %s1", "Worldedit.Schematic"),
|
||||||
SCHEMATIC_LOADED("%s0 loaded. Paste it with //paste", "Worldedit.Schematic"),
|
SCHEMATIC_LOADED("%s0 loaded. Paste it with //paste", "Worldedit.Schematic"),
|
||||||
SCHEMATIC_SAVED("%s0 saved.", "Worldedit.Schematic"),
|
SCHEMATIC_SAVED("%s0 saved.", "Worldedit.Schematic"),
|
||||||
SCHEMATIC_PAGE("Page must be %s", "WorldEdit.Schematic"),
|
SCHEMATIC_PAGE("Page must be %s", "WorldEdit.Schematic"),
|
||||||
|
@ -72,7 +72,10 @@ public class Settings extends Config {
|
|||||||
public String TEXTURES = "textures";
|
public String TEXTURES = "textures";
|
||||||
public String HEIGHTMAP = "heightmap";
|
public String HEIGHTMAP = "heightmap";
|
||||||
public String HISTORY = "history";
|
public String HISTORY = "history";
|
||||||
@Comment("Multiple servers can use the same clipboards")
|
@Comment({
|
||||||
|
"Multiple servers can use the same clipboards",
|
||||||
|
" - Use a shared directory or NFS/Samba"
|
||||||
|
})
|
||||||
public String CLIPBOARD = "clipboard";
|
public String CLIPBOARD = "clipboard";
|
||||||
@Comment("Each player has their own sub directory for schematics")
|
@Comment("Each player has their own sub directory for schematics")
|
||||||
public boolean PER_PLAYER_SCHEMATICS = true;
|
public boolean PER_PLAYER_SCHEMATICS = true;
|
||||||
@ -315,6 +318,11 @@ public class Settings extends Config {
|
|||||||
})
|
})
|
||||||
public boolean VANILLA_CUI = false;
|
public boolean VANILLA_CUI = false;
|
||||||
|
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Disable using native libraries",
|
||||||
|
})
|
||||||
|
public boolean DISABLE_NATIVES = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class WEB {
|
public static class WEB {
|
||||||
|
@ -3,41 +3,20 @@ package com.boydti.fawe.jnbt.anvil;
|
|||||||
import com.boydti.fawe.Fawe;
|
import com.boydti.fawe.Fawe;
|
||||||
import com.boydti.fawe.FaweCache;
|
import com.boydti.fawe.FaweCache;
|
||||||
import com.boydti.fawe.example.SimpleCharFaweChunk;
|
import com.boydti.fawe.example.SimpleCharFaweChunk;
|
||||||
import com.boydti.fawe.object.FaweChunk;
|
import com.boydti.fawe.object.*;
|
||||||
import com.boydti.fawe.object.FaweInputStream;
|
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
||||||
import com.boydti.fawe.object.FaweLocation;
|
|
||||||
import com.boydti.fawe.object.FaweOutputStream;
|
|
||||||
import com.boydti.fawe.object.FawePlayer;
|
|
||||||
import com.boydti.fawe.object.FaweQueue;
|
|
||||||
import com.boydti.fawe.object.Metadatable;
|
|
||||||
import com.boydti.fawe.object.PseudoRandom;
|
|
||||||
import com.boydti.fawe.object.RunnableVal2;
|
|
||||||
import com.boydti.fawe.object.change.StreamChange;
|
import com.boydti.fawe.object.change.StreamChange;
|
||||||
import com.boydti.fawe.object.changeset.CFIChangeSet;
|
import com.boydti.fawe.object.changeset.CFIChangeSet;
|
||||||
import com.boydti.fawe.object.collection.DifferentialArray;
|
import com.boydti.fawe.object.collection.*;
|
||||||
import com.boydti.fawe.object.collection.DifferentialBlockBuffer;
|
|
||||||
import com.boydti.fawe.object.collection.IterableThreadLocal;
|
|
||||||
import com.boydti.fawe.object.collection.LocalBlockVector2DSet;
|
|
||||||
import com.boydti.fawe.object.collection.SummedAreaTable;
|
|
||||||
import com.boydti.fawe.object.exception.FaweException;
|
import com.boydti.fawe.object.exception.FaweException;
|
||||||
import com.boydti.fawe.object.queue.LazyFaweChunk;
|
import com.boydti.fawe.object.queue.LazyFaweChunk;
|
||||||
import com.boydti.fawe.object.schematic.Schematic;
|
import com.boydti.fawe.object.schematic.Schematic;
|
||||||
import com.boydti.fawe.util.CachedTextureUtil;
|
import com.boydti.fawe.util.*;
|
||||||
import com.boydti.fawe.util.RandomTextureUtil;
|
|
||||||
import com.boydti.fawe.util.ReflectionUtils;
|
|
||||||
import com.boydti.fawe.util.SetQueue;
|
|
||||||
import com.boydti.fawe.util.TaskManager;
|
|
||||||
import com.boydti.fawe.util.TextureUtil;
|
|
||||||
import com.boydti.fawe.util.image.Drawable;
|
import com.boydti.fawe.util.image.Drawable;
|
||||||
import com.boydti.fawe.util.image.ImageViewer;
|
import com.boydti.fawe.util.image.ImageViewer;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.worldedit.BlockVector;
|
import com.sk89q.worldedit.*;
|
||||||
import com.sk89q.worldedit.EditSession;
|
|
||||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
|
||||||
import com.sk89q.worldedit.MutableBlockVector;
|
|
||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
import com.sk89q.worldedit.Vector2D;
|
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import com.sk89q.worldedit.blocks.BaseItemStack;
|
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||||
import com.sk89q.worldedit.blocks.BlockID;
|
import com.sk89q.worldedit.blocks.BlockID;
|
||||||
@ -51,24 +30,18 @@ import com.sk89q.worldedit.regions.CuboidRegion;
|
|||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||||
import com.sk89q.worldedit.util.TreeGenerator;
|
import com.sk89q.worldedit.util.TreeGenerator;
|
||||||
import com.sk89q.worldedit.world.SimpleWorld;
|
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
import com.sk89q.worldedit.world.registry.WorldData;
|
import com.sk89q.worldedit.world.registry.WorldData;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.Closeable;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class HeightMapMCAGenerator extends MCAWriter implements SimpleWorld, FaweQueue, StreamChange, Closeable, Drawable {
|
public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Drawable, VirtualWorld {
|
||||||
private final MutableBlockVector mutable = new MutableBlockVector();
|
private final MutableBlockVector mutable = new MutableBlockVector();
|
||||||
|
|
||||||
private final ThreadLocal<int[]> indexStore = new ThreadLocal<int[]>() {
|
private final ThreadLocal<int[]> indexStore = new ThreadLocal<int[]>() {
|
||||||
@ -251,6 +224,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements SimpleWorld, Faw
|
|||||||
throw new UnsupportedOperationException("Not supported: Queue is not backed by a real world");
|
throw new UnsupportedOperationException("Not supported: Queue is not backed by a real world");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Vector getOrigin() {
|
public Vector getOrigin() {
|
||||||
return new BlockVector(chunkOffset.getBlockX() << 4, 0, chunkOffset.getBlockZ() << 4);
|
return new BlockVector(chunkOffset.getBlockX() << 4, 0, chunkOffset.getBlockZ() << 4);
|
||||||
}
|
}
|
||||||
@ -286,6 +260,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements SimpleWorld, Faw
|
|||||||
return viewer;
|
return viewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void update() {
|
public void update() {
|
||||||
if (viewer != null) {
|
if (viewer != null) {
|
||||||
viewer.view(this);
|
viewer.view(this);
|
||||||
@ -326,9 +301,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements SimpleWorld, Faw
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// FaweChunk toSend = getSnapshot(chunk, finalCX, finalCZ);
|
|
||||||
// toSend.setLoc(HeightMapMCAGenerator.this, finalCX + OX, finalCZ + OZ);
|
|
||||||
// packetQueue.sendChunkUpdate(toSend, player);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -695,6 +667,11 @@ public class HeightMapMCAGenerator extends MCAWriter implements SimpleWorld, Faw
|
|||||||
return new Vector(0, 0, 0);
|
return new Vector(0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FawePlayer getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vector getMaximumPoint() {
|
public Vector getMaximumPoint() {
|
||||||
return new Vector(getWidth() - 1, 255, getLength() - 1);
|
return new Vector(getWidth() - 1, 255, getLength() - 1);
|
||||||
@ -774,6 +751,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements SimpleWorld, Faw
|
|||||||
return new SimpleCharFaweChunk(this, chunkX, chunkZ);
|
return new SimpleCharFaweChunk(this, chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public FaweChunk getSnapshot(int chunkX, int chunkZ) {
|
public FaweChunk getSnapshot(int chunkX, int chunkZ) {
|
||||||
return getSnapshot(null, chunkX, chunkZ);
|
return getSnapshot(null, chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
@ -899,9 +877,9 @@ public class HeightMapMCAGenerator extends MCAWriter implements SimpleWorld, Faw
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close(boolean update) {
|
||||||
clear();
|
clear();
|
||||||
if (chunkOffset != null && player != null) {
|
if (chunkOffset != null && player != null && update) {
|
||||||
FaweQueue packetQueue = SetQueue.IMP.getNewQueue(player.getWorld(), true, false);
|
FaweQueue packetQueue = SetQueue.IMP.getNewQueue(player.getWorld(), true, false);
|
||||||
|
|
||||||
int lenCX = (getWidth() + 15) >> 4;
|
int lenCX = (getWidth() + 15) >> 4;
|
||||||
@ -925,6 +903,11 @@ public class HeightMapMCAGenerator extends MCAWriter implements SimpleWorld, Faw
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (player != null) {
|
||||||
|
player.deleteMeta("CFISettings");
|
||||||
|
LocalSession session = player.getSession();
|
||||||
|
session.clearHistory();
|
||||||
|
}
|
||||||
player = null;
|
player = null;
|
||||||
chunkOffset = null;
|
chunkOffset = null;
|
||||||
}
|
}
|
||||||
@ -2151,7 +2134,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements SimpleWorld, Faw
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMaxY() {
|
public int getMaxY() {
|
||||||
return SimpleWorld.super.getMaxY();
|
return 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -11,24 +11,11 @@ import com.boydti.fawe.util.ArrayUtil;
|
|||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.MathMan;
|
import com.boydti.fawe.util.MathMan;
|
||||||
import com.boydti.fawe.util.ReflectionUtils;
|
import com.boydti.fawe.util.ReflectionUtils;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.*;
|
||||||
import com.sk89q.jnbt.IntTag;
|
|
||||||
import com.sk89q.jnbt.ListTag;
|
|
||||||
import com.sk89q.jnbt.NBTConstants;
|
|
||||||
import com.sk89q.jnbt.NBTInputStream;
|
|
||||||
import com.sk89q.jnbt.NBTOutputStream;
|
|
||||||
import com.sk89q.jnbt.Tag;
|
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class MCAChunk extends FaweChunk<Void> {
|
public class MCAChunk extends FaweChunk<Void> {
|
||||||
|
|
||||||
@ -102,13 +89,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] toBytes(byte[] buffer) throws IOException {
|
public void write(NBTOutputStream nbtOut) throws IOException {
|
||||||
if (buffer == null) {
|
|
||||||
buffer = new byte[8192];
|
|
||||||
}
|
|
||||||
FastByteArrayOutputStream buffered = new FastByteArrayOutputStream(buffer);
|
|
||||||
DataOutputStream dataOut = new DataOutputStream(buffered);
|
|
||||||
NBTOutputStream nbtOut = new NBTOutputStream((DataOutput) dataOut);
|
|
||||||
nbtOut.writeNamedTagName("", NBTConstants.TYPE_COMPOUND);
|
nbtOut.writeNamedTagName("", NBTConstants.TYPE_COMPOUND);
|
||||||
nbtOut.writeLazyCompoundTag("Level", new NBTOutputStream.LazyWrite() {
|
nbtOut.writeLazyCompoundTag("Level", new NBTOutputStream.LazyWrite() {
|
||||||
@Override
|
@Override
|
||||||
@ -135,12 +116,12 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
}
|
}
|
||||||
out.writeNamedTag("HeightMap", heightMap);
|
out.writeNamedTag("HeightMap", heightMap);
|
||||||
out.writeNamedTagName("Sections", NBTConstants.TYPE_LIST);
|
out.writeNamedTagName("Sections", NBTConstants.TYPE_LIST);
|
||||||
dataOut.writeByte(NBTConstants.TYPE_COMPOUND);
|
nbtOut.getOutputStream().writeByte(NBTConstants.TYPE_COMPOUND);
|
||||||
int len = 0;
|
int len = 0;
|
||||||
for (int layer = 0; layer < ids.length; layer++) {
|
for (int layer = 0; layer < ids.length; layer++) {
|
||||||
if (ids[layer] != null) len++;
|
if (ids[layer] != null) len++;
|
||||||
}
|
}
|
||||||
dataOut.writeInt(len);
|
nbtOut.getOutputStream().writeInt(len);
|
||||||
for (int layer = 0; layer < ids.length; layer++) {
|
for (int layer = 0; layer < ids.length; layer++) {
|
||||||
byte[] idLayer = ids[layer];
|
byte[] idLayer = ids[layer];
|
||||||
if (idLayer == null) {
|
if (idLayer == null) {
|
||||||
@ -156,7 +137,17 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
nbtOut.writeEndTag();
|
nbtOut.writeEndTag();
|
||||||
nbtOut.close();
|
}
|
||||||
|
|
||||||
|
public byte[] toBytes(byte[] buffer) throws IOException {
|
||||||
|
if (buffer == null) {
|
||||||
|
buffer = new byte[8192];
|
||||||
|
}
|
||||||
|
FastByteArrayOutputStream buffered = new FastByteArrayOutputStream(buffer);
|
||||||
|
DataOutputStream dataOut = new DataOutputStream(buffered);
|
||||||
|
try (NBTOutputStream nbtOut = new NBTOutputStream((DataOutput) dataOut)) {
|
||||||
|
write(nbtOut);
|
||||||
|
}
|
||||||
return buffered.toByteArray();
|
return buffered.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,7 +456,7 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
return FaweCache.asTag(root);
|
return FaweCache.asTag(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MCAChunk(NBTInputStream nis, FaweQueue parent, int x, int z, int compressedSize) throws IOException {
|
public MCAChunk(NBTInputStream nis, FaweQueue parent, int x, int z, boolean readPos) throws IOException {
|
||||||
super(parent, x, z);
|
super(parent, x, z);
|
||||||
ids = new byte[16][];
|
ids = new byte[16][];
|
||||||
data = new byte[16][];
|
data = new byte[16][];
|
||||||
@ -527,6 +518,20 @@ public class MCAChunk extends FaweChunk<Void> {
|
|||||||
heightMap = value;
|
heightMap = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (readPos) {
|
||||||
|
streamer.addReader(".Level.xPos", new RunnableVal2<Integer, Integer>() {
|
||||||
|
@Override
|
||||||
|
public void run(Integer index, Integer value) {
|
||||||
|
MCAChunk.this.setLoc(getParent(), value, getZ());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
streamer.addReader(".Level.zPos", new RunnableVal2<Integer, Integer>() {
|
||||||
|
@Override
|
||||||
|
public void run(Integer index, Integer value) {
|
||||||
|
MCAChunk.this.setLoc(getParent(), getX(), value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
streamer.readFully();
|
streamer.readFully();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +86,17 @@ public class MCAFile {
|
|||||||
Z = Integer.parseInt(split[2]);
|
Z = Integer.parseInt(split[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MCAFile(FaweQueue parent, int mcrX, int mcrZ) throws Exception {
|
||||||
|
this(parent, mcrX, mcrZ, new File(parent.getSaveFolder(), "r." + mcrX + "." + mcrZ + ".mca"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MCAFile(FaweQueue parent, int mcrX, int mcrZ, File file) {
|
||||||
|
this.queue = parent;
|
||||||
|
this.file = file;
|
||||||
|
X = mcrX;
|
||||||
|
Z = mcrZ;
|
||||||
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
if (raf != null) {
|
if (raf != null) {
|
||||||
try {
|
try {
|
||||||
@ -130,12 +141,14 @@ public class MCAFile {
|
|||||||
try {
|
try {
|
||||||
if (raf == null) {
|
if (raf == null) {
|
||||||
this.locations = new byte[4096];
|
this.locations = new byte[4096];
|
||||||
this.raf = new RandomAccessFile(file, "rw");
|
if (file != null) {
|
||||||
if (raf.length() < 8192) {
|
this.raf = new RandomAccessFile(file, "rw");
|
||||||
raf.setLength(8192);
|
if (raf.length() < 8192) {
|
||||||
} else {
|
raf.setLength(8192);
|
||||||
raf.seek(0);
|
} else {
|
||||||
raf.readFully(locations);
|
raf.seek(0);
|
||||||
|
raf.readFully(locations);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@ -143,10 +156,6 @@ public class MCAFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MCAFile(FaweQueue parent, int mcrX, int mcrZ) throws Exception {
|
|
||||||
this(parent, new File(parent.getSaveFolder(), "r." + mcrX + "." + mcrZ + ".mca"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getX() {
|
public int getX() {
|
||||||
return X;
|
return X;
|
||||||
}
|
}
|
||||||
@ -196,7 +205,7 @@ public class MCAFile {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
NBTInputStream nis = getChunkIS(offset);
|
NBTInputStream nis = getChunkIS(offset);
|
||||||
MCAChunk chunk = new MCAChunk(nis, queue, cx, cz, size);
|
MCAChunk chunk = new MCAChunk(nis, queue, cx, cz, false);
|
||||||
nis.close();
|
nis.close();
|
||||||
int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31));
|
int pair = MathMan.pair((short) (cx & 31), (short) (cz & 31));
|
||||||
synchronized (chunks) {
|
synchronized (chunks) {
|
||||||
|
@ -116,38 +116,38 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
|||||||
int otherBCZ = (obz) >> 4;
|
int otherBCZ = (obz) >> 4;
|
||||||
int otherTCX = (otx) >> 4;
|
int otherTCX = (otx) >> 4;
|
||||||
int otherTCZ = (otz) >> 4;
|
int otherTCZ = (otz) >> 4;
|
||||||
int cx = newChunk.getX();
|
int cx = newChunk.getX();
|
||||||
int cz = newChunk.getZ();
|
int cz = newChunk.getZ();
|
||||||
int cbx = (cx << 4) - oX;
|
int cbx = (cx << 4) - oX;
|
||||||
int cbz = (cz << 4) - oZ;
|
int cbz = (cz << 4) - oZ;
|
||||||
|
|
||||||
boolean changed = false;
|
boolean changed = false;
|
||||||
for (int otherCZ = otherBCZ; otherCZ <= otherTCZ; otherCZ++) {
|
for (int otherCZ = otherBCZ; otherCZ <= otherTCZ; otherCZ++) {
|
||||||
for (int otherCX = otherBCX; otherCX <= otherTCX; otherCX++) {
|
for (int otherCX = otherBCX; otherCX <= otherTCX; otherCX++) {
|
||||||
FaweChunk chunk;
|
FaweChunk chunk;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
chunk = this.getFaweChunk(otherCX, otherCZ);
|
chunk = this.getFaweChunk(otherCX, otherCZ);
|
||||||
}
|
}
|
||||||
if (!(chunk instanceof NullFaweChunk)) {
|
if (!(chunk instanceof NullFaweChunk)) {
|
||||||
changed = true;
|
changed = true;
|
||||||
MCAChunk other = (MCAChunk) chunk;
|
MCAChunk other = (MCAChunk) chunk;
|
||||||
int ocbx = otherCX << 4;
|
int ocbx = otherCX << 4;
|
||||||
int ocbz = otherCZ << 4;
|
int ocbz = otherCZ << 4;
|
||||||
int octx = ocbx + 15;
|
int octx = ocbx + 15;
|
||||||
int octz = ocbz + 15;
|
int octz = ocbz + 15;
|
||||||
int offsetY = 0;
|
int offsetY = 0;
|
||||||
int minX = obx > ocbx ? (obx - ocbx) & 15 : 0;
|
int minX = obx > ocbx ? (obx - ocbx) & 15 : 0;
|
||||||
int maxX = otx < octx ? (otx - ocbx) : 15;
|
int maxX = otx < octx ? (otx - ocbx) : 15;
|
||||||
int minZ = obz > ocbz ? (obz - ocbz) & 15 : 0;
|
int minZ = obz > ocbz ? (obz - ocbz) & 15 : 0;
|
||||||
int maxZ = otz < octz ? (otz - ocbz) : 15;
|
int maxZ = otz < octz ? (otz - ocbz) : 15;
|
||||||
int offsetX = ocbx - cbx;
|
int offsetX = ocbx - cbx;
|
||||||
int offsetZ = ocbz - cbz;
|
int offsetZ = ocbz - cbz;
|
||||||
newChunk.copyFrom(other, minX, maxX, 0, 255, minZ, maxZ, offsetX, offsetY, offsetZ);
|
newChunk.copyFrom(other, minX, maxX, 0, 255, minZ, maxZ, offsetX, offsetY, offsetZ);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return changed;
|
|
||||||
}
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper region, Runnable whileLocked, boolean save, boolean unload) {
|
public boolean setMCA(int mcaX, int mcaZ, RegionWrapper region, Runnable whileLocked, boolean save, boolean unload) {
|
||||||
|
@ -53,13 +53,19 @@ public class MCAQueueMap implements IFaweQueueMap {
|
|||||||
if (lastFile == null) {
|
if (lastFile == null) {
|
||||||
try {
|
try {
|
||||||
queue.setMCA(lastFileX, lastFileZ, RegionWrapper.GLOBAL(), null, true, false);
|
queue.setMCA(lastFileX, lastFileZ, RegionWrapper.GLOBAL(), null, true, false);
|
||||||
File file = new File(queue.getSaveFolder(), "r." + lastFileX + "." + lastFileZ + ".mca");
|
File save = queue.getSaveFolder();
|
||||||
if (create) {
|
File file;
|
||||||
File parent = file.getParentFile();
|
if (save != null) {
|
||||||
if (!parent.exists()) parent.mkdirs();
|
file = new File(queue.getSaveFolder(), "r." + lastFileX + "." + lastFileZ + ".mca");
|
||||||
if (!file.exists()) file.createNewFile();
|
if (create) {
|
||||||
|
File parent = file.getParentFile();
|
||||||
|
if (!parent.exists()) parent.mkdirs();
|
||||||
|
if (!file.exists()) file.createNewFile();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
file = null;
|
||||||
}
|
}
|
||||||
lastFile = tmp = new MCAFile(queue, file);
|
lastFile = tmp = new MCAFile(queue, mcaX, mcaZ, file);
|
||||||
} catch (FaweException.FaweChunkLoadException ignore) {
|
} catch (FaweException.FaweChunkLoadException ignore) {
|
||||||
lastFile = null;
|
lastFile = null;
|
||||||
return null;
|
return null;
|
||||||
|
@ -56,7 +56,7 @@ public class DebugFixAir extends MCAFilterCounter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ids0[i] = BlockID.BEDROCK;
|
ids0[i] = BlockID.BEDROCK;
|
||||||
chunk.ids[4][i] = BlockID.GRASS;
|
if (chunk.ids[4][i] == 0) chunk.ids[4][i] = BlockID.GRASS;
|
||||||
cache.add(256);
|
cache.add(256);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.boydti.fawe.object;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public abstract class DelegateConsumer<T> implements Consumer<T> {
|
||||||
|
private final Consumer parent;
|
||||||
|
|
||||||
|
public DelegateConsumer(Consumer parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void accept(T o) {
|
||||||
|
parent.accept(o);
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package com.boydti.fawe.object;
|
package com.boydti.fawe.object;
|
||||||
|
|
||||||
|
import com.boydti.fawe.util.IOUtil;
|
||||||
import com.sk89q.jnbt.NBTInputStream;
|
import com.sk89q.jnbt.NBTInputStream;
|
||||||
import com.sk89q.jnbt.NamedTag;
|
import com.sk89q.jnbt.NamedTag;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
@ -64,16 +65,8 @@ public class FaweInputStream extends DataInputStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int readVarInt() throws IOException {
|
public final int readVarInt() throws IOException {
|
||||||
int i = 0;
|
return IOUtil.readVarInt(this);
|
||||||
int offset = 0;
|
|
||||||
int b;
|
|
||||||
while ((b = read()) > 127) {
|
|
||||||
i |= (b - 128) << offset;
|
|
||||||
offset += 7;
|
|
||||||
}
|
|
||||||
i |= b << offset;
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,7 +18,6 @@ public class FaweLimit {
|
|||||||
public boolean FAST_PLACEMENT = false;
|
public boolean FAST_PLACEMENT = false;
|
||||||
public boolean CONFIRM_LARGE = true;
|
public boolean CONFIRM_LARGE = true;
|
||||||
|
|
||||||
|
|
||||||
public static FaweLimit MAX;
|
public static FaweLimit MAX;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -5,7 +5,7 @@ import com.boydti.fawe.FaweAPI;
|
|||||||
import com.boydti.fawe.command.CFICommands;
|
import com.boydti.fawe.command.CFICommands;
|
||||||
import com.boydti.fawe.config.BBC;
|
import com.boydti.fawe.config.BBC;
|
||||||
import com.boydti.fawe.config.Settings;
|
import com.boydti.fawe.config.Settings;
|
||||||
import com.boydti.fawe.jnbt.anvil.HeightMapMCAGenerator;
|
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
||||||
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
||||||
import com.boydti.fawe.object.exception.FaweException;
|
import com.boydti.fawe.object.exception.FaweException;
|
||||||
import com.boydti.fawe.regions.FaweMaskManager;
|
import com.boydti.fawe.regions.FaweMaskManager;
|
||||||
@ -302,6 +302,13 @@ public abstract class FawePlayer<T> extends Metadatable {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean checkAction() {
|
||||||
|
long time = getMeta("faweActionTick", Long.MIN_VALUE);
|
||||||
|
long tick = Fawe.get().getTimer().getTick();
|
||||||
|
setMeta("faweActionTick", tick);
|
||||||
|
return tick > time;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads any history items from disk:
|
* Loads any history items from disk:
|
||||||
* - Should already be called if history on disk is enabled
|
* - Should already be called if history on disk is enabled
|
||||||
@ -610,16 +617,24 @@ public abstract class FawePlayer<T> extends Metadatable {
|
|||||||
return new EditSessionBuilder(getWorld()).player(this).build();
|
return new EditSessionBuilder(getWorld()).player(this).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setVirtualWorld(VirtualWorld world) {
|
||||||
|
getSession().setVirtualWorld(world);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the World the player is editing in (may not match the world they are in)<br/>
|
* Get the World the player is editing in (may not match the world they are in)<br/>
|
||||||
* - e.g. If they are editing a CFI world.<br/>
|
* - e.g. If they are editing a CFI world.<br/>
|
||||||
* @return Editing world
|
* @return Editing world
|
||||||
*/
|
*/
|
||||||
public World getWorldForEditing() {
|
public World getWorldForEditing() {
|
||||||
CFICommands.CFISettings cfi = getMeta("CFISettings");
|
VirtualWorld virtual = getSession().getVirtualWorld();
|
||||||
if (cfi != null && cfi.hasGenerator() && cfi.getGenerator().hasPacketViewer()) {
|
if (virtual != null) {
|
||||||
return cfi.getGenerator();
|
return virtual;
|
||||||
}
|
}
|
||||||
|
// CFICommands.CFISettings cfi = getMeta("CFISettings");
|
||||||
|
// if (cfi != null && cfi.hasGenerator() && cfi.getGenerator().hasPacketViewer()) {
|
||||||
|
// return cfi.getGenerator();
|
||||||
|
// }
|
||||||
return WorldEdit.getInstance().getPlatformManager().getWorldForEditing(getWorld());
|
return WorldEdit.getInstance().getPlatformManager().getWorldForEditing(getWorld());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,8 +655,8 @@ public abstract class FawePlayer<T> extends Metadatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PlayerProxy proxy = new PlayerProxy(player, permActor, cuiActor, world);
|
PlayerProxy proxy = new PlayerProxy(player, permActor, cuiActor, world);
|
||||||
if (world instanceof HeightMapMCAGenerator) {
|
if (world instanceof VirtualWorld) {
|
||||||
proxy.setOffset(Vector.ZERO.subtract(((HeightMapMCAGenerator) world).getOrigin()));
|
proxy.setOffset(Vector.ZERO.subtract(((VirtualWorld) world).getOrigin()));
|
||||||
}
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package com.boydti.fawe.object;
|
|||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public class RegionWrapper extends CuboidRegion {
|
public class RegionWrapper extends CuboidRegion {
|
||||||
private final static RegionWrapper GLOBAL = new RegionWrapper(Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
private final static RegionWrapper GLOBAL = new RegionWrapper(Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
@ -0,0 +1,265 @@
|
|||||||
|
package com.boydti.fawe.object.brush.visualization;
|
||||||
|
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.example.SimpleCharFaweChunk;
|
||||||
|
import com.boydti.fawe.object.FaweChunk;
|
||||||
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.object.RunnableVal2;
|
||||||
|
import com.boydti.fawe.object.exception.FaweException;
|
||||||
|
import com.boydti.fawe.util.SetQueue;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.worldedit.*;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||||
|
import com.sk89q.worldedit.function.operation.Operation;
|
||||||
|
import com.sk89q.worldedit.regions.Region;
|
||||||
|
import com.sk89q.worldedit.util.TreeGenerator;
|
||||||
|
import com.sk89q.worldedit.world.World;
|
||||||
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.UUID;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public abstract class ImmutableVirtualWorld implements VirtualWorld {
|
||||||
|
@Override
|
||||||
|
public int getMaxY() {
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<FaweChunk> getFaweChunks() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean regenerateChunk(int x, int z, @Nullable BaseBiome biome, @Nullable Long seed) {
|
||||||
|
return unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendBlockUpdate(FaweChunk chunk, FawePlayer... players) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getSaveFolder() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addNotifyTask(int x, int z, Runnable runnable) {
|
||||||
|
if (runnable != null) runnable.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseBiome getBiome(Vector2D position) {
|
||||||
|
return FaweCache.getBiome(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCombinedId4Data(int x, int y, int z, int def) {
|
||||||
|
return getCombinedId4Data(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCachedCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
|
||||||
|
return getCombinedId4Data(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasSky() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSkyLight(int x, int y, int z) {
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEmmittedLight(int x, int y, int z) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag getTileEntity(int x, int y, int z) throws FaweException.FaweChunkLoadException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWorld(String world) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public World getWEWorld() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWorldName() {
|
||||||
|
return getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getModified() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setModified(long modified) {
|
||||||
|
// Unsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RunnableVal2<ProgressType, Integer> getProgressTask() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProgressTask(RunnableVal2<ProgressType, Integer> progressTask) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChangeTask(RunnableVal2<FaweChunk, FaweChunk> changeTask) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RunnableVal2<FaweChunk, FaweChunk> getChangeTask() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SetQueue.QueueStage getStage() {
|
||||||
|
return SetQueue.QueueStage.NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setStage(SetQueue.QueueStage stage) {
|
||||||
|
// Not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addNotifyTask(Runnable runnable) {
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runTasks() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addTask(Runnable whenFree) {
|
||||||
|
whenFree.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Operation commit() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return Integer.toString(hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setBlock(Vector position, BaseBlock block, boolean notifyAndLight) throws WorldEditException {
|
||||||
|
return setBlock(position, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockLightLevel(Vector position) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearContainerBlockContents(Vector position) {
|
||||||
|
return unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dropItem(Vector position, BaseItemStack item) {
|
||||||
|
unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, Vector position) throws MaxChangedBlocksException {
|
||||||
|
return unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FaweChunk getFaweChunk(int chunkX, int chunkZ) {
|
||||||
|
return new SimpleCharFaweChunk(this, chunkX, chunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEntity(int x, int y, int z, CompoundTag tag) {
|
||||||
|
unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setBlock(Vector pt, BaseBlock block) throws WorldEditException {
|
||||||
|
return unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setBlock(int x, int y, int z, int id, int data) {
|
||||||
|
return unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTile(int x, int y, int z, CompoundTag tag) {
|
||||||
|
unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeEntity(int x, int y, int z, UUID uuid) {
|
||||||
|
unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setBiome(int x, int z, BaseBiome biome) {
|
||||||
|
return unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setChunk(FaweChunk chunk) {
|
||||||
|
unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean next(int amount, long time) {
|
||||||
|
return unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean regenerate(Region region, EditSession editSession) {
|
||||||
|
return unsupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
// do nothing - world is immutable
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean unsupported() {
|
||||||
|
throw new UnsupportedOperationException("World is immutable");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
package com.boydti.fawe.object.brush.visualization;
|
||||||
|
|
||||||
|
import com.boydti.fawe.object.FaweChunk;
|
||||||
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.object.FaweQueue;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.entity.Player;
|
||||||
|
import com.sk89q.worldedit.event.platform.BlockInteractEvent;
|
||||||
|
import com.sk89q.worldedit.event.platform.PlayerInputEvent;
|
||||||
|
import com.sk89q.worldedit.world.SimpleWorld;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface VirtualWorld extends SimpleWorld, FaweQueue, Closeable {
|
||||||
|
Vector getOrigin();
|
||||||
|
|
||||||
|
FaweChunk getSnapshot(int chunkX, int chunkZ);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
int getMaxY();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean setBlock(Vector pt, BaseBlock block) throws WorldEditException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default Vector getMaximumPoint() {
|
||||||
|
return FaweQueue.super.getMaximumPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default Vector getMinimumPoint() {
|
||||||
|
return FaweQueue.super.getMinimumPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
FawePlayer getPlayer();
|
||||||
|
|
||||||
|
void update();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void close() throws IOException {
|
||||||
|
close(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void close(boolean update) throws IOException;
|
||||||
|
|
||||||
|
default void handleBlockInteract(Player player, Vector pos, BlockInteractEvent event) {}
|
||||||
|
|
||||||
|
default void handlePlayerInput(Player player, PlayerInputEvent event) {}
|
||||||
|
}
|
@ -20,7 +20,7 @@ public class CFIChangeSet extends FaweChangeSet {
|
|||||||
|
|
||||||
public CFIChangeSet(HeightMapMCAGenerator hmmg, UUID uuid) throws IOException {
|
public CFIChangeSet(HeightMapMCAGenerator hmmg, UUID uuid) throws IOException {
|
||||||
super(hmmg);
|
super(hmmg);
|
||||||
File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + uuid + File.separator + hmmg.getWorldName());
|
File folder = MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.HISTORY + File.separator + uuid + File.separator + "CFI" + File.separator + hmmg.getWorldName());
|
||||||
int max = MainUtil.getMaxFileId(folder);
|
int max = MainUtil.getMaxFileId(folder);
|
||||||
this.file = new File(folder, Integer.toString(max) + ".cfi");
|
this.file = new File(folder, Integer.toString(max) + ".cfi");
|
||||||
File parent = this.file.getParentFile();
|
File parent = this.file.getParentFile();
|
||||||
|
@ -6,9 +6,7 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
|||||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||||
import com.sk89q.worldedit.world.registry.WorldData;
|
import com.sk89q.worldedit.world.registry.WorldData;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
@ -139,6 +137,18 @@ public class MultiClipboardHolder extends URIClipboardHolder {
|
|||||||
return available[index];
|
return available[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<URI> getURIs() {
|
||||||
|
Set<URI> set = new HashSet<>();
|
||||||
|
for (ClipboardHolder holder : getHolders()) {
|
||||||
|
if (holder instanceof URIClipboardHolder) {
|
||||||
|
URI uri = ((URIClipboardHolder) holder).getUri();
|
||||||
|
if (!uri.toString().isEmpty()) set.add(uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
cached = null;
|
cached = null;
|
||||||
|
@ -4,6 +4,8 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
|||||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||||
import com.sk89q.worldedit.world.registry.WorldData;
|
import com.sk89q.worldedit.world.registry.WorldData;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
@ -30,4 +32,8 @@ public class URIClipboardHolder extends ClipboardHolder {
|
|||||||
public URI getUri() {
|
public URI getUri() {
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<URI> getURIs() {
|
||||||
|
return Collections.singleton(uri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,553 @@
|
|||||||
|
package com.boydti.fawe.object.schematic.visualizer;
|
||||||
|
|
||||||
|
import com.boydti.fawe.config.BBC;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAChunk;
|
||||||
|
import com.boydti.fawe.jnbt.anvil.MCAQueue;
|
||||||
|
import com.boydti.fawe.object.*;
|
||||||
|
import com.boydti.fawe.object.brush.visualization.ImmutableVirtualWorld;
|
||||||
|
import com.boydti.fawe.object.clipboard.LazyClipboardHolder;
|
||||||
|
import com.boydti.fawe.object.clipboard.MultiClipboardHolder;
|
||||||
|
import com.boydti.fawe.object.clipboard.URIClipboardHolder;
|
||||||
|
import com.boydti.fawe.object.exception.FaweException;
|
||||||
|
import com.boydti.fawe.object.queue.LazyFaweChunk;
|
||||||
|
import com.boydti.fawe.object.schematic.Schematic;
|
||||||
|
import com.boydti.fawe.util.*;
|
||||||
|
import com.google.common.io.ByteSource;
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import com.sk89q.jnbt.NBTInputStream;
|
||||||
|
import com.sk89q.jnbt.NBTOutputStream;
|
||||||
|
import com.sk89q.worldedit.*;
|
||||||
|
import com.sk89q.worldedit.Vector;
|
||||||
|
import com.sk89q.worldedit.blocks.BlockID;
|
||||||
|
import com.sk89q.worldedit.entity.Player;
|
||||||
|
import com.sk89q.worldedit.event.platform.PlayerInputEvent;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
|
||||||
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||||
|
import com.sk89q.worldedit.util.Location;
|
||||||
|
import com.sk89q.worldedit.util.TargetBlock;
|
||||||
|
import com.sk89q.worldedit.world.registry.WorldData;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.file.LinkOption;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Immutable virtual world used to display & select schematics
|
||||||
|
*/
|
||||||
|
public class SchemVis extends ImmutableVirtualWorld {
|
||||||
|
private final WorldData worldData;
|
||||||
|
|
||||||
|
private final Long2ObjectOpenHashMap<Map.Entry<File, Long>> files;
|
||||||
|
private final Long2ObjectOpenHashMap<MCAChunk> chunks; // TODO use soft references OR clear chunks outside view distance
|
||||||
|
|
||||||
|
private final MutableBlockVector2D lastPos = new MutableBlockVector2D();
|
||||||
|
private final FawePlayer player;
|
||||||
|
private final Location origin;
|
||||||
|
private final BlockVector2D chunkOffset;
|
||||||
|
|
||||||
|
public SchemVis(FawePlayer player) {
|
||||||
|
this.files = new Long2ObjectOpenHashMap<>();
|
||||||
|
this.chunks = new Long2ObjectOpenHashMap<>();
|
||||||
|
this.player = player;
|
||||||
|
this.worldData = player.getWorld().getWorldData();
|
||||||
|
|
||||||
|
// Set the origin to somewhere around where the player currently is
|
||||||
|
FaweLocation pos = player.getLocation();
|
||||||
|
this.origin = player.getPlayer().getLocation();
|
||||||
|
this.chunkOffset = new BlockVector2D(pos.x >> 4,pos.z >> 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handlePlayerInput(Player player, PlayerInputEvent event) {
|
||||||
|
int range = 240;
|
||||||
|
BlockWorldVector target = new TargetBlock(player, range, 0.2).getAnyTargetBlock();
|
||||||
|
if (target != null) {
|
||||||
|
int chunkX = target.getBlockX() >> 4;
|
||||||
|
int chunkZ = target.getBlockZ() >> 4;
|
||||||
|
long pos = MathMan.pairInt(chunkX, chunkZ);
|
||||||
|
Map.Entry<File, Long> entry = files.get(pos);
|
||||||
|
if (entry != null) {
|
||||||
|
File cachedFile = entry.getKey();
|
||||||
|
String filename = cachedFile.getName();
|
||||||
|
// get non `.cached` file
|
||||||
|
File file = new File(cachedFile.getParentFile(), filename.substring(1, filename.length() - 7));
|
||||||
|
URI uri = file.toURI();
|
||||||
|
|
||||||
|
ClipboardFormat format = ClipboardFormat.findByFile(file);
|
||||||
|
if (format != null) {
|
||||||
|
LocalSession session = this.player.getSession();
|
||||||
|
try {
|
||||||
|
synchronized (this) {
|
||||||
|
switch (event.getInputType()) {
|
||||||
|
case PRIMARY: // set clipboard
|
||||||
|
format.hold(player, uri, new FileInputStream(file));
|
||||||
|
BBC.SCHEMATIC_LOADED.send(player, filename);
|
||||||
|
session.setVirtualWorld(null);
|
||||||
|
break;
|
||||||
|
case SECONDARY: // add/remove clipboard
|
||||||
|
ClipboardHolder existing = session.getExistingClipboard();
|
||||||
|
|
||||||
|
boolean contains = existing instanceof URIClipboardHolder && ((URIClipboardHolder) existing).contains(uri);
|
||||||
|
if (contains) {
|
||||||
|
// Remove it
|
||||||
|
if (existing instanceof MultiClipboardHolder) {
|
||||||
|
MultiClipboardHolder multi = ((MultiClipboardHolder) existing);
|
||||||
|
multi.remove(uri);
|
||||||
|
if (multi.getClipboards().isEmpty()) session.setClipboard(null);
|
||||||
|
} else {
|
||||||
|
session.setClipboard(null);
|
||||||
|
}
|
||||||
|
BBC.CLIPBOARD_CLEARED.send(player);
|
||||||
|
} else {
|
||||||
|
// Add it
|
||||||
|
ByteSource source = Files.asByteSource(file);
|
||||||
|
MultiClipboardHolder multi = new MultiClipboardHolder(URI.create(""), worldData, new LazyClipboardHolder(uri, source, format, worldData, null));
|
||||||
|
session.addClipboard(multi);
|
||||||
|
BBC.SCHEMATIC_LOADED.send(player, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resend relevant chunks
|
||||||
|
FaweQueue packetQueue = SetQueue.IMP.getNewQueue(this.player.getWorld(), true, false);
|
||||||
|
if (packetQueue.supports(Capability.CHUNK_PACKETS)) {
|
||||||
|
ArrayDeque<Long> toSend = new ArrayDeque<>();
|
||||||
|
int OX = chunkOffset.getBlockX();
|
||||||
|
int OZ = chunkOffset.getBlockZ();
|
||||||
|
ObjectIterator<Long2ObjectMap.Entry<MCAChunk>> iter = chunks.long2ObjectEntrySet().fastIterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Long2ObjectMap.Entry<MCAChunk> mcaChunkEntry = iter.next();
|
||||||
|
long curChunkPos = mcaChunkEntry.getLongKey();
|
||||||
|
Map.Entry<File, Long> curFileEntry = files.get(curChunkPos);
|
||||||
|
if (curFileEntry != null && curFileEntry == entry) {
|
||||||
|
MCAChunk chunk = mcaChunkEntry.getValue();
|
||||||
|
if (contains) {
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
else select(chunk);
|
||||||
|
toSend.add(curChunkPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (long curChunkPos : toSend) send(packetQueue, MathMan.unpairIntX(curChunkPos), MathMan.unpairIntY(curChunkPos));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discard chunks outside FOV
|
||||||
|
*/
|
||||||
|
private void clean() {
|
||||||
|
if (chunks.size() > 225) {
|
||||||
|
TaskManager.IMP.sync(() -> {
|
||||||
|
if (chunks.size() > 225) {
|
||||||
|
synchronized (SchemVis.this) {
|
||||||
|
FaweLocation pos = player.getLocation();
|
||||||
|
int centerX = pos.x >> 4;
|
||||||
|
int centerZ = pos.z >> 4;
|
||||||
|
ObjectIterator<Long2ObjectMap.Entry<MCAChunk>> iter = chunks.long2ObjectEntrySet().fastIterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Long2ObjectMap.Entry<MCAChunk> entry = iter.next();
|
||||||
|
long pair = entry.getLongKey();
|
||||||
|
int chunkX = MathMan.unpairIntX(pair);
|
||||||
|
int chunkZ = MathMan.unpairIntY(pair);
|
||||||
|
if (Math.abs(centerX - chunkX) > 15 || Math.abs(centerZ - chunkZ) > 15) {
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a chunk
|
||||||
|
* @param packetQueue
|
||||||
|
* @param chunkX
|
||||||
|
* @param chunkZ
|
||||||
|
*/
|
||||||
|
private void send(FaweQueue packetQueue, int chunkX, int chunkZ) {
|
||||||
|
TaskManager.IMP.getPublicForkJoinPool().submit(() -> {
|
||||||
|
try {
|
||||||
|
int OX = chunkOffset.getBlockX();
|
||||||
|
int OZ = chunkOffset.getBlockZ();
|
||||||
|
FaweChunk toSend = getSnapshot(chunkX, chunkZ);
|
||||||
|
toSend.setLoc(SchemVis.this, chunkX + OX, chunkZ + OZ);
|
||||||
|
packetQueue.sendChunkUpdate(toSend, SchemVis.this.player);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The offset for this virtual world
|
||||||
|
* @return offset vector
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Vector getOrigin() {
|
||||||
|
return new BlockVector(chunkOffset.getBlockX() << 4, 0, chunkOffset.getBlockZ() << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param chunkX
|
||||||
|
* @param chunkZ
|
||||||
|
* @return The schematic file visualized at a chunk position
|
||||||
|
*/
|
||||||
|
private File getFile(int chunkX, int chunkZ) {
|
||||||
|
long pair = MathMan.pairInt(chunkX, chunkZ);
|
||||||
|
Map.Entry<File, Long> entry = files.get(pair);
|
||||||
|
return entry != null ? entry.getKey() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map.Entry<File, Long> getEntry(File file, long position) {
|
||||||
|
return new AbstractMap.SimpleEntry(file, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace the blocks with glass, to indicate it's been selected
|
||||||
|
* @param chunk
|
||||||
|
*/
|
||||||
|
private void select(MCAChunk chunk) {
|
||||||
|
for (int layer = 0; layer < 16; layer++) {
|
||||||
|
byte[] ids = chunk.ids[layer];
|
||||||
|
if (ids != null) {
|
||||||
|
for (int i = 0; i < ids.length; i++) {
|
||||||
|
if (ids[i] != 0) ids[i] = BlockID.STAINED_GLASS;
|
||||||
|
Arrays.fill(chunk.data[layer], (byte) 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache a chunk
|
||||||
|
* @param file
|
||||||
|
* @param chunk
|
||||||
|
*/
|
||||||
|
private void cacheChunk(File file, MCAChunk chunk, boolean selected) {
|
||||||
|
long pair = MathMan.pairInt(chunk.getX(), chunk.getZ());
|
||||||
|
// Light chunk
|
||||||
|
for (int layer = 0; layer < 16; layer++) {
|
||||||
|
if (chunk.skyLight[layer] != null) {
|
||||||
|
Arrays.fill(chunk.skyLight[layer], (byte) 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selected) {
|
||||||
|
select(chunk);
|
||||||
|
}
|
||||||
|
synchronized (this) {
|
||||||
|
chunks.put(pair, chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next free position for a schematic of the provided dimensions
|
||||||
|
* @param schemDimensions
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private BlockVector2D registerAndGetChunkOffset(BlockVector schemDimensions, File file) {
|
||||||
|
int chunkX = schemDimensions.getBlockX() >> 4;
|
||||||
|
int chunkZ = schemDimensions.getBlockZ() >> 4;
|
||||||
|
MutableBlockVector2D pos2 = new MutableBlockVector2D();
|
||||||
|
MutableBlockVector2D curPos = lastPos;
|
||||||
|
// Find next free position
|
||||||
|
while (!isAreaFree(curPos, pos2.setComponents(curPos.getBlockX() + chunkX, curPos.getBlockZ() + chunkZ))) {
|
||||||
|
if (curPos == lastPos && !files.containsKey(MathMan.pairInt(curPos.getBlockX(), curPos.getBlockZ()))) {
|
||||||
|
curPos = new MutableBlockVector2D();
|
||||||
|
curPos.setComponents(lastPos.getBlockX(), lastPos.getBlockZ());
|
||||||
|
}
|
||||||
|
curPos.nextPosition();
|
||||||
|
}
|
||||||
|
// Register the chunks
|
||||||
|
Map.Entry<File, Long> originValue = getEntry(file, MathMan.pairInt(curPos.getBlockX(), curPos.getBlockZ()));
|
||||||
|
for (int x = 0; x <= chunkX; x++) {
|
||||||
|
for (int z = 0; z <= chunkZ; z++) {
|
||||||
|
long pos = MathMan.pairInt(curPos.getBlockX() + x, curPos.getBlockZ() + z);
|
||||||
|
files.put(pos, originValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return curPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAreaFree(BlockVector2D chunkPos1, BlockVector2D chunkPos2 /* inclusive */) {
|
||||||
|
for (int x = chunkPos1.getBlockX(); x <= chunkPos2.getBlockX(); x++) {
|
||||||
|
for (int z = chunkPos1.getBlockZ(); z <= chunkPos2.getBlockZ(); z++) {
|
||||||
|
if (files.containsKey(MathMan.pairInt(x, z)) || (x == 0 && z == 0)) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSelected(File file) {
|
||||||
|
ClipboardHolder clipboard = player.getSession().getExistingClipboard();
|
||||||
|
if (clipboard != null) {
|
||||||
|
if (clipboard instanceof URIClipboardHolder) {
|
||||||
|
return ((URIClipboardHolder) clipboard).contains(file.toURI());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(File file) throws IOException {
|
||||||
|
File cached = new File(file.getParentFile(), "." + file.getName() + ".cached");
|
||||||
|
if (cached.exists() && file.lastModified() <= cached.lastModified()) {
|
||||||
|
try (FileInputStream fis = new FileInputStream(cached)) {
|
||||||
|
BlockVector dimensions = new BlockVector(IOUtil.readVarInt(fis), IOUtil.readVarInt(fis), IOUtil.readVarInt(fis));
|
||||||
|
BlockVector2D offset = registerAndGetChunkOffset(dimensions, cached);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
player.sendMessage(BBC.getPrefix() + "Converting: " + file);
|
||||||
|
cached.createNewFile();
|
||||||
|
try (FileInputStream in = new FileInputStream(file)) {
|
||||||
|
ClipboardFormat format = ClipboardFormat.findByFile(file);
|
||||||
|
ClipboardReader reader = format.getReader(in);
|
||||||
|
Clipboard clipboard = reader.read(worldData);
|
||||||
|
clipboard.setOrigin(clipboard.getMinimumPoint());
|
||||||
|
try {
|
||||||
|
MCAQueue queue = new MCAQueue(null, null, false);
|
||||||
|
BlockVector dimensions = clipboard.getDimensions().toBlockVector();
|
||||||
|
BlockVector2D offset = registerAndGetChunkOffset(dimensions, cached);
|
||||||
|
new Schematic(clipboard).paste(queue, Vector.ZERO, true);
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(cached)) {
|
||||||
|
IOUtil.writeVarInt(fos, dimensions.getBlockX());
|
||||||
|
IOUtil.writeVarInt(fos, dimensions.getBlockY());
|
||||||
|
IOUtil.writeVarInt(fos, dimensions.getBlockZ());
|
||||||
|
|
||||||
|
try (FaweOutputStream cos = MainUtil.getCompressedOS(fos, 2)) {
|
||||||
|
NBTOutputStream nos = new NBTOutputStream((DataOutput) cos);
|
||||||
|
Collection<FaweChunk> writeChunks = queue.getFaweChunks();
|
||||||
|
cos.writeInt(writeChunks.size());
|
||||||
|
|
||||||
|
boolean selected = isSelected(file);
|
||||||
|
|
||||||
|
for (FaweChunk chunk : writeChunks) {
|
||||||
|
MCAChunk mcaChunk = ((MCAChunk) chunk);
|
||||||
|
mcaChunk.write(nos);
|
||||||
|
mcaChunk.setLoc(this, mcaChunk.getX() + offset.getBlockX(), mcaChunk.getZ() + offset.getBlockZ());
|
||||||
|
if (Math.abs(mcaChunk.getX()) <= 15 && Math.abs(mcaChunk.getZ()) <= 15) {
|
||||||
|
cacheChunk(cached, mcaChunk, selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (System.getProperty("os.name").contains("Windows")) {
|
||||||
|
Path path = cached.toPath();
|
||||||
|
Object hidden = java.nio.file.Files.getAttribute(path, "dos:hidden", LinkOption.NOFOLLOW_LINKS);
|
||||||
|
if (hidden != null) {
|
||||||
|
//link file to DosFileAttributes
|
||||||
|
java.nio.file.Files.setAttribute(path, "dos:hidden", Boolean.TRUE, LinkOption.NOFOLLOW_LINKS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (clipboard instanceof Closeable) {
|
||||||
|
((Closeable) clipboard).close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
cached.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized MCAChunk getCachedChunk(int chunkX, int chunkZ) {
|
||||||
|
return chunks.get(MathMan.pairInt(chunkX, chunkZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
private MCAChunk getChunk(int chunkX, int chunkZ) {
|
||||||
|
long pair = MathMan.pairInt(chunkX, chunkZ);
|
||||||
|
// Check cached
|
||||||
|
MCAChunk chunk = getCachedChunk(chunkX, chunkZ);
|
||||||
|
if (chunk != null) return chunk;
|
||||||
|
|
||||||
|
// We need to cache it
|
||||||
|
Map.Entry<File, Long> entry = files.get(pair);
|
||||||
|
if (entry != null) {
|
||||||
|
File cached = entry.getKey();
|
||||||
|
|
||||||
|
// Guard caching by other threads
|
||||||
|
synchronized (cached) {
|
||||||
|
chunk = getCachedChunk(chunkX, chunkZ);
|
||||||
|
|
||||||
|
// Read chunks from disk
|
||||||
|
if (chunk == null) {
|
||||||
|
clean();
|
||||||
|
String filename = cached.getName();
|
||||||
|
File file = new File(cached.getParentFile(), filename.substring(1, filename.length() - 7));
|
||||||
|
boolean selected = isSelected(file);
|
||||||
|
|
||||||
|
long origin = entry.getValue();
|
||||||
|
int OCX = MathMan.unpairIntX(origin);
|
||||||
|
int OCZ = MathMan.unpairIntY(origin);
|
||||||
|
try {
|
||||||
|
try (FileInputStream fis = new FileInputStream(cached)) {
|
||||||
|
BlockVector dimensions = new BlockVector(IOUtil.readVarInt(fis), IOUtil.readVarInt(fis), IOUtil.readVarInt(fis));
|
||||||
|
try (FaweInputStream in = MainUtil.getCompressedIS(fis)) {
|
||||||
|
try (NBTInputStream nis = new NBTInputStream(in)) {
|
||||||
|
|
||||||
|
int numChunks = in.readInt();
|
||||||
|
for (int i = 0; i < numChunks; i++) {
|
||||||
|
MCAChunk mcaChunk = new MCAChunk(nis, null, 0, 0, true);
|
||||||
|
mcaChunk.setLoc(this, mcaChunk.getX() + OCX, mcaChunk.getZ() + OCZ);
|
||||||
|
cacheChunk(cached, mcaChunk, selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
// Return the cached chunk, or an empty one
|
||||||
|
chunk = getCachedChunk(chunkX, chunkZ);
|
||||||
|
if (chunk == null) {
|
||||||
|
// TODO use shared chunk
|
||||||
|
// TODO synchronize on sending chunk packet
|
||||||
|
cacheChunk(cached, chunk = new MCAChunk(this, chunkX, chunkZ), selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
chunk = new MCAChunk(this, chunkX, chunkZ);
|
||||||
|
}
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a lazily evaluated chunk
|
||||||
|
* @param chunkX
|
||||||
|
* @param chunkZ
|
||||||
|
* @return lazy chunk
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public FaweChunk getSnapshot(int chunkX, int chunkZ) {
|
||||||
|
return new LazyFaweChunk<MCAChunk>(this, chunkX, chunkZ) {
|
||||||
|
@Override
|
||||||
|
public MCAChunk getChunk() {
|
||||||
|
MCAChunk tmp = SchemVis.this.getChunk(chunkX, chunkZ);
|
||||||
|
tmp.setLoc(SchemVis.this, getX(), getZ());
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addToQueue() {
|
||||||
|
MCAChunk cached = getCachedChunk();
|
||||||
|
if (cached != null) setChunk(cached);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WorldData getWorldData() {
|
||||||
|
return worldData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FawePlayer getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind() {
|
||||||
|
player.setVirtualWorld(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send all chunks to the player
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void update() {
|
||||||
|
FaweQueue packetQueue = SetQueue.IMP.getNewQueue(player.getWorld(), true, false);
|
||||||
|
|
||||||
|
if (!packetQueue.supports(Capability.CHUNK_PACKETS)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int OX = chunkOffset.getBlockX();
|
||||||
|
int OZ = chunkOffset.getBlockZ();
|
||||||
|
|
||||||
|
FaweLocation position = player.getLocation();
|
||||||
|
int pcx = (position.x >> 4) - OX;
|
||||||
|
int pcz = (position.z >> 4) - OZ;
|
||||||
|
|
||||||
|
int scx = pcx - 15;
|
||||||
|
int scz = pcz - 15;
|
||||||
|
int ecx = pcx + 15;
|
||||||
|
int ecz = pcz + 15;
|
||||||
|
|
||||||
|
for (int cz = scz; cz <= ecz; cz++) {
|
||||||
|
for (int cx = scx; cx <= ecx; cx++) {
|
||||||
|
final int finalCX = cx;
|
||||||
|
final int finalCZ = cz;
|
||||||
|
send(packetQueue, finalCX, finalCZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendChunk(FaweChunk chunk) { /* do nothing - never used */ }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendChunk(int x, int z, int bitMask) { /* do nothing - never used*/ }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBiomeId(int x, int z) throws FaweException.FaweChunkLoadException {
|
||||||
|
// TODO later (currently not used)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCombinedId4Data(int x, int y, int z) throws FaweException.FaweChunkLoadException {
|
||||||
|
MCAChunk chunk = getChunk(x >> 4, z >> 4);
|
||||||
|
if (y < 0 || y > 255) return 0;
|
||||||
|
return chunk.getBlockCombinedId(x & 15, y, z & 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes this virtual world and sends the normal world chunks to the player
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public synchronized void close(boolean update) throws IOException {
|
||||||
|
clear();
|
||||||
|
chunks.clear();
|
||||||
|
files.clear();
|
||||||
|
player.getPlayer().setPosition(origin.toVector(), origin.getPitch(), origin.getYaw());
|
||||||
|
if (update) {
|
||||||
|
FaweQueue packetQueue = SetQueue.IMP.getNewQueue(player.getWorld(), true, false);
|
||||||
|
|
||||||
|
int OX = chunkOffset.getBlockX();
|
||||||
|
int OZ = chunkOffset.getBlockZ();
|
||||||
|
|
||||||
|
FaweLocation position = player.getLocation();
|
||||||
|
int pcx = (position.x >> 4) - OX;
|
||||||
|
int pcz = (position.z >> 4) - OZ;
|
||||||
|
|
||||||
|
int scx = pcx - 15;
|
||||||
|
int scz = pcz - 15;
|
||||||
|
int ecx = pcx + 15;
|
||||||
|
int ecz = pcz + 15;
|
||||||
|
|
||||||
|
for (int cz = scz; cz <= ecz; cz++) {
|
||||||
|
for (int cx = scx; cx <= ecx; cx++) {
|
||||||
|
packetQueue.sendChunk(cx + OX, cz + OZ, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
core/src/main/java/com/boydti/fawe/util/IOUtil.java
Normal file
56
core/src/main/java/com/boydti/fawe/util/IOUtil.java
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package com.boydti.fawe.util;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
public final class IOUtil {
|
||||||
|
public InputStream toInputStream(URI uri) throws IOException {
|
||||||
|
String scheme = uri.getScheme();
|
||||||
|
switch (scheme.toLowerCase()) {
|
||||||
|
case "file":
|
||||||
|
return new FileInputStream(uri.getPath());
|
||||||
|
case "http":
|
||||||
|
case "https":
|
||||||
|
return uri.toURL().openStream();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int readInt(InputStream in) throws IOException {
|
||||||
|
int ch1 = in.read();
|
||||||
|
int ch2 = in.read();
|
||||||
|
int ch3 = in.read();
|
||||||
|
int ch4 = in.read();
|
||||||
|
if ((ch1 | ch2 | ch3 | ch4) < 0)
|
||||||
|
throw new EOFException();
|
||||||
|
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final void writeInt(OutputStream out, int v) throws IOException {
|
||||||
|
out.write((v >>> 24) & 0xFF);
|
||||||
|
out.write((v >>> 16) & 0xFF);
|
||||||
|
out.write((v >>> 8) & 0xFF);
|
||||||
|
out.write((v >>> 0) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeVarInt(OutputStream out, int i) throws IOException {
|
||||||
|
while((i & -128) != 0) {
|
||||||
|
out.write(i & 127 | 128);
|
||||||
|
i >>>= 7;
|
||||||
|
}
|
||||||
|
out.write(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int readVarInt(InputStream in) throws IOException {
|
||||||
|
int i = 0;
|
||||||
|
int offset = 0;
|
||||||
|
int b;
|
||||||
|
while ((b = in.read()) > 127) {
|
||||||
|
i |= (b - 128) << offset;
|
||||||
|
offset += 7;
|
||||||
|
}
|
||||||
|
i |= b << offset;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit;
|
package com.sk89q.worldedit;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extension of {@code Vector} that that compares with other instances
|
* Extension of {@code Vector} that that compares with other instances
|
||||||
* using integer components.
|
* using integer components.
|
||||||
@ -93,6 +95,19 @@ public class BlockVector extends Vector {
|
|||||||
return ((int) getX() ^ ((int) getZ() << 16)) ^ ((int) getY() << 30);
|
return ((int) getX() ^ ((int) getZ() << 16)) ^ ((int) getY() << 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
|
||||||
|
if (!(this instanceof MutableBlockVector)) {
|
||||||
|
stream.writeInt(getBlockX());
|
||||||
|
stream.writeInt(getBlockY());
|
||||||
|
stream.writeInt(getBlockZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
|
||||||
|
if (this instanceof MutableBlockVector) return;
|
||||||
|
this.setComponents(stream.readInt(), stream.readInt(), stream.readInt());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockVector toBlockVector() {
|
public BlockVector toBlockVector() {
|
||||||
return this;
|
return this;
|
||||||
|
@ -25,12 +25,12 @@ import com.boydti.fawe.FaweCache;
|
|||||||
import com.boydti.fawe.config.BBC;
|
import com.boydti.fawe.config.BBC;
|
||||||
import com.boydti.fawe.config.Settings;
|
import com.boydti.fawe.config.Settings;
|
||||||
import com.boydti.fawe.example.MappedFaweQueue;
|
import com.boydti.fawe.example.MappedFaweQueue;
|
||||||
import com.boydti.fawe.jnbt.anvil.HeightMapMCAGenerator;
|
|
||||||
import com.boydti.fawe.jnbt.anvil.MCAQueue;
|
import com.boydti.fawe.jnbt.anvil.MCAQueue;
|
||||||
import com.boydti.fawe.jnbt.anvil.MCAWorld;
|
import com.boydti.fawe.jnbt.anvil.MCAWorld;
|
||||||
import com.boydti.fawe.logging.LoggingChangeSet;
|
import com.boydti.fawe.logging.LoggingChangeSet;
|
||||||
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
||||||
import com.boydti.fawe.object.*;
|
import com.boydti.fawe.object.*;
|
||||||
|
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
||||||
import com.boydti.fawe.object.changeset.*;
|
import com.boydti.fawe.object.changeset.*;
|
||||||
import com.boydti.fawe.object.clipboard.WorldCopyClipboard;
|
import com.boydti.fawe.object.clipboard.WorldCopyClipboard;
|
||||||
import com.boydti.fawe.object.collection.LocalBlockVectorSet;
|
import com.boydti.fawe.object.collection.LocalBlockVectorSet;
|
||||||
@ -297,7 +297,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (allowedRegions == null) {
|
if (allowedRegions == null) {
|
||||||
if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(queue instanceof HeightMapMCAGenerator)) {
|
if (player != null && !player.hasPermission("fawe.bypass") && !player.hasPermission("fawe.bypass.regions") && !(queue instanceof VirtualWorld)) {
|
||||||
allowedRegions = player.getCurrentRegions();
|
allowedRegions = player.getCurrentRegions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,11 @@ import com.boydti.fawe.object.FaweInputStream;
|
|||||||
import com.boydti.fawe.object.FaweLimit;
|
import com.boydti.fawe.object.FaweLimit;
|
||||||
import com.boydti.fawe.object.FaweOutputStream;
|
import com.boydti.fawe.object.FaweOutputStream;
|
||||||
import com.boydti.fawe.object.FawePlayer;
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
||||||
import com.boydti.fawe.object.changeset.AnvilHistory;
|
import com.boydti.fawe.object.changeset.AnvilHistory;
|
||||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||||
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
import com.boydti.fawe.object.changeset.FaweChangeSet;
|
||||||
|
import com.boydti.fawe.object.clipboard.MultiClipboardHolder;
|
||||||
import com.boydti.fawe.object.collection.SparseBitSet;
|
import com.boydti.fawe.object.collection.SparseBitSet;
|
||||||
import com.boydti.fawe.object.extent.ResettableExtent;
|
import com.boydti.fawe.object.extent.ResettableExtent;
|
||||||
import com.boydti.fawe.util.EditSessionBuilder;
|
import com.boydti.fawe.util.EditSessionBuilder;
|
||||||
@ -41,12 +43,7 @@ import com.sk89q.jchronic.Options;
|
|||||||
import com.sk89q.jchronic.utils.Span;
|
import com.sk89q.jchronic.utils.Span;
|
||||||
import com.sk89q.jchronic.utils.Time;
|
import com.sk89q.jchronic.utils.Time;
|
||||||
import com.sk89q.worldedit.blocks.BaseBlock;
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import com.sk89q.worldedit.command.tool.BlockTool;
|
import com.sk89q.worldedit.command.tool.*;
|
||||||
import com.sk89q.worldedit.command.tool.BrushHolder;
|
|
||||||
import com.sk89q.worldedit.command.tool.BrushTool;
|
|
||||||
import com.sk89q.worldedit.command.tool.InvalidToolBindException;
|
|
||||||
import com.sk89q.worldedit.command.tool.SinglePickaxe;
|
|
||||||
import com.sk89q.worldedit.command.tool.Tool;
|
|
||||||
import com.sk89q.worldedit.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
import com.sk89q.worldedit.extension.platform.Actor;
|
import com.sk89q.worldedit.extension.platform.Actor;
|
||||||
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
import com.sk89q.worldedit.extent.inventory.BlockBag;
|
||||||
@ -65,21 +62,10 @@ import com.sk89q.worldedit.session.ClipboardHolder;
|
|||||||
import com.sk89q.worldedit.session.request.Request;
|
import com.sk89q.worldedit.session.request.Request;
|
||||||
import com.sk89q.worldedit.world.World;
|
import com.sk89q.worldedit.world.World;
|
||||||
import com.sk89q.worldedit.world.snapshot.Snapshot;
|
import com.sk89q.worldedit.world.snapshot.Snapshot;
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileFilter;
|
import java.util.*;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ListIterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TimeZone;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
|
||||||
@ -138,6 +124,8 @@ public class LocalSession {
|
|||||||
private transient UUID uuid;
|
private transient UUID uuid;
|
||||||
private transient volatile long historySize = 0;
|
private transient volatile long historySize = 0;
|
||||||
|
|
||||||
|
private transient VirtualWorld virtual;
|
||||||
|
|
||||||
// Saved properties
|
// Saved properties
|
||||||
private String lastScript;
|
private String lastScript;
|
||||||
private RegionSelectorType defaultSelector;
|
private RegionSelectorType defaultSelector;
|
||||||
@ -733,6 +721,29 @@ public class LocalSession {
|
|||||||
return selector.getRegion();
|
return selector.getRegion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized @Nullable VirtualWorld getVirtualWorld() {
|
||||||
|
return virtual;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVirtualWorld(@Nullable VirtualWorld world) {
|
||||||
|
VirtualWorld tmp;
|
||||||
|
synchronized (this) {
|
||||||
|
tmp = this.virtual;
|
||||||
|
this.virtual = world;
|
||||||
|
}
|
||||||
|
if (tmp != null) {
|
||||||
|
try {
|
||||||
|
tmp.close(world == null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (world != null) {
|
||||||
|
Fawe.imp().registerPacketListener();
|
||||||
|
world.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the selection world.
|
* Get the selection world.
|
||||||
*
|
*
|
||||||
@ -785,6 +796,24 @@ public class LocalSession {
|
|||||||
return clipboard;
|
return clipboard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addClipboard(@Nonnull MultiClipboardHolder toAppend) {
|
||||||
|
checkNotNull(toAppend);
|
||||||
|
ClipboardHolder existing = getExistingClipboard();
|
||||||
|
MultiClipboardHolder multi;
|
||||||
|
if (existing instanceof MultiClipboardHolder) {
|
||||||
|
multi = (MultiClipboardHolder) existing;
|
||||||
|
for (ClipboardHolder holder : toAppend.getHolders()) {
|
||||||
|
multi.add(holder);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
multi = toAppend;
|
||||||
|
if (existing != null) {
|
||||||
|
multi.add(existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setClipboard(multi);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the clipboard.
|
* Sets the clipboard.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -78,4 +78,33 @@ public final class MutableBlockVector2D extends BlockVector2D implements Seriali
|
|||||||
this.x = stream.readInt();
|
this.x = stream.readInt();
|
||||||
this.z = stream.readInt();
|
this.z = stream.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MutableBlockVector2D nextPosition() {
|
||||||
|
int absX = Math.abs(x);
|
||||||
|
int absY = Math.abs(z);
|
||||||
|
if (absX > absY) {
|
||||||
|
if (x > 0) {
|
||||||
|
return setComponents(x, z + 1);
|
||||||
|
} else {
|
||||||
|
return setComponents(x, z - 1);
|
||||||
|
}
|
||||||
|
} else if (absY > absX) {
|
||||||
|
if (z > 0) {
|
||||||
|
return setComponents(x - 1, z);
|
||||||
|
} else {
|
||||||
|
return setComponents(x + 1, z);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (x == z && x > 0) {
|
||||||
|
return setComponents(x, z + 1);
|
||||||
|
}
|
||||||
|
if (x == absX) {
|
||||||
|
return setComponents(x, z + 1);
|
||||||
|
}
|
||||||
|
if (z == absY) {
|
||||||
|
return setComponents(x, z - 1);
|
||||||
|
}
|
||||||
|
return setComponents(x + 1, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -889,7 +889,7 @@ public class Vector implements Comparable<Vector>, Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
|
private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
|
||||||
if (!(this instanceof Vector)) {
|
if (!(this instanceof MutableBlockVector)) {
|
||||||
stream.writeDouble(x);
|
stream.writeDouble(x);
|
||||||
stream.writeDouble(y);
|
stream.writeDouble(y);
|
||||||
stream.writeDouble(z);
|
stream.writeDouble(z);
|
||||||
|
@ -117,7 +117,7 @@ public class GenerationCommands extends MethodCommands {
|
|||||||
@Command(
|
@Command(
|
||||||
aliases = {"/image", "/img"},
|
aliases = {"/image", "/img"},
|
||||||
desc = "Generate an image",
|
desc = "Generate an image",
|
||||||
usage = "<imgur> [randomize=true] [complexity=100]",
|
usage = "<imgur> [randomize=true] [complexity=100] [dimensions]",
|
||||||
min = 1,
|
min = 1,
|
||||||
max = 3
|
max = 3
|
||||||
)
|
)
|
||||||
|
@ -29,6 +29,7 @@ import com.boydti.fawe.object.clipboard.MultiClipboardHolder;
|
|||||||
import com.boydti.fawe.object.clipboard.URIClipboardHolder;
|
import com.boydti.fawe.object.clipboard.URIClipboardHolder;
|
||||||
import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper;
|
import com.boydti.fawe.object.clipboard.remap.ClipboardRemapper;
|
||||||
import com.boydti.fawe.object.schematic.StructureFormat;
|
import com.boydti.fawe.object.schematic.StructureFormat;
|
||||||
|
import com.boydti.fawe.object.schematic.visualizer.SchemVis;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.chat.Message;
|
import com.boydti.fawe.util.chat.Message;
|
||||||
import com.sk89q.minecraft.util.commands.Command;
|
import com.sk89q.minecraft.util.commands.Command;
|
||||||
@ -44,9 +45,7 @@ import com.sk89q.worldedit.extension.platform.Actor;
|
|||||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
|
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
|
||||||
import com.sk89q.worldedit.extent.clipboard.io.SchematicReader;
|
|
||||||
import com.sk89q.worldedit.function.operation.Operations;
|
import com.sk89q.worldedit.function.operation.Operations;
|
||||||
import com.sk89q.worldedit.math.transform.Transform;
|
import com.sk89q.worldedit.math.transform.Transform;
|
||||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||||
@ -54,18 +53,15 @@ import com.sk89q.worldedit.util.command.binding.Switch;
|
|||||||
import com.sk89q.worldedit.util.command.parametric.Optional;
|
import com.sk89q.worldedit.util.command.parametric.Optional;
|
||||||
import com.sk89q.worldedit.util.io.file.FilenameException;
|
import com.sk89q.worldedit.util.io.file.FilenameException;
|
||||||
import com.sk89q.worldedit.world.registry.WorldData;
|
import com.sk89q.worldedit.world.registry.WorldData;
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.nio.channels.ReadableByteChannel;
|
import java.nio.channels.ReadableByteChannel;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.UUID;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.LongAdder;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@ -110,20 +106,7 @@ public class SchematicCommands extends MethodCommands {
|
|||||||
|
|
||||||
MultiClipboardHolder all = format.loadAllFromInput(player, wd, filename, true);
|
MultiClipboardHolder all = format.loadAllFromInput(player, wd, filename, true);
|
||||||
if (all != null) {
|
if (all != null) {
|
||||||
ClipboardHolder existing = session.getExistingClipboard();
|
session.addClipboard(all);
|
||||||
MultiClipboardHolder multi;
|
|
||||||
if (existing instanceof MultiClipboardHolder) {
|
|
||||||
multi = (MultiClipboardHolder) existing;
|
|
||||||
for (ClipboardHolder holder : all.getHolders()) {
|
|
||||||
multi.add(holder);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
multi = all;
|
|
||||||
if (existing != null) {
|
|
||||||
multi.add(existing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
session.setClipboard(multi);
|
|
||||||
BBC.SCHEMATIC_LOADED.send(player, filename);
|
BBC.SCHEMATIC_LOADED.send(player, filename);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -274,18 +257,7 @@ public class SchematicCommands extends MethodCommands {
|
|||||||
|
|
||||||
uri = f.toURI();
|
uri = f.toURI();
|
||||||
}
|
}
|
||||||
final ClipboardReader reader = format.getReader(in);
|
format.hold(player, uri, in);
|
||||||
final WorldData worldData = player.getWorld().getWorldData();
|
|
||||||
final Clipboard clipboard;
|
|
||||||
session.setClipboard(null);
|
|
||||||
if (reader instanceof SchematicReader) {
|
|
||||||
clipboard = ((SchematicReader) reader).read(player.getWorld().getWorldData(), player.getUniqueId());
|
|
||||||
} else if (reader instanceof StructureFormat) {
|
|
||||||
clipboard = ((StructureFormat) reader).read(player.getWorld().getWorldData(), player.getUniqueId());
|
|
||||||
} else {
|
|
||||||
clipboard = reader.read(player.getWorld().getWorldData());
|
|
||||||
}
|
|
||||||
session.setClipboard(new URIClipboardHolder(uri, clipboard, worldData));
|
|
||||||
BBC.SCHEMATIC_LOADED.send(player, filename);
|
BBC.SCHEMATIC_LOADED.send(player, filename);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
player.printError("Unknown filename: " + filename);
|
player.printError("Unknown filename: " + filename);
|
||||||
@ -380,24 +352,107 @@ public class SchematicCommands extends MethodCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(aliases = {"delete", "d"}, usage = "<filename>", desc = "Delete a saved schematic", help = "Delete a schematic from the schematic list", min = 1, max = 1)
|
@Command(aliases = {"move", "m"}, usage = "<directory>", desc = "Move your loaded schematic", help = "Move your currently loaded schematics", min = 1, max = 1)
|
||||||
@CommandPermissions("worldedit.schematic.delete")
|
@CommandPermissions({"worldedit.schematic.move", "worldedit.schematic.move.other"})
|
||||||
public void delete(final Player player, final LocalSession session, final CommandContext args) throws WorldEditException {
|
public void move(final Player player, final LocalSession session, final CommandContext args) throws WorldEditException {
|
||||||
final LocalConfiguration config = this.worldEdit.getConfiguration();
|
final LocalConfiguration config = this.worldEdit.getConfiguration();
|
||||||
final String filename = args.getString(0);
|
|
||||||
|
|
||||||
final File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
|
final File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||||
final File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working;
|
final File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working;
|
||||||
final File f = this.worldEdit.getSafeSaveFile(player, dir, filename, "schematic", "schematic");
|
File destDir = new File(dir, args.getString(0));
|
||||||
if (!f.exists()) {
|
if (!MainUtil.isInSubDirectory(working, destDir)) {
|
||||||
player.printError("Schematic " + filename + " does not exist!");
|
player.printError("Directory " + destDir + " does not exist!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!f.delete()) {
|
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, destDir) && !player.hasPermission("worldedit.schematic.move.other")) {
|
||||||
player.printError("Deletion of " + filename + " failed! Maybe it is read-only.");
|
BBC.NO_PERM.send(player, "worldedit.schematic.move.other");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BBC.FILE_DELETED.send(player, filename);
|
ClipboardHolder clipboard = session.getClipboard();
|
||||||
|
List<File> sources = getFiles(clipboard);
|
||||||
|
if (sources.isEmpty()) {
|
||||||
|
BBC.SCHEMATIC_NONE.send(player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!destDir.exists() && !destDir.mkdirs()) {
|
||||||
|
player.printError("Creation of " + destDir + " failed! (check file permissions)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (File source : sources) {
|
||||||
|
File destFile = new File(destDir, source.getName());
|
||||||
|
if (destFile.exists()) {
|
||||||
|
BBC.SCHEMATIC_MOVE_EXISTS.send(player, destFile);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && (!MainUtil.isInSubDirectory(dir, destFile) || !MainUtil.isInSubDirectory(dir, source)) && !player.hasPermission("worldedit.schematic.delete.other")) {
|
||||||
|
BBC.SCHEMATIC_MOVE_FAILED.send(player, destFile, BBC.NO_PERM.f("worldedit.schematic.move.other"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
File cached = new File(source.getParentFile(), "." + source.getName() + ".cached");
|
||||||
|
Files.move(source.toPath(), destFile.toPath());
|
||||||
|
if (cached.exists()) Files.move(cached.toPath(), destFile.toPath());
|
||||||
|
BBC.SCHEMATIC_MOVE_SUCCESS.send(player, source, destFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(aliases = {"delete", "d"}, usage = "<filename|*>", desc = "Delete a saved schematic", help = "Delete a schematic from the schematic list", min = 1, max = 1)
|
||||||
|
@CommandPermissions({"worldedit.schematic.delete", "worldedit.schematic.other"})
|
||||||
|
public void delete(final Player player, final LocalSession session, final CommandContext args) throws WorldEditException {
|
||||||
|
final LocalConfiguration config = this.worldEdit.getConfiguration();
|
||||||
|
final File working = this.worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||||
|
final File dir = Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? new File(working, player.getUniqueId().toString()) : working;
|
||||||
|
List<File> files = new ArrayList<>();
|
||||||
|
|
||||||
|
final String filename = args.getString(0);
|
||||||
|
|
||||||
|
if (filename.equalsIgnoreCase("*")) {
|
||||||
|
files.addAll(getFiles(session.getClipboard()));
|
||||||
|
} else {
|
||||||
|
files.add(new File(dir, filename));
|
||||||
|
}
|
||||||
|
if (files.isEmpty()) {
|
||||||
|
BBC.SCHEMATIC_NONE.send(player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (File f : files) {
|
||||||
|
if (!MainUtil.isInSubDirectory(working, f) || !f.exists()) {
|
||||||
|
player.printError("Schematic " + filename + " does not exist! (" + f.exists() + "|" + f + "|" + (!MainUtil.isInSubDirectory(working, f)) + ")");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS && !MainUtil.isInSubDirectory(dir, f) && !player.hasPermission("worldedit.schematic.delete.other")) {
|
||||||
|
BBC.NO_PERM.send(player, "worldedit.schematic.delete.other");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!delete(f)) {
|
||||||
|
player.printError("Deletion of " + filename + " failed! Maybe it is read-only.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
BBC.FILE_DELETED.send(player, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<File> getFiles(ClipboardHolder clipboard) {
|
||||||
|
List<File> files = new ArrayList<>();
|
||||||
|
Collection<URI> uris = Collections.emptyList();
|
||||||
|
if (clipboard instanceof URIClipboardHolder) {
|
||||||
|
uris = ((URIClipboardHolder) clipboard).getURIs();
|
||||||
|
}
|
||||||
|
for (URI uri : uris) {
|
||||||
|
File file = new File(uri);
|
||||||
|
if (file.exists()) files.add(file);
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean delete(File file) {
|
||||||
|
if (file.delete()) {
|
||||||
|
new File(file.getParentFile(), "." + file.getName() + ".cached").delete();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(aliases = {"formats", "listformats", "f"}, desc = "List available formats", max = 0)
|
@Command(aliases = {"formats", "listformats", "f"}, desc = "List available formats", max = 0)
|
||||||
@ -424,6 +479,58 @@ public class SchematicCommands extends MethodCommands {
|
|||||||
m.send(actor);
|
m.send(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Command(
|
||||||
|
aliases = {"show"},
|
||||||
|
desc = "Show a schematic",
|
||||||
|
usage = "[global|mine|<filter>] [page=1]",
|
||||||
|
min = 0,
|
||||||
|
max = -1,
|
||||||
|
flags = "dnp",
|
||||||
|
help = "List all schematics in the schematics directory\n" +
|
||||||
|
" -p <page> prints the requested page\n" +
|
||||||
|
" -f <format> restricts by format\n"
|
||||||
|
)
|
||||||
|
@CommandPermissions("worldedit.heightmap.list")
|
||||||
|
public void show(Player player, CommandContext args, @Switch('p') @Optional("1") int page) {
|
||||||
|
FawePlayer fp = FawePlayer.wrap(player);
|
||||||
|
if (args.argsLength() == 0 && fp.getSession().getVirtualWorld() != null) {
|
||||||
|
fp.setVirtualWorld(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LocalConfiguration config = worldEdit.getConfiguration();
|
||||||
|
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||||
|
try {
|
||||||
|
SchemVis visExtent = new SchemVis(fp);
|
||||||
|
LongAdder count = new LongAdder();
|
||||||
|
UtilityCommands.getFiles(dir, player, args, 0, Character.MAX_VALUE, null, Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS, file -> {
|
||||||
|
if (file.isFile()) {
|
||||||
|
try {
|
||||||
|
visExtent.add(file);
|
||||||
|
count.add(1);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
visExtent.bind();
|
||||||
|
visExtent.update();
|
||||||
|
|
||||||
|
String cmdPrefix = "/" + (config.noDoubleSlash ? "" : "/");
|
||||||
|
String cmdShow = Commands.getAlias(ClipboardCommands.class, "schematic") + " " + Commands.getAlias(ClipboardCommands.class, "show");
|
||||||
|
BBC.SCHEMATIC_SHOW.send(fp, count.longValue(), args.getJoinedStrings(0), cmdShow);
|
||||||
|
|
||||||
|
if (fp.getSession().getExistingClipboard() != null) {
|
||||||
|
String cmd = cmdPrefix + Commands.getAlias(ClipboardCommands.class, "clipboard") + " " + Commands.getAlias(ClipboardCommands.class, "clear");
|
||||||
|
BBC.SCHEMATIC_PROMPT_CLEAR.send(fp, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Throwable e) {
|
||||||
|
fp.setVirtualWorld(null);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Command(
|
@Command(
|
||||||
aliases = {"list", "ls", "all"},
|
aliases = {"list", "ls", "all"},
|
||||||
desc = "List saved schematics",
|
desc = "List saved schematics",
|
||||||
@ -454,7 +561,7 @@ public class SchematicCommands extends MethodCommands {
|
|||||||
|
|
||||||
URIClipboardHolder multi = as(URIClipboardHolder.class, fp.getSession().getExistingClipboard());
|
URIClipboardHolder multi = as(URIClipboardHolder.class, fp.getSession().getExistingClipboard());
|
||||||
|
|
||||||
UtilityCommands.list(dir, actor, args, page, formatName, Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS, new RunnableVal3<Message, URI, String>() {
|
UtilityCommands.list(dir, actor, args, page, -1, formatName, Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS, new RunnableVal3<Message, URI, String>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Message msg, URI uri, String relFilePath) {
|
public void run(Message msg, URI uri, String relFilePath) {
|
||||||
boolean isDir = false;
|
boolean isDir = false;
|
||||||
|
@ -24,6 +24,7 @@ import com.boydti.fawe.FaweAPI;
|
|||||||
import com.boydti.fawe.command.FaweParser;
|
import com.boydti.fawe.command.FaweParser;
|
||||||
import com.boydti.fawe.config.BBC;
|
import com.boydti.fawe.config.BBC;
|
||||||
import com.boydti.fawe.config.Commands;
|
import com.boydti.fawe.config.Commands;
|
||||||
|
import com.boydti.fawe.object.DelegateConsumer;
|
||||||
import com.boydti.fawe.object.FaweLimit;
|
import com.boydti.fawe.object.FaweLimit;
|
||||||
import com.boydti.fawe.object.FawePlayer;
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
import com.boydti.fawe.object.RunnableVal3;
|
import com.boydti.fawe.object.RunnableVal3;
|
||||||
@ -74,8 +75,8 @@ import java.lang.reflect.Type;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
|
|
||||||
import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT;
|
import static com.sk89q.minecraft.util.commands.Logging.LogMode.PLACEMENT;
|
||||||
@ -619,7 +620,7 @@ public class UtilityCommands extends MethodCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void list(File dir, Actor actor, CommandContext args, @Range(min = 0) int page, String formatName, boolean playerFolder, String onClickCmd) {
|
public static void list(File dir, Actor actor, CommandContext args, @Range(min = 0) int page, String formatName, boolean playerFolder, String onClickCmd) {
|
||||||
list(dir, actor, args, page, formatName, playerFolder, new RunnableVal3<Message, URI, String>() {
|
list(dir, actor, args, page, -1, formatName, playerFolder, new RunnableVal3<Message, URI, String>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(Message m, URI uri, String fileName) {
|
public void run(Message m, URI uri, String fileName) {
|
||||||
m.text(BBC.SCHEMATIC_LIST_ELEM, fileName, "");
|
m.text(BBC.SCHEMATIC_LIST_ELEM, fileName, "");
|
||||||
@ -628,7 +629,75 @@ public class UtilityCommands extends MethodCommands {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void list(File dir, Actor actor, CommandContext args, @Range(min = 0) int page, String formatName, boolean playerFolder, RunnableVal3<Message, URI, String> eachMsg) {
|
public static void list(File dir, Actor actor, CommandContext args, @Range(min = 0) int page, int perPage, String formatName, boolean playerFolder, RunnableVal3<Message, URI, String> eachMsg) {
|
||||||
|
AtomicInteger pageInt = new AtomicInteger(page);
|
||||||
|
List<File> fileList = new ArrayList<>();
|
||||||
|
page = getFiles(dir, actor, args, page, perPage, formatName, playerFolder, file -> fileList.add(file));
|
||||||
|
|
||||||
|
if (fileList.isEmpty()) {
|
||||||
|
BBC.SCHEMATIC_NONE.send(actor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (perPage == -1) perPage = actor instanceof Player ? 12 : 20; // More pages for console
|
||||||
|
int pageCount = (fileList.size() + perPage - 1) / perPage;
|
||||||
|
if (page < 1) {
|
||||||
|
BBC.SCHEMATIC_PAGE.send(actor, ">0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (page > pageCount) {
|
||||||
|
BBC.SCHEMATIC_PAGE.send(actor, "<" + (pageCount + 1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int sortType = args.hasFlag('d') ? -1 : args.hasFlag('n') ? 1 : 0;
|
||||||
|
// cleanup file list
|
||||||
|
Collections.sort(fileList, new Comparator<File>() {
|
||||||
|
@Override
|
||||||
|
public int compare(File f1, File f2) {
|
||||||
|
boolean dir1 = f1.isDirectory();
|
||||||
|
boolean dir2 = f2.isDirectory();
|
||||||
|
if (dir1 != dir2) return dir1 ? -1 : 1;
|
||||||
|
int res;
|
||||||
|
if (sortType == 0) { // use name by default
|
||||||
|
int p = f1.getParent().compareTo(f2.getParent());
|
||||||
|
if (p == 0) { // same parent, compare names
|
||||||
|
res = f1.getName().compareTo(f2.getName());
|
||||||
|
} else { // different parent, sort by that
|
||||||
|
res = p;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res = Long.valueOf(f1.lastModified()).compareTo(f2.lastModified()); // use date if there is a flag
|
||||||
|
if (sortType == 1) res = -res; // flip date for newest first instead of oldest first
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
int offset = (page - 1) * perPage;
|
||||||
|
|
||||||
|
int limit = Math.min(offset + perPage, fileList.size());
|
||||||
|
|
||||||
|
String fullArgs = (String) args.getLocals().get("arguments");
|
||||||
|
String baseCmd = null;
|
||||||
|
if (fullArgs != null) {
|
||||||
|
baseCmd = fullArgs.endsWith(" " + page) ? fullArgs.substring(0, fullArgs.length() - (" " + page).length()) : fullArgs;
|
||||||
|
}
|
||||||
|
Message m = new Message(BBC.SCHEMATIC_LIST, page, pageCount);
|
||||||
|
|
||||||
|
UUID uuid = playerFolder ? actor.getUniqueId() : null;
|
||||||
|
for (int i = offset; i < limit; i++) {
|
||||||
|
m.newline();
|
||||||
|
File file = fileList.get(i);
|
||||||
|
eachMsg.run(m, file.toURI(), getPath(dir, file, uuid));
|
||||||
|
}
|
||||||
|
if (baseCmd != null) {
|
||||||
|
m.newline().paginate(baseCmd, page, pageCount);
|
||||||
|
}
|
||||||
|
m.send(actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int getFiles(File dir, Actor actor, CommandContext args, @Range(min = 0) int page, int perPage, String formatName, boolean playerFolder, Consumer<File> forEachFile) {
|
||||||
int len = args.argsLength();
|
int len = args.argsLength();
|
||||||
List<String> filters = new ArrayList<>();
|
List<String> filters = new ArrayList<>();
|
||||||
|
|
||||||
@ -696,90 +765,49 @@ public class UtilityCommands extends MethodCommands {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
List<File> fileList = new ArrayList<>();
|
if (formatName != null) {
|
||||||
|
final ClipboardFormat cf = ClipboardFormat.findByAlias(formatName);
|
||||||
|
forEachFile = new DelegateConsumer<File>(forEachFile) {
|
||||||
|
@Override
|
||||||
|
public void accept(File file) {
|
||||||
|
if (cf.isFormat(file)) super.accept(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
forEachFile = new DelegateConsumer<File>(forEachFile) {
|
||||||
|
@Override
|
||||||
|
public void accept(File file) {
|
||||||
|
if (!file.toString().endsWith(".cached")) super.accept(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (playerFolder) {
|
if (playerFolder) {
|
||||||
if (listMine) {
|
if (listMine) {
|
||||||
File playerDir = new File(dir, actor.getUniqueId() + dirFilter);
|
File playerDir = new File(dir, actor.getUniqueId() + dirFilter);
|
||||||
if (playerDir.exists()) fileList.addAll(allFiles(playerDir.listFiles(), false));
|
if (playerDir.exists()) allFiles(playerDir.listFiles(), false, forEachFile);
|
||||||
}
|
}
|
||||||
if (listGlobal) {
|
if (listGlobal) {
|
||||||
File rel = new File(dir, dirFilter);
|
File rel = new File(dir, dirFilter);
|
||||||
if (rel.exists()) fileList.addAll(allFiles(rel.listFiles(ignoreUUIDs), false));
|
forEachFile = new DelegateConsumer<File>(forEachFile) {
|
||||||
|
@Override
|
||||||
|
public void accept(File f) {
|
||||||
|
try {
|
||||||
|
if (f.isDirectory()) {
|
||||||
|
UUID uuid = UUID.fromString(f.getName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException exception) {}
|
||||||
|
super.accept(f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (rel.exists()) allFiles(rel.listFiles(), false, forEachFile);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
File rel = new File(dir, dirFilter);
|
File rel = new File(dir, dirFilter);
|
||||||
if (rel.exists()) fileList.addAll(allFiles(rel.listFiles(), false));
|
if (rel.exists()) allFiles(rel.listFiles(), false, forEachFile);
|
||||||
}
|
}
|
||||||
|
return page;
|
||||||
if (fileList.isEmpty()) {
|
|
||||||
BBC.SCHEMATIC_NONE.send(actor);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (formatName != null) {
|
|
||||||
final ClipboardFormat cf = ClipboardFormat.findByAlias(formatName);
|
|
||||||
fileList = fileList.stream()
|
|
||||||
.filter(file -> cf.isFormat(file))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
}
|
|
||||||
fileList = filter(fileList, filters);
|
|
||||||
|
|
||||||
final int perPage = actor instanceof Player ? 12 : 20; // More pages for console
|
|
||||||
int pageCount = (fileList.size() + perPage - 1) / perPage;
|
|
||||||
if (page < 1) {
|
|
||||||
BBC.SCHEMATIC_PAGE.send(actor, ">0");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (page > pageCount) {
|
|
||||||
BBC.SCHEMATIC_PAGE.send(actor, "<" + (pageCount + 1));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int sortType = args.hasFlag('d') ? -1 : args.hasFlag('n') ? 1 : 0;
|
|
||||||
// cleanup file list
|
|
||||||
Collections.sort(fileList, new Comparator<File>() {
|
|
||||||
@Override
|
|
||||||
public int compare(File f1, File f2) {
|
|
||||||
boolean dir1 = f1.isDirectory();
|
|
||||||
boolean dir2 = f2.isDirectory();
|
|
||||||
if (dir1 != dir2) return dir1 ? -1 : 1;
|
|
||||||
int res;
|
|
||||||
if (sortType == 0) { // use name by default
|
|
||||||
int p = f1.getParent().compareTo(f2.getParent());
|
|
||||||
if (p == 0) { // same parent, compare names
|
|
||||||
res = f1.getName().compareTo(f2.getName());
|
|
||||||
} else { // different parent, sort by that
|
|
||||||
res = p;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res = Long.valueOf(f1.lastModified()).compareTo(f2.lastModified()); // use date if there is a flag
|
|
||||||
if (sortType == 1) res = -res; // flip date for newest first instead of oldest first
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
int offset = (page - 1) * perPage;
|
|
||||||
|
|
||||||
int limit = Math.min(offset + perPage, fileList.size());
|
|
||||||
|
|
||||||
String fullArgs = (String) args.getLocals().get("arguments");
|
|
||||||
String baseCmd = null;
|
|
||||||
if (fullArgs != null) {
|
|
||||||
baseCmd = fullArgs.endsWith(" " + page) ? fullArgs.substring(0, fullArgs.length() - (" " + page).length()) : fullArgs;
|
|
||||||
}
|
|
||||||
Message m = new Message(BBC.SCHEMATIC_LIST, page, pageCount);
|
|
||||||
|
|
||||||
UUID uuid = playerFolder ? actor.getUniqueId() : null;
|
|
||||||
for (int i = offset; i < limit; i++) {
|
|
||||||
m.newline();
|
|
||||||
File file = fileList.get(i);
|
|
||||||
eachMsg.run(m, file.toURI(), getPath(dir, file, uuid));
|
|
||||||
}
|
|
||||||
if (baseCmd != null) {
|
|
||||||
m.newline().paginate(baseCmd, page, pageCount);
|
|
||||||
}
|
|
||||||
m.send(actor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<File> filter(List<File> fileList, List<String> filters) {
|
private static List<File> filter(List<File> fileList, List<String> filters) {
|
||||||
@ -822,23 +850,19 @@ public class UtilityCommands extends MethodCommands {
|
|||||||
return fileList;
|
return fileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<File> allFiles(File[] files, boolean recursive) {
|
private static void allFiles(File[] files, boolean recursive, Consumer<File> task) {
|
||||||
if (files == null || files.length == 0) return Arrays.asList();
|
if (files == null || files.length == 0) return;
|
||||||
List<File> fileList = new ArrayList<File>();
|
|
||||||
for (File f : files) {
|
for (File f : files) {
|
||||||
if (f.isDirectory()) {
|
if (f.isDirectory()) {
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
List<File> subFiles = allFiles(f.listFiles(), recursive);
|
allFiles(f.listFiles(), recursive, task);
|
||||||
if (subFiles == null || subFiles.isEmpty()) continue; // empty subdir
|
|
||||||
fileList.addAll(subFiles);
|
|
||||||
} else {
|
} else {
|
||||||
fileList.add(f);
|
task.accept(f);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fileList.add(f);
|
task.accept(f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fileList;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getPath(File root, File file, UUID uuid) {
|
private static String getPath(File root, File file, UUID uuid) {
|
||||||
|
@ -21,6 +21,7 @@ package com.sk89q.worldedit.extension.platform;
|
|||||||
|
|
||||||
import com.boydti.fawe.config.BBC;
|
import com.boydti.fawe.config.BBC;
|
||||||
import com.boydti.fawe.object.FawePlayer;
|
import com.boydti.fawe.object.FawePlayer;
|
||||||
|
import com.boydti.fawe.object.brush.visualization.VirtualWorld;
|
||||||
import com.boydti.fawe.object.exception.FaweException;
|
import com.boydti.fawe.object.exception.FaweException;
|
||||||
import com.boydti.fawe.object.pattern.PatternTraverser;
|
import com.boydti.fawe.object.pattern.PatternTraverser;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
@ -328,10 +329,6 @@ public class PlatformManager {
|
|||||||
return tool;
|
return tool;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleMove() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void handleBlockInteract(BlockInteractEvent event) {
|
public void handleBlockInteract(BlockInteractEvent event) {
|
||||||
@ -347,6 +344,13 @@ public class PlatformManager {
|
|||||||
if (actor instanceof Player) {
|
if (actor instanceof Player) {
|
||||||
final LocalSession session = worldEdit.getSessionManager().get(actor);
|
final LocalSession session = worldEdit.getSessionManager().get(actor);
|
||||||
Player playerActor = (Player) actor;
|
Player playerActor = (Player) actor;
|
||||||
|
|
||||||
|
VirtualWorld virtual = session.getVirtualWorld();
|
||||||
|
if (virtual != null) {
|
||||||
|
virtual.handleBlockInteract(playerActor, vector, event);
|
||||||
|
if (event.isCancelled()) return;
|
||||||
|
}
|
||||||
|
|
||||||
if (event.getType() == Interaction.HIT) {
|
if (event.getType() == Interaction.HIT) {
|
||||||
if (session.isToolControlEnabled() && playerActor.getItemInHand() == getConfiguration().wandItem) {
|
if (session.isToolControlEnabled() && playerActor.getItemInHand() == getConfiguration().wandItem) {
|
||||||
FawePlayer<?> fp = FawePlayer.wrap(playerActor);
|
FawePlayer<?> fp = FawePlayer.wrap(playerActor);
|
||||||
@ -394,6 +398,7 @@ public class PlatformManager {
|
|||||||
}
|
}
|
||||||
}, true, true);
|
}, true, true);
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (event.getType() == Interaction.OPEN) {
|
} else if (event.getType() == Interaction.OPEN) {
|
||||||
@ -402,17 +407,18 @@ public class PlatformManager {
|
|||||||
if (!actor.hasPermission("worldedit.selection.pos")) {
|
if (!actor.hasPermission("worldedit.selection.pos")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final RegionSelector selector = session.getRegionSelector(playerActor.getWorld());
|
if (fp.checkAction()) {
|
||||||
final Player player = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor), ((Player) actor).getLocation());
|
final RegionSelector selector = session.getRegionSelector(playerActor.getWorld());
|
||||||
fp.runAction(new Runnable() {
|
final Player player = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor), ((Player) actor).getLocation());
|
||||||
@Override
|
fp.runAction(new Runnable() {
|
||||||
public void run() {
|
@Override
|
||||||
if (selector.selectSecondary(vector, ActorSelectorLimits.forActor(player))) {
|
public void run() {
|
||||||
selector.explainSecondarySelection(actor, session, vector);
|
if (selector.selectSecondary(vector, ActorSelectorLimits.forActor(player))) {
|
||||||
|
selector.explainSecondarySelection(actor, session, vector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}, true, true);
|
||||||
}, true, true);
|
}
|
||||||
|
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -421,18 +427,21 @@ public class PlatformManager {
|
|||||||
if (tool != null && tool instanceof BlockTool) {
|
if (tool != null && tool instanceof BlockTool) {
|
||||||
if (tool.canUse(playerActor)) {
|
if (tool.canUse(playerActor)) {
|
||||||
FawePlayer<?> fp = FawePlayer.wrap(playerActor);
|
FawePlayer<?> fp = FawePlayer.wrap(playerActor);
|
||||||
final Player player = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor), ((Player) actor).getLocation());
|
if (fp.checkAction()) {
|
||||||
fp.runAction(new Runnable() {
|
final Player player = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap((Player) actor), ((Player) actor).getLocation());
|
||||||
@Override
|
fp.runAction(new Runnable() {
|
||||||
public void run() {
|
@Override
|
||||||
if (tool instanceof BrushTool) {
|
public void run() {
|
||||||
((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location);
|
if (tool instanceof BrushTool) {
|
||||||
} else {
|
((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location);
|
||||||
reset((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location);
|
} else {
|
||||||
|
reset((BlockTool) tool).actPrimary(queryCapability(Capability.WORLD_EDITING), getConfiguration(), player, session, location);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}, true, true);
|
||||||
}, true, true);
|
event.setCancelled(true);
|
||||||
event.setCancelled(true);
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,6 +469,13 @@ public class PlatformManager {
|
|||||||
// making changes to the world
|
// making changes to the world
|
||||||
Player actor = createProxyActor(event.getPlayer());
|
Player actor = createProxyActor(event.getPlayer());
|
||||||
final Player player = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap(actor), actor.getLocation(), true);
|
final Player player = new LocationMaskedPlayerWrapper(PlayerWrapper.wrap(actor), actor.getLocation(), true);
|
||||||
|
final LocalSession session = worldEdit.getSessionManager().get(player);
|
||||||
|
|
||||||
|
VirtualWorld virtual = session.getVirtualWorld();
|
||||||
|
if (virtual != null) {
|
||||||
|
virtual.handlePlayerInput(player, event);
|
||||||
|
if (event.isCancelled()) return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (event.getInputType()) {
|
switch (event.getInputType()) {
|
||||||
@ -484,8 +500,6 @@ public class PlatformManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final LocalSession session = worldEdit.getSessionManager().get(player);
|
|
||||||
|
|
||||||
final Tool tool = session.getTool(player);
|
final Tool tool = session.getTool(player);
|
||||||
if (tool != null && tool instanceof DoubleActionTraceTool) {
|
if (tool != null && tool instanceof DoubleActionTraceTool) {
|
||||||
if (tool.canUse(player)) {
|
if (tool.canUse(player)) {
|
||||||
@ -521,8 +535,6 @@ public class PlatformManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final LocalSession session = worldEdit.getSessionManager().get(player);
|
|
||||||
|
|
||||||
final Tool tool = session.getTool(player);
|
final Tool tool = session.getTool(player);
|
||||||
if (tool != null && tool instanceof TraceTool) {
|
if (tool != null && tool instanceof TraceTool) {
|
||||||
if (tool.canUse(player)) {
|
if (tool.canUse(player)) {
|
||||||
|
@ -38,7 +38,7 @@ public interface Extent extends InputExtent, OutputExtent {
|
|||||||
default
|
default
|
||||||
@Nullable
|
@Nullable
|
||||||
Entity createEntity(Location location, BaseEntity entity) {
|
Entity createEntity(Location location, BaseEntity entity) {
|
||||||
throw new UnsupportedOperationException(getClass() + " does not support entity creation!");
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -240,7 +240,7 @@ public interface Extent extends InputExtent, OutputExtent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean contain(Vector pt) {
|
default boolean contains(Vector pt) {
|
||||||
Vector min = getMinimumPoint();
|
Vector min = getMinimumPoint();
|
||||||
Vector max = getMaximumPoint();
|
Vector max = getMaximumPoint();
|
||||||
return (pt.containedWithin(min, max));
|
return (pt.containedWithin(min, max));
|
||||||
|
@ -39,6 +39,7 @@ import com.sk89q.worldedit.regions.Region;
|
|||||||
import com.sk89q.worldedit.util.Location;
|
import com.sk89q.worldedit.util.Location;
|
||||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||||
import com.sk89q.worldedit.world.registry.BundledBlockData;
|
import com.sk89q.worldedit.world.registry.BundledBlockData;
|
||||||
|
import java.io.Closeable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -52,7 +53,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||||||
* Stores block data as a multi-dimensional array of {@link BaseBlock}s and
|
* Stores block data as a multi-dimensional array of {@link BaseBlock}s and
|
||||||
* other data as lists or maps.
|
* other data as lists or maps.
|
||||||
*/
|
*/
|
||||||
public class BlockArrayClipboard implements Clipboard, LightingExtent {
|
public class BlockArrayClipboard implements Clipboard, LightingExtent, Closeable {
|
||||||
|
|
||||||
private Region region;
|
private Region region;
|
||||||
public FaweClipboard IMP;
|
public FaweClipboard IMP;
|
||||||
@ -120,6 +121,7 @@ public class BlockArrayClipboard implements Clipboard, LightingExtent {
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
IMP.close();
|
IMP.close();
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,7 @@ import com.boydti.fawe.config.Settings;
|
|||||||
import com.boydti.fawe.jnbt.NBTStreamer;
|
import com.boydti.fawe.jnbt.NBTStreamer;
|
||||||
import com.boydti.fawe.object.FaweOutputStream;
|
import com.boydti.fawe.object.FaweOutputStream;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.object.clipboard.AbstractClipboardFormat;
|
import com.boydti.fawe.object.clipboard.*;
|
||||||
import com.boydti.fawe.object.clipboard.DiskOptimizedClipboard;
|
|
||||||
import com.boydti.fawe.object.clipboard.FaweClipboard;
|
|
||||||
import com.boydti.fawe.object.clipboard.IClipboardFormat;
|
|
||||||
import com.boydti.fawe.object.clipboard.LazyClipboardHolder;
|
|
||||||
import com.boydti.fawe.object.clipboard.MultiClipboardHolder;
|
|
||||||
import com.boydti.fawe.object.clipboard.URIClipboardHolder;
|
|
||||||
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
import com.boydti.fawe.object.io.FastByteArrayOutputStream;
|
||||||
import com.boydti.fawe.object.io.PGZIPOutputStream;
|
import com.boydti.fawe.object.io.PGZIPOutputStream;
|
||||||
import com.boydti.fawe.object.io.ResettableFileInputStream;
|
import com.boydti.fawe.object.io.ResettableFileInputStream;
|
||||||
@ -47,32 +41,22 @@ import com.sk89q.jnbt.NBTConstants;
|
|||||||
import com.sk89q.jnbt.NBTInputStream;
|
import com.sk89q.jnbt.NBTInputStream;
|
||||||
import com.sk89q.jnbt.NBTOutputStream;
|
import com.sk89q.jnbt.NBTOutputStream;
|
||||||
import com.sk89q.worldedit.LocalConfiguration;
|
import com.sk89q.worldedit.LocalConfiguration;
|
||||||
|
import com.sk89q.worldedit.LocalSession;
|
||||||
import com.sk89q.worldedit.Vector;
|
import com.sk89q.worldedit.Vector;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
|
import com.sk89q.worldedit.entity.Player;
|
||||||
import com.sk89q.worldedit.extension.platform.Actor;
|
import com.sk89q.worldedit.extension.platform.Actor;
|
||||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
|
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||||
import com.sk89q.worldedit.world.registry.WorldData;
|
import com.sk89q.worldedit.world.registry.WorldData;
|
||||||
import java.io.BufferedInputStream;
|
import java.io.*;
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileFilter;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.channels.Channels;
|
import java.nio.channels.Channels;
|
||||||
import java.nio.channels.ReadableByteChannel;
|
import java.nio.channels.ReadableByteChannel;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.EnumSet;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
import java.util.zip.GZIPOutputStream;
|
import java.util.zip.GZIPOutputStream;
|
||||||
@ -481,6 +465,38 @@ public enum ClipboardFormat {
|
|||||||
return format.getWriter(outputStream);
|
return format.getWriter(outputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the player's clipboard
|
||||||
|
* @param player
|
||||||
|
* @param uri
|
||||||
|
* @param in
|
||||||
|
* @return the held clipboard
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public ClipboardHolder hold(Player player, URI uri, InputStream in) throws IOException {
|
||||||
|
checkNotNull(player);
|
||||||
|
checkNotNull(uri);
|
||||||
|
checkNotNull(in);
|
||||||
|
|
||||||
|
final ClipboardReader reader = getReader(in);
|
||||||
|
|
||||||
|
final WorldData worldData = player.getWorld().getWorldData();
|
||||||
|
final Clipboard clipboard;
|
||||||
|
|
||||||
|
LocalSession session = WorldEdit.getInstance().getSessionManager().get(player);
|
||||||
|
session.setClipboard(null);
|
||||||
|
if (reader instanceof SchematicReader) {
|
||||||
|
clipboard = ((SchematicReader) reader).read(player.getWorld().getWorldData(), player.getUniqueId());
|
||||||
|
} else if (reader instanceof StructureFormat) {
|
||||||
|
clipboard = ((StructureFormat) reader).read(player.getWorld().getWorldData(), player.getUniqueId());
|
||||||
|
} else {
|
||||||
|
clipboard = reader.read(player.getWorld().getWorldData());
|
||||||
|
}
|
||||||
|
URIClipboardHolder holder = new URIClipboardHolder(uri, clipboard, worldData);
|
||||||
|
session.setClipboard(holder);
|
||||||
|
return holder;
|
||||||
|
}
|
||||||
|
|
||||||
public Schematic load(File file) throws IOException {
|
public Schematic load(File file) throws IOException {
|
||||||
return load(new FileInputStream(file));
|
return load(new FileInputStream(file));
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ public class FaweForge implements IFawe {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPlatformVersion() {
|
public String getPlatformVersion() {
|
||||||
return FMLCommonHandler.instance().getMinecraftServerInstance().getMinecraftVersion();
|
return "1.12";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user