Various
FAWE texture support - Put any mods or client jars in `FastAsyncWorldEdit/textures` - These textures can be used in patterns and commands (WIP) - Adds #color:color pattern Added random flip to #fullcopy:<schem>:<random-rotate>:<random-flip> Improved parsing for clipboard loading FRB now only works in regions you are the owner of (or if you have admin bypass)
This commit is contained in:
parent
45827b611d
commit
17fb559f10
|
@ -26,4 +26,5 @@ gradle.log
|
||||||
build
|
build
|
||||||
/mvn
|
/mvn
|
||||||
spigot-1.10
|
spigot-1.10
|
||||||
wiki_permissions.md
|
wiki_permissions.md
|
||||||
|
/textures
|
|
@ -0,0 +1,243 @@
|
||||||
|
package com.boydti.fawe.bukkit.v1_11;
|
||||||
|
|
||||||
|
import com.boydti.fawe.object.FaweInputStream;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
import com.boydti.fawe.util.MathMan;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import net.minecraft.server.v1_11_R1.Block;
|
||||||
|
import net.minecraft.server.v1_11_R1.Chunk;
|
||||||
|
import net.minecraft.server.v1_11_R1.ChunkSection;
|
||||||
|
import net.minecraft.server.v1_11_R1.Entity;
|
||||||
|
import net.minecraft.server.v1_11_R1.ExceptionWorldConflict;
|
||||||
|
import net.minecraft.server.v1_11_R1.IAsyncChunkSaver;
|
||||||
|
import net.minecraft.server.v1_11_R1.IChunkLoader;
|
||||||
|
import net.minecraft.server.v1_11_R1.MinecraftKey;
|
||||||
|
import net.minecraft.server.v1_11_R1.NBTCompressedStreamTools;
|
||||||
|
import net.minecraft.server.v1_11_R1.NBTReadLimiter;
|
||||||
|
import net.minecraft.server.v1_11_R1.NBTTagCompound;
|
||||||
|
import net.minecraft.server.v1_11_R1.NBTTagList;
|
||||||
|
import net.minecraft.server.v1_11_R1.NextTickListEntry;
|
||||||
|
import net.minecraft.server.v1_11_R1.NibbleArray;
|
||||||
|
import net.minecraft.server.v1_11_R1.TileEntity;
|
||||||
|
import net.minecraft.server.v1_11_R1.World;
|
||||||
|
|
||||||
|
public class FaweChunkLoader implements IChunkLoader, IAsyncChunkSaver {
|
||||||
|
|
||||||
|
private final File folder;
|
||||||
|
private Long2ObjectMap<Long> hashes = new Long2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
public FaweChunkLoader(File folder) {
|
||||||
|
this.folder = folder;
|
||||||
|
System.out.println(folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeNextIO (save)
|
||||||
|
@Override
|
||||||
|
public boolean c() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadChunk
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Chunk a(World world, int x, int z) throws IOException {
|
||||||
|
long pair = MathMan.pairInt(x, z);
|
||||||
|
Long hash = hashes.get(pair);
|
||||||
|
if (hash == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
File file = new File(folder, hash.toString());
|
||||||
|
int length = (int) file.length();
|
||||||
|
try (FaweInputStream in = MainUtil.getCompressedIS(new FileInputStream(file), Math.min(length, 8192))) {
|
||||||
|
NBTTagCompound nbttagcompound = NBTCompressedStreamTools.a(in, NBTReadLimiter.a);
|
||||||
|
return readChunkFromNBT(world, nbttagcompound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Chunk readChunkFromNBT(World world, NBTTagCompound nbttagcompound) {
|
||||||
|
int i = nbttagcompound.getInt("xPos");
|
||||||
|
int j = nbttagcompound.getInt("zPos");
|
||||||
|
Chunk chunk = new Chunk(world, i, j);
|
||||||
|
chunk.a(nbttagcompound.getIntArray("HeightMap"));
|
||||||
|
chunk.d(nbttagcompound.getBoolean("TerrainPopulated"));
|
||||||
|
chunk.e(nbttagcompound.getBoolean("LightPopulated"));
|
||||||
|
chunk.c(nbttagcompound.getLong("InhabitedTime"));
|
||||||
|
NBTTagList nbttaglist = nbttagcompound.getList("Sections", 10);
|
||||||
|
ChunkSection[] achunksection = new ChunkSection[16];
|
||||||
|
boolean flag1 = world.worldProvider.m();
|
||||||
|
|
||||||
|
for(int k = 0; k < nbttaglist.size(); ++k) {
|
||||||
|
NBTTagCompound nbttagcompound1 = nbttaglist.get(k);
|
||||||
|
byte b0 = nbttagcompound1.getByte("Y");
|
||||||
|
ChunkSection chunksection = new ChunkSection(b0 << 4, flag1);
|
||||||
|
byte[] abyte = nbttagcompound1.getByteArray("Blocks");
|
||||||
|
NibbleArray nibblearray = new NibbleArray(nbttagcompound1.getByteArray("Data"));
|
||||||
|
NibbleArray nibblearray1 = nbttagcompound1.hasKeyOfType("Add", 7) ? new NibbleArray(nbttagcompound1.getByteArray("Add")):null;
|
||||||
|
chunksection.getBlocks().a(abyte, nibblearray, nibblearray1);
|
||||||
|
chunksection.a(new NibbleArray(nbttagcompound1.getByteArray("BlockLight")));
|
||||||
|
if(flag1) {
|
||||||
|
chunksection.b(new NibbleArray(nbttagcompound1.getByteArray("SkyLight")));
|
||||||
|
}
|
||||||
|
|
||||||
|
chunksection.recalcBlockCounts();
|
||||||
|
achunksection[b0] = chunksection;
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk.a(achunksection);
|
||||||
|
if(nbttagcompound.hasKeyOfType("Biomes", 7)) {
|
||||||
|
chunk.a(nbttagcompound.getByteArray("Biomes"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// saveChunk
|
||||||
|
@Override
|
||||||
|
public void a(World world, Chunk chunk) throws IOException, ExceptionWorldConflict {
|
||||||
|
try {
|
||||||
|
NBTTagCompound exception = new NBTTagCompound();
|
||||||
|
NBTTagCompound nbttagcompound1 = new NBTTagCompound();
|
||||||
|
exception.set("Level", nbttagcompound1);
|
||||||
|
exception.setInt("DataVersion", 819);
|
||||||
|
this.writeChunkToNBT(chunk, world, nbttagcompound1);
|
||||||
|
// this.a(chunk.k(), exception);
|
||||||
|
} catch (Exception var5) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeChunkToNBT(Chunk chunk, World world, NBTTagCompound nbttagcompound) {
|
||||||
|
nbttagcompound.setInt("xPos", chunk.locX);
|
||||||
|
nbttagcompound.setInt("zPos", chunk.locZ);
|
||||||
|
nbttagcompound.setLong("LastUpdate", world.getTime());
|
||||||
|
nbttagcompound.setIntArray("HeightMap", chunk.r());
|
||||||
|
nbttagcompound.setBoolean("TerrainPopulated", chunk.isDone());
|
||||||
|
nbttagcompound.setBoolean("LightPopulated", chunk.v());
|
||||||
|
nbttagcompound.setLong("InhabitedTime", chunk.x());
|
||||||
|
ChunkSection[] achunksection = chunk.getSections();
|
||||||
|
NBTTagList nbttaglist = new NBTTagList();
|
||||||
|
boolean flag = world.worldProvider.m();
|
||||||
|
ChunkSection[] achunksection1 = achunksection;
|
||||||
|
int i = achunksection.length;
|
||||||
|
|
||||||
|
NBTTagCompound nbttagcompound1;
|
||||||
|
for(int nbttaglist1 = 0; nbttaglist1 < i; ++nbttaglist1) {
|
||||||
|
ChunkSection iterator = achunksection1[nbttaglist1];
|
||||||
|
if(iterator != Chunk.a) {
|
||||||
|
nbttagcompound1 = new NBTTagCompound();
|
||||||
|
nbttagcompound1.setByte("Y", (byte)(iterator.getYPosition() >> 4 & 255));
|
||||||
|
byte[] nbttaglist2 = new byte[4096];
|
||||||
|
NibbleArray list = new NibbleArray();
|
||||||
|
NibbleArray nibblearray1 = iterator.getBlocks().exportData(nbttaglist2, list);
|
||||||
|
nbttagcompound1.setByteArray("Blocks", nbttaglist2);
|
||||||
|
nbttagcompound1.setByteArray("Data", list.asBytes());
|
||||||
|
if(nibblearray1 != null) {
|
||||||
|
nbttagcompound1.setByteArray("Add", nibblearray1.asBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
nbttagcompound1.setByteArray("BlockLight", iterator.getEmittedLightArray().asBytes());
|
||||||
|
if(flag) {
|
||||||
|
nbttagcompound1.setByteArray("SkyLight", iterator.getSkyLightArray().asBytes());
|
||||||
|
} else {
|
||||||
|
nbttagcompound1.setByteArray("SkyLight", new byte[iterator.getEmittedLightArray().asBytes().length]);
|
||||||
|
}
|
||||||
|
|
||||||
|
nbttaglist.add(nbttagcompound1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nbttagcompound.set("Sections", nbttaglist);
|
||||||
|
nbttagcompound.setByteArray("Biomes", chunk.getBiomeIndex());
|
||||||
|
chunk.g(false);
|
||||||
|
NBTTagList var22 = new NBTTagList();
|
||||||
|
|
||||||
|
Iterator var23;
|
||||||
|
for(i = 0; i < chunk.getEntitySlices().length; ++i) {
|
||||||
|
var23 = chunk.getEntitySlices()[i].iterator();
|
||||||
|
|
||||||
|
while(var23.hasNext()) {
|
||||||
|
Entity var24 = (Entity)var23.next();
|
||||||
|
nbttagcompound1 = new NBTTagCompound();
|
||||||
|
if(var24.d(nbttagcompound1)) {
|
||||||
|
chunk.g(true);
|
||||||
|
var22.add(nbttagcompound1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nbttagcompound.set("Entities", var22);
|
||||||
|
NBTTagList var25 = new NBTTagList();
|
||||||
|
var23 = chunk.getTileEntities().values().iterator();
|
||||||
|
|
||||||
|
while(var23.hasNext()) {
|
||||||
|
TileEntity var26 = (TileEntity)var23.next();
|
||||||
|
nbttagcompound1 = var26.save(new NBTTagCompound());
|
||||||
|
var25.add(nbttagcompound1);
|
||||||
|
}
|
||||||
|
|
||||||
|
nbttagcompound.set("TileEntities", var25);
|
||||||
|
List var27 = world.a(chunk, false);
|
||||||
|
if(var27 != null) {
|
||||||
|
long k = world.getTime();
|
||||||
|
NBTTagList nbttaglist3 = new NBTTagList();
|
||||||
|
Iterator iterator1 = var27.iterator();
|
||||||
|
|
||||||
|
while(iterator1.hasNext()) {
|
||||||
|
NextTickListEntry nextticklistentry = (NextTickListEntry)iterator1.next();
|
||||||
|
NBTTagCompound nbttagcompound2 = new NBTTagCompound();
|
||||||
|
MinecraftKey minecraftkey = (MinecraftKey) Block.REGISTRY.b(nextticklistentry.a());
|
||||||
|
nbttagcompound2.setString("i", minecraftkey == null?"":minecraftkey.toString());
|
||||||
|
nbttagcompound2.setInt("x", nextticklistentry.a.getX());
|
||||||
|
nbttagcompound2.setInt("y", nextticklistentry.a.getY());
|
||||||
|
nbttagcompound2.setInt("z", nextticklistentry.a.getZ());
|
||||||
|
nbttagcompound2.setInt("t", (int)(nextticklistentry.b - k));
|
||||||
|
nbttagcompound2.setInt("p", nextticklistentry.c);
|
||||||
|
nbttaglist3.add(nbttagcompound2);
|
||||||
|
}
|
||||||
|
|
||||||
|
nbttagcompound.set("TileTicks", nbttaglist3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// saveExtraChunkData
|
||||||
|
@Override
|
||||||
|
public void b(World world, Chunk chunk) throws IOException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// chunkTick
|
||||||
|
@Override
|
||||||
|
public void a() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// saveExtraData
|
||||||
|
@Override
|
||||||
|
public void b() {
|
||||||
|
// try {
|
||||||
|
// this.savingExtraData = true;
|
||||||
|
//
|
||||||
|
// while(true) {
|
||||||
|
// if(this.writeNextIO()) {
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } finally {
|
||||||
|
// this.savingExtraData = false;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// isChunkGeneratedAt
|
||||||
|
@Override
|
||||||
|
public boolean a(int x, int z) {
|
||||||
|
return hashes.containsKey(MathMan.pairInt(x, z));
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import com.boydti.fawe.util.MainUtil;
|
||||||
import com.boydti.fawe.util.MemUtil;
|
import com.boydti.fawe.util.MemUtil;
|
||||||
import com.boydti.fawe.util.StringMan;
|
import com.boydti.fawe.util.StringMan;
|
||||||
import com.boydti.fawe.util.TaskManager;
|
import com.boydti.fawe.util.TaskManager;
|
||||||
|
import com.boydti.fawe.util.TextureUtil;
|
||||||
import com.boydti.fawe.util.Updater;
|
import com.boydti.fawe.util.Updater;
|
||||||
import com.boydti.fawe.util.WEManager;
|
import com.boydti.fawe.util.WEManager;
|
||||||
import com.sk89q.jnbt.NBTInputStream;
|
import com.sk89q.jnbt.NBTInputStream;
|
||||||
|
@ -184,6 +185,7 @@ public class Fawe {
|
||||||
private FaweVersion version;
|
private FaweVersion version;
|
||||||
private VisualQueue visualQueue;
|
private VisualQueue visualQueue;
|
||||||
private Updater updater;
|
private Updater updater;
|
||||||
|
private TextureUtil textures;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the implementation specific class
|
* Get the implementation specific class
|
||||||
|
@ -272,7 +274,6 @@ public class Fawe {
|
||||||
WEManager.IMP.managers.add(new PlotSquaredFeature());
|
WEManager.IMP.managers.add(new PlotSquaredFeature());
|
||||||
Fawe.debug("Plugin 'PlotSquared' found. Using it now.");
|
Fawe.debug("Plugin 'PlotSquared' found. Using it now.");
|
||||||
} catch (Throwable e) {}
|
} catch (Throwable e) {}
|
||||||
Fawe.this.worldedit = WorldEdit.getInstance();
|
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
|
@ -319,6 +320,19 @@ public class Fawe {
|
||||||
return updater;
|
return updater;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TextureUtil getTextureUtil() {
|
||||||
|
TextureUtil tmp = textures;
|
||||||
|
if (tmp == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
tmp = textures;
|
||||||
|
if (tmp == null) {
|
||||||
|
textures = tmp = new TextureUtil();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The FaweTimer is a useful class for monitoring TPS
|
* The FaweTimer is a useful class for monitoring TPS
|
||||||
* @return FaweTimer
|
* @return FaweTimer
|
||||||
|
@ -372,13 +386,8 @@ public class Fawe {
|
||||||
BBC.load(new File(this.IMP.getDirectory(), "message.yml"));
|
BBC.load(new File(this.IMP.getDirectory(), "message.yml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private WorldEdit worldedit;
|
|
||||||
|
|
||||||
public WorldEdit getWorldEdit() {
|
public WorldEdit getWorldEdit() {
|
||||||
if (this.worldedit == null) {
|
return WorldEdit.getInstance();
|
||||||
return worldedit = WorldEdit.getInstance();
|
|
||||||
}
|
|
||||||
return this.worldedit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setupInjector() {
|
public static void setupInjector() {
|
||||||
|
|
|
@ -68,6 +68,10 @@ public class Settings extends Config {
|
||||||
|
|
||||||
@Comment("Paths for various directories")
|
@Comment("Paths for various directories")
|
||||||
public static final class PATHS {
|
public static final class PATHS {
|
||||||
|
@Comment({
|
||||||
|
"Put any minecraft or mod jars for FAWE to be aware of block textures",
|
||||||
|
})
|
||||||
|
public String TEXTURES = "textures";
|
||||||
public String HISTORY = "history";
|
public String HISTORY = "history";
|
||||||
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")
|
||||||
|
|
|
@ -8,6 +8,7 @@ import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.function.mask.Mask;
|
import com.sk89q.worldedit.function.mask.Mask;
|
||||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||||
|
import com.sk89q.worldedit.math.transform.Transform;
|
||||||
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;
|
||||||
|
|
||||||
|
@ -45,10 +46,11 @@ public class SchemGen extends Resource {
|
||||||
}
|
}
|
||||||
Clipboard clipboard = holder.getClipboard();
|
Clipboard clipboard = holder.getClipboard();
|
||||||
Schematic schematic = new Schematic(clipboard);
|
Schematic schematic = new Schematic(clipboard);
|
||||||
if (holder.getTransform().isIdentity()) {
|
Transform transform = holder.getTransform();
|
||||||
|
if (transform.isIdentity()) {
|
||||||
schematic.paste(extent, mutable, false);
|
schematic.paste(extent, mutable, false);
|
||||||
} else {
|
} else {
|
||||||
schematic.paste(extent, worldData, mutable, false, holder.getTransform());
|
schematic.paste(extent, worldData, mutable, false, transform);
|
||||||
}
|
}
|
||||||
mutable.mutY(y);
|
mutable.mutY(y);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.boydti.fawe.object.brush.heightmap;
|
||||||
|
|
||||||
|
public class AverageHeightMapFilter {
|
||||||
|
private int[] inData;
|
||||||
|
private int[] buffer;
|
||||||
|
private final int width;
|
||||||
|
private final int height;
|
||||||
|
private final int minY;
|
||||||
|
private final int maxY;
|
||||||
|
|
||||||
|
public AverageHeightMapFilter(int[] inData, int width, int height, int minY, int maxY) {
|
||||||
|
this.inData = inData;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.minY = minY;
|
||||||
|
this.maxY = maxY;
|
||||||
|
this.buffer = new int[inData.length];
|
||||||
|
}
|
||||||
|
public int[] filter(int iterations) {
|
||||||
|
for (int j = 0; j < iterations; j++) {
|
||||||
|
int a = -width;
|
||||||
|
int b = width;
|
||||||
|
int c = 1;
|
||||||
|
int d = -1;
|
||||||
|
for (int i = 0; i < inData.length; i++, a++, b++, c++, d++) {
|
||||||
|
int height = inData[i];
|
||||||
|
if (height < minY || height > maxY) {
|
||||||
|
buffer[i] = height;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int average = (2 + get(a, height) + get(b, height) + get(c, height) + get(d, height)) >> 2;
|
||||||
|
buffer[i] = average;
|
||||||
|
}
|
||||||
|
int[] tmp = inData;
|
||||||
|
inData = buffer;
|
||||||
|
buffer = tmp;
|
||||||
|
}
|
||||||
|
return inData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int get(int index, int def) {
|
||||||
|
int val = inData[Math.max(0, Math.min(inData.length - 1, index))];
|
||||||
|
if (val < minY || val > maxY) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
|
@ -135,12 +135,16 @@ public class DiskStorageHistory extends FaweStreamChangeSet {
|
||||||
enttFile.delete();
|
enttFile.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void undo(FawePlayer fp) {
|
public void undo(FawePlayer fp, RegionWrapper[] regions) {
|
||||||
EditSession session = toEditSession(fp);
|
EditSession session = toEditSession(fp, regions);
|
||||||
session.undo(session);
|
session.undo(session);
|
||||||
deleteFiles();
|
deleteFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void undo(FawePlayer fp) {
|
||||||
|
undo(fp, null);
|
||||||
|
}
|
||||||
|
|
||||||
public UUID getUUID() {
|
public UUID getUUID() {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import com.boydti.fawe.config.Settings;
|
||||||
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.RegionWrapper;
|
||||||
import com.boydti.fawe.object.RunnableVal2;
|
import com.boydti.fawe.object.RunnableVal2;
|
||||||
import com.boydti.fawe.util.EditSessionBuilder;
|
import com.boydti.fawe.util.EditSessionBuilder;
|
||||||
import com.boydti.fawe.util.MainUtil;
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
@ -138,7 +139,17 @@ public abstract class FaweChangeSet implements ChangeSet {
|
||||||
public void delete() {};
|
public void delete() {};
|
||||||
|
|
||||||
public EditSession toEditSession(FawePlayer player) {
|
public EditSession toEditSession(FawePlayer player) {
|
||||||
EditSession editSession = new EditSessionBuilder(getWorld()).player(player).autoQueue(false).fastmode(false).checkMemory(false).changeSet(this).limitUnlimited().allowedRegionsEverywhere().build();
|
return toEditSession(player, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EditSession toEditSession(FawePlayer player, RegionWrapper[] regions) {
|
||||||
|
EditSessionBuilder builder = new EditSessionBuilder(getWorld()).player(player).autoQueue(false).fastmode(false).checkMemory(false).changeSet(this).limitUnlimited();
|
||||||
|
if (regions != null) {
|
||||||
|
builder.allowedRegions(regions);
|
||||||
|
} else {
|
||||||
|
builder.allowedRegionsEverywhere();
|
||||||
|
}
|
||||||
|
EditSession editSession = builder.build();
|
||||||
editSession.setSize(1);
|
editSession.setSize(1);
|
||||||
return editSession;
|
return editSession;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package com.boydti.fawe.object.clipboard;
|
package com.boydti.fawe.object.clipboard;
|
||||||
|
|
||||||
import com.boydti.fawe.object.PseudoRandom;
|
import com.boydti.fawe.object.PseudoRandom;
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
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;
|
||||||
import com.sk89q.worldedit.world.registry.WorldData;
|
import com.sk89q.worldedit.world.registry.WorldData;
|
||||||
|
|
||||||
public class MultiClipboardHolder extends ClipboardHolder{
|
public class MultiClipboardHolder extends ClipboardHolder{
|
||||||
private final ClipboardHolder[] holders;
|
private final ClipboardHolder[] holders;
|
||||||
|
@ -41,4 +41,4 @@ public class MultiClipboardHolder extends ClipboardHolder{
|
||||||
if (holder != null) holder.close();
|
if (holder != null) holder.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,6 +10,7 @@ import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
import com.sk89q.worldedit.function.pattern.AbstractPattern;
|
import com.sk89q.worldedit.function.pattern.AbstractPattern;
|
||||||
import com.sk89q.worldedit.math.transform.AffineTransform;
|
import com.sk89q.worldedit.math.transform.AffineTransform;
|
||||||
|
import com.sk89q.worldedit.math.transform.Transform;
|
||||||
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;
|
||||||
|
|
||||||
|
@ -21,9 +22,10 @@ public class RandomFullClipboardPattern extends AbstractPattern {
|
||||||
private final ClipboardHolder[] clipboards;
|
private final ClipboardHolder[] clipboards;
|
||||||
private final MutableBlockVector mutable = new MutableBlockVector();
|
private final MutableBlockVector mutable = new MutableBlockVector();
|
||||||
private boolean randomRotate;
|
private boolean randomRotate;
|
||||||
|
private boolean randomFlip;
|
||||||
private WorldData worldData;
|
private WorldData worldData;
|
||||||
|
|
||||||
public RandomFullClipboardPattern(Extent extent, WorldData worldData, ClipboardHolder[] clipboards, boolean randomRotate) {
|
public RandomFullClipboardPattern(Extent extent, WorldData worldData, ClipboardHolder[] clipboards, boolean randomRotate, boolean randomFlip) {
|
||||||
checkNotNull(clipboards);
|
checkNotNull(clipboards);
|
||||||
this.clipboards = clipboards;
|
this.clipboards = clipboards;
|
||||||
this.extent = extent;
|
this.extent = extent;
|
||||||
|
@ -34,15 +36,24 @@ public class RandomFullClipboardPattern extends AbstractPattern {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException {
|
public boolean apply(Extent extent, Vector setPosition, Vector getPosition) throws WorldEditException {
|
||||||
ClipboardHolder holder = clipboards[PseudoRandom.random.random(clipboards.length)];
|
ClipboardHolder holder = clipboards[PseudoRandom.random.random(clipboards.length)];
|
||||||
|
AffineTransform transform = new AffineTransform();
|
||||||
if (randomRotate) {
|
if (randomRotate) {
|
||||||
|
transform = transform.rotateY(PseudoRandom.random.random(4) * 90);
|
||||||
holder.setTransform(new AffineTransform().rotateY(PseudoRandom.random.random(4) * 90));
|
holder.setTransform(new AffineTransform().rotateY(PseudoRandom.random.random(4) * 90));
|
||||||
}
|
}
|
||||||
|
if (randomFlip) {
|
||||||
|
transform = transform.scale(new Vector(1, 0, 0).multiply(-2).add(1, 1, 1));
|
||||||
|
}
|
||||||
|
if (!transform.isIdentity()) {
|
||||||
|
holder.setTransform(transform);
|
||||||
|
}
|
||||||
Clipboard clipboard = holder.getClipboard();
|
Clipboard clipboard = holder.getClipboard();
|
||||||
Schematic schematic = new Schematic(clipboard);
|
Schematic schematic = new Schematic(clipboard);
|
||||||
if (holder.getTransform().isIdentity()) {
|
Transform newTransform = holder.getTransform();
|
||||||
|
if (newTransform.isIdentity()) {
|
||||||
schematic.paste(extent, setPosition, false);
|
schematic.paste(extent, setPosition, false);
|
||||||
} else {
|
} else {
|
||||||
schematic.paste(extent, worldData, setPosition, false, holder.getTransform());
|
schematic.paste(extent, worldData, setPosition, false, newTransform);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,313 @@
|
||||||
package com.boydti.fawe.util;
|
package com.boydti.fawe.util;
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.config.Settings;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.registry.BundledBlockData;
|
import com.sk89q.worldedit.world.registry.BundledBlockData;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.json.simple.parser.JSONParser;
|
||||||
|
import org.json.simple.parser.ParseException;
|
||||||
|
|
||||||
public class TextureUtil {
|
public class TextureUtil {
|
||||||
private final File folder;
|
private final File folder;
|
||||||
private Color[] colors;
|
|
||||||
|
|
||||||
public TextureUtil(File folder) {
|
private int[] blockColors = new int[Character.MAX_VALUE + 1];
|
||||||
|
private int[] validColors;
|
||||||
|
private int[] validBlockIds;
|
||||||
|
|
||||||
|
private String getFileName(String path) {
|
||||||
|
String[] split = path.toString().split("[/|\\\\]");
|
||||||
|
String name = split[split.length - 1];
|
||||||
|
int dot = name.indexOf('.');
|
||||||
|
if (dot != -1) {
|
||||||
|
name = name.substring(0, dot);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String alphabetize(String asset) {
|
||||||
|
String[] split = asset.split("_");
|
||||||
|
Arrays.sort(split);
|
||||||
|
return StringMan.join(split, "_");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unfortunately the names used for the textures don't match the block id <br>
|
||||||
|
* - This will try to guess possible relevant block ids <br>
|
||||||
|
* - Match some by reformatting <br>
|
||||||
|
* - Match by reordering <br>
|
||||||
|
* - Match by appending / removing <br>
|
||||||
|
* - Match by hardcoded values <br>
|
||||||
|
*/
|
||||||
|
private void addTextureNames(String modelName, JSONObject root, Map<String, String> texturesMap) {
|
||||||
|
JSONObject textures = (JSONObject) root.get("textures");
|
||||||
|
if (textures == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Set<String> names = new HashSet<>();
|
||||||
|
String all = (String) textures.get("all");
|
||||||
|
if (all != null) {
|
||||||
|
String textureName = getFileName(all);
|
||||||
|
// Add the model
|
||||||
|
names.add(modelName);
|
||||||
|
names.add(textureName);
|
||||||
|
for (String name : new ArrayList<>(names)) {
|
||||||
|
if (name.contains("big_oak")) {
|
||||||
|
name = name.replaceAll("big_oak", "oak");
|
||||||
|
names.add(name);
|
||||||
|
}
|
||||||
|
String[] split = name.split("_");
|
||||||
|
switch (split[0]) {
|
||||||
|
case "glass":
|
||||||
|
names.add(name.replaceAll("glass_", "stained_glass_"));
|
||||||
|
break;
|
||||||
|
case "log":
|
||||||
|
names.add(name.replaceAll("log_", "log2_"));
|
||||||
|
break;
|
||||||
|
case "leaves":
|
||||||
|
names.add(name.replaceAll("leaves_", "leaves2_"));
|
||||||
|
case "mushroom":
|
||||||
|
names.add(name.replaceAll("mushroom_block_skin_", "mushroom_block_"));
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String name : names) {
|
||||||
|
texturesMap.putIfAbsent(name, textureName);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (textures.containsKey("side") && textures.containsKey("end") && !textures.containsKey("bottom") && !textures.containsKey("top") && !textures.containsKey("platform")) {
|
||||||
|
String side = (String) textures.get("side");
|
||||||
|
} else if (textures.containsKey("up")) {
|
||||||
|
// TODO: Just mushroom, not super important
|
||||||
|
String up = (String) textures.get("up");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureUtil() throws IOException, ParseException {
|
||||||
|
this(MainUtil.getFile(Fawe.imp().getDirectory(), Settings.IMP.PATHS.TEXTURES));
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureUtil(File folder) throws IOException, ParseException {
|
||||||
this.folder = folder;
|
this.folder = folder;
|
||||||
BundledBlockData bundled = BundledBlockData.getInstance();
|
loadModTextures();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadModTextures() throws IOException, ParseException {
|
||||||
|
if (!folder.exists()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (File file : folder.listFiles(new FilenameFilter() {
|
for (File file : folder.listFiles(new FilenameFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File dir, String name) {
|
public boolean accept(File dir, String name) {
|
||||||
return name.endsWith(".png");
|
return name.endsWith(".jar");
|
||||||
}
|
}
|
||||||
})) {
|
})) {
|
||||||
String name = file.getName().split("\\.")[0];
|
ZipFile zipFile = new ZipFile(file);
|
||||||
|
// get mods
|
||||||
|
|
||||||
|
BundledBlockData bundled = BundledBlockData.getInstance();
|
||||||
|
bundled.loadFromResource();
|
||||||
|
|
||||||
|
Set<String> mods = new HashSet<String>();
|
||||||
|
{
|
||||||
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry entry = entries.nextElement();
|
||||||
|
String name = entry.getName();
|
||||||
|
Path path = Paths.get(name);
|
||||||
|
if (path.startsWith("assets" + File.separator)) {
|
||||||
|
String[] split = path.toString().split(Pattern.quote(File.separator));
|
||||||
|
if (split.length > 1) {
|
||||||
|
String modId = split[1];
|
||||||
|
if (mods.add(modId)) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Int2ObjectOpenHashMap<Integer> colorMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
for (String modId : mods) {
|
||||||
|
String modelsDir = "assets" + "/" + modId + "/" + "models" + "/" + "block";
|
||||||
|
String texturesDir = "assets" + "/" + modId + "/" + "textures" + "/" + "blocks";
|
||||||
|
Map<String, String> texturesMap = new ConcurrentHashMap<>();
|
||||||
|
// Read models
|
||||||
|
{
|
||||||
|
// Read .json
|
||||||
|
// Find texture file
|
||||||
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry entry = entries.nextElement();
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = entry.getName();
|
||||||
|
if (!name.endsWith(".json")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Path path = Paths.get(name);
|
||||||
|
if (path.startsWith(modelsDir)) {
|
||||||
|
String[] split = path.toString().split("[/|\\\\|\\.]");
|
||||||
|
String blockName = getFileName(path.toString());
|
||||||
|
// Ignore special models
|
||||||
|
if (blockName.startsWith("#")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try (InputStream is = zipFile.getInputStream(entry)) { //Read from a file, or a HttpRequest, or whatever.
|
||||||
|
JSONParser parser = new JSONParser();
|
||||||
|
JSONObject root = (JSONObject) parser.parse(new InputStreamReader(is, "UTF-8"));
|
||||||
|
addTextureNames(blockName, root, texturesMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String key : new ArrayList<>(texturesMap.keySet())) {
|
||||||
|
String value = texturesMap.get(key);
|
||||||
|
texturesMap.put(alphabetize(key), value);
|
||||||
|
String[] split = key.split("_");
|
||||||
|
if (split.length > 1) {
|
||||||
|
key = StringMan.join(Arrays.copyOfRange(split, 0, split.length - 1), "_");
|
||||||
|
texturesMap.putIfAbsent(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Int2ObjectOpenHashMap<String> idMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
for (String id : bundled.stateMap.keySet()) {
|
||||||
|
if (id.startsWith(modId)) {
|
||||||
|
BaseBlock block = bundled.findByState(id);
|
||||||
|
id = id.substring(modId.length() + 1).replaceAll(":", "_");
|
||||||
|
String texture = texturesMap.remove(id);
|
||||||
|
if (texture == null) {
|
||||||
|
texture = texturesMap.remove(alphabetize(id));
|
||||||
|
}
|
||||||
|
if (texture != null) {
|
||||||
|
idMap.put(block.getCombined(), texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
for (Int2ObjectMap.Entry<String> entry : idMap.int2ObjectEntrySet()) {
|
||||||
|
int combined = entry.getIntKey();
|
||||||
|
String path = texturesDir + "/" + entry.getValue() + ".png";
|
||||||
|
ZipEntry textureEntry = zipFile.getEntry(path);
|
||||||
|
try (InputStream is = zipFile.getInputStream(textureEntry)) {
|
||||||
|
BufferedImage image = ImageIO.read(is);
|
||||||
|
int color = getColor(image);
|
||||||
|
colorMap.put((int) combined, (Integer) color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Load and map the textures
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validBlockIds = new int[colorMap.size()];
|
||||||
|
validColors = new int[colorMap.size()];
|
||||||
|
Arrays.fill(blockColors, 0);
|
||||||
|
int index = 0;
|
||||||
|
for (Int2ObjectMap.Entry<Integer> entry : colorMap.int2ObjectEntrySet()) {
|
||||||
|
int combinedId = entry.getIntKey();
|
||||||
|
int color = entry.getValue();
|
||||||
|
blockColors[combinedId] = color;
|
||||||
|
validBlockIds[index] = combinedId;
|
||||||
|
validColors[index] = color;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
zipFile.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
|
public BaseBlock getNearestBlock(int color) {
|
||||||
|
long min = Long.MAX_VALUE;
|
||||||
|
int closest = 0;
|
||||||
|
int red1 = (color >> 16) & 0xFF;
|
||||||
|
int green1 = (color >> 8) & 0xFF;
|
||||||
|
int blue1 = (color >> 0) & 0xFF;
|
||||||
|
int alpha = (color >> 24) & 0xFF;
|
||||||
|
for (int i = 0; i < validColors.length; i++) {
|
||||||
|
int other = validColors[i];
|
||||||
|
if (((other >> 24) & 0xFF) == alpha) {
|
||||||
|
long distance = colorDistance(red1, green1, blue1, other);
|
||||||
|
if (distance < min) {
|
||||||
|
min = distance;
|
||||||
|
closest = validBlockIds[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FaweCache.CACHE_BLOCK[closest];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor(BaseBlock block) {
|
||||||
|
return blockColors[block.getCombined()];
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasAlpha(int color) {
|
||||||
|
int alpha = (color >> 24) & 0xFF;
|
||||||
|
return alpha != 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long colorDistance(int c1, int c2) {
|
||||||
|
int red1 = (c1 >> 16) & 0xFF;
|
||||||
|
int green1 = (c1 >> 8) & 0xFF;
|
||||||
|
int blue1 = (c1 >> 0) & 0xFF;
|
||||||
|
return colorDistance(red1, green1, blue1, c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long colorDistance(int red1, int green1, int blue1, int c2) {
|
||||||
|
int red2 = (c2 >> 16) & 0xFF;
|
||||||
|
int green2 = (c2 >> 8) & 0xFF;
|
||||||
|
int blue2 = (c2 >> 0) & 0xFF;
|
||||||
|
int rmean = (red1 + red2) >> 1;
|
||||||
|
int r = red1 - red2;
|
||||||
|
int g = green1 - green2;
|
||||||
|
int b = blue1 - blue2;
|
||||||
|
return (((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor(BufferedImage image) {
|
||||||
|
int width = image.getWidth();
|
||||||
|
int height = image.getHeight();
|
||||||
|
long totalRed = 0;
|
||||||
|
long totalGreen = 0;
|
||||||
|
long totalBlue = 0;
|
||||||
|
long totalAlpha = 0;
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
int color = image.getRGB(x, y);
|
||||||
|
totalRed += (color >> 16) & 0xFF;
|
||||||
|
totalGreen += (color >> 8) & 0xFF;
|
||||||
|
totalBlue += (color >> 0) & 0xFF;
|
||||||
|
totalAlpha += (color >> 24) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int a = width * height;
|
||||||
|
Color color = new Color((int) (totalRed / a), (int) (totalGreen / a), (int) (totalBlue / a), (int) (totalAlpha / a));
|
||||||
|
return color.getRGB();
|
||||||
|
}
|
||||||
|
|
||||||
// public Color getColor(BaseBlock block) {
|
// public Color getColor(BaseBlock block) {
|
||||||
// long r;
|
// long r;
|
||||||
// long b;
|
// long b;
|
||||||
|
|
|
@ -28,14 +28,12 @@ import com.boydti.fawe.database.RollbackDatabase;
|
||||||
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
import com.boydti.fawe.logging.rollback.RollbackOptimizedHistory;
|
||||||
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.MaskedFaweQueue;
|
|
||||||
import com.boydti.fawe.object.RegionWrapper;
|
import com.boydti.fawe.object.RegionWrapper;
|
||||||
import com.boydti.fawe.object.RunnableVal;
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
import com.boydti.fawe.object.changeset.DiskStorageHistory;
|
||||||
import com.boydti.fawe.regions.FaweMaskManager;
|
import com.boydti.fawe.regions.FaweMaskManager;
|
||||||
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.SetQueue;
|
|
||||||
import com.sk89q.minecraft.util.commands.Command;
|
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.CommandPermissions;
|
import com.sk89q.minecraft.util.commands.CommandPermissions;
|
||||||
|
@ -180,15 +178,21 @@ public class HistoryCommands {
|
||||||
|
|
||||||
final FaweQueue finalQueue;
|
final FaweQueue finalQueue;
|
||||||
RegionWrapper[] allowedRegions = fp.getCurrentRegions(FaweMaskManager.MaskType.OWNER);
|
RegionWrapper[] allowedRegions = fp.getCurrentRegions(FaweMaskManager.MaskType.OWNER);
|
||||||
if (allowedRegions.length != 1 || !allowedRegions[0].isGlobal()) {
|
if (allowedRegions == null) {
|
||||||
finalQueue = new MaskedFaweQueue(SetQueue.IMP.getNewQueue(fp.getWorld(), true, false), allowedRegions);
|
BBC.NO_REGION.send(fp);
|
||||||
} else {
|
return;
|
||||||
finalQueue = SetQueue.IMP.getNewQueue(fp.getWorld(), true, false);
|
|
||||||
}
|
}
|
||||||
|
// TODO mask the regions bot / top to the bottom and top coord in the allowedRegions
|
||||||
|
// TODO: then mask the edit to the bot / top
|
||||||
|
// if (allowedRegions.length != 1 || !allowedRegions[0].isGlobal()) {
|
||||||
|
// finalQueue = new MaskedFaweQueue(SetQueue.IMP.getNewQueue(fp.getWorld(), true, false), allowedRegions);
|
||||||
|
// } else {
|
||||||
|
// finalQueue = SetQueue.IMP.getNewQueue(fp.getWorld(), true, false);
|
||||||
|
// }
|
||||||
database.getPotentialEdits(other, System.currentTimeMillis() - timeDiff, bot, top, new RunnableVal<DiskStorageHistory>() {
|
database.getPotentialEdits(other, System.currentTimeMillis() - timeDiff, bot, top, new RunnableVal<DiskStorageHistory>() {
|
||||||
@Override
|
@Override
|
||||||
public void run(DiskStorageHistory edit) {
|
public void run(DiskStorageHistory edit) {
|
||||||
edit.undo(fp);
|
edit.undo(fp, allowedRegions);
|
||||||
BBC.ROLLBACK_ELEMENT.send(player, Fawe.imp().getWorldName(edit.getWorld()) + "/" + user + "-" + edit.getIndex());
|
BBC.ROLLBACK_ELEMENT.send(player, Fawe.imp().getWorldName(edit.getWorld()) + "/" + user + "-" + edit.getIndex());
|
||||||
count.incrementAndGet();
|
count.incrementAndGet();
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,10 +92,16 @@ public class SchematicCommands {
|
||||||
this.worldEdit = worldEdit;
|
this.worldEdit = worldEdit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Command(aliases = { "loadall" }, usage = "[<format>] <filename|url>", desc = "Load multiple clipboards (paste will randomly choose one)")
|
@Command(
|
||||||
|
aliases = { "loadall" },
|
||||||
|
usage = "[<format>] <filename|url>",
|
||||||
|
help = "Load multiple clipboards\n" +
|
||||||
|
"The -r flag will apply random rotation",
|
||||||
|
desc = "Load multiple clipboards (paste will randomly choose one)"
|
||||||
|
)
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@CommandPermissions({ "worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.upload" })
|
@CommandPermissions({ "worldedit.clipboard.load", "worldedit.schematic.load", "worldedit.schematic.upload" })
|
||||||
public void loadall(final Player player, final LocalSession session, @Optional("schematic") final String formatName, final String filename) throws FilenameException {
|
public void loadall(final Player player, final LocalSession session, @Optional("schematic") final String formatName, final String filename, @Switch('r') boolean randomRotate) throws FilenameException {
|
||||||
final ClipboardFormat format = ClipboardFormat.findByAlias(formatName);
|
final ClipboardFormat format = ClipboardFormat.findByAlias(formatName);
|
||||||
if (format == null) {
|
if (format == null) {
|
||||||
BBC.CLIPBOARD_INVALID_FORMAT.send(player, formatName);
|
BBC.CLIPBOARD_INVALID_FORMAT.send(player, formatName);
|
||||||
|
@ -348,6 +354,7 @@ public class SchematicCommands {
|
||||||
}
|
}
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
switch (args.getString(i).toLowerCase()) {
|
switch (args.getString(i).toLowerCase()) {
|
||||||
|
case "me":
|
||||||
case "mine":
|
case "mine":
|
||||||
mine = true;
|
mine = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.sk89q.worldedit.extension.factory;
|
package com.sk89q.worldedit.extension.factory;
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
import com.boydti.fawe.command.FaweParser;
|
import com.boydti.fawe.command.FaweParser;
|
||||||
import com.boydti.fawe.command.SuggestInputParseException;
|
import com.boydti.fawe.command.SuggestInputParseException;
|
||||||
import com.boydti.fawe.object.pattern.BiomePattern;
|
import com.boydti.fawe.object.pattern.BiomePattern;
|
||||||
|
@ -30,6 +31,7 @@ import com.sk89q.worldedit.EmptyClipboardException;
|
||||||
import com.sk89q.worldedit.LocalSession;
|
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.blocks.BaseBlock;
|
||||||
import com.sk89q.worldedit.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||||
import com.sk89q.worldedit.extension.input.ParserContext;
|
import com.sk89q.worldedit.extension.input.ParserContext;
|
||||||
|
@ -53,6 +55,7 @@ import com.sk89q.worldedit.world.registry.BundledBlockData;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
|
||||||
public class HashTagPatternParser extends FaweParser<Pattern> {
|
public class HashTagPatternParser extends FaweParser<Pattern> {
|
||||||
|
|
||||||
|
@ -141,6 +144,16 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
|
||||||
throw new InputParseException("No session is available, so no clipboard is available");
|
throw new InputParseException("No session is available, so no clipboard is available");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case "#color": {
|
||||||
|
if (split2.length > 1) {
|
||||||
|
Color color = Color.web(split2[1]);
|
||||||
|
java.awt.Color awtColor = new java.awt.Color((float) color.getRed(), (float) color.getGreen(), (float) color.getBlue(), (float) color.getOpacity());
|
||||||
|
BaseBlock block = Fawe.get().getTextureUtil().getNearestBlock(awtColor.getRGB());
|
||||||
|
return new BlockPattern(block);
|
||||||
|
} else {
|
||||||
|
throw new InputParseException("#color:<hex>");
|
||||||
|
}
|
||||||
|
}
|
||||||
case "#fullcopy": {
|
case "#fullcopy": {
|
||||||
LocalSession session = context.requireSession();
|
LocalSession session = context.requireSession();
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
|
@ -148,12 +161,26 @@ public class HashTagPatternParser extends FaweParser<Pattern> {
|
||||||
if (split2.length > 1) {
|
if (split2.length > 1) {
|
||||||
String location = split2[1];
|
String location = split2[1];
|
||||||
try {
|
try {
|
||||||
ClipboardHolder[] clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(context.getActor(), context.requireWorld().getWorldData(), location, true);
|
ClipboardHolder[] clipboards;
|
||||||
|
switch (location.toLowerCase()) {
|
||||||
|
case "#copy":
|
||||||
|
case "#clipboard":
|
||||||
|
ClipboardHolder clipboard = session.getExistingClipboard();
|
||||||
|
if (clipboard == null) {
|
||||||
|
throw new InputParseException("To use #fullcopy, please first copy something to your clipboard");
|
||||||
|
}
|
||||||
|
clipboards = new ClipboardHolder[] {clipboard};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
clipboards = ClipboardFormat.SCHEMATIC.loadAllFromInput(context.getActor(), context.requireWorld().getWorldData(), location, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (clipboards == null) {
|
if (clipboards == null) {
|
||||||
throw new InputParseException("#fullcopy:<source>");
|
throw new InputParseException("#fullcopy:<source>");
|
||||||
}
|
}
|
||||||
boolean random = split2.length == 3 && split2[2].equalsIgnoreCase("true");
|
boolean randomRotate = split2.length >= 3 && split2[2].equalsIgnoreCase("true");
|
||||||
return new RandomFullClipboardPattern(Request.request().getExtent(), context.requireWorld().getWorldData(), clipboards, random);
|
boolean randomFlip = split2.length >= 4 && split2[3].equalsIgnoreCase("true");
|
||||||
|
return new RandomFullClipboardPattern(Request.request().getExtent(), context.requireWorld().getWorldData(), clipboards, randomRotate, randomFlip);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|
|
@ -509,7 +509,6 @@ public class PlatformManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -335,10 +335,16 @@ public enum ClipboardFormat {
|
||||||
}
|
}
|
||||||
File working = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
File working = worldEdit.getWorkingDirectoryFile(config.saveDir);
|
||||||
File dir = new File(working, (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? (player.getUniqueId().toString() + File.separator) : "") + input);
|
File dir = new File(working, (Settings.IMP.PATHS.PER_PLAYER_SCHEMATICS ? (player.getUniqueId().toString() + File.separator) : "") + input);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir = new File(dir + "." + getExtension());
|
||||||
|
}
|
||||||
if (!dir.exists()) {
|
if (!dir.exists()) {
|
||||||
if ((!input.contains("/") && !input.contains("\\")) || player.hasPermission("worldedit.schematic.load.other")) {
|
if ((!input.contains("/") && !input.contains("\\")) || player.hasPermission("worldedit.schematic.load.other")) {
|
||||||
dir = new File(worldEdit.getWorkingDirectoryFile(config.saveDir), input);
|
dir = new File(worldEdit.getWorkingDirectoryFile(config.saveDir), input);
|
||||||
}
|
}
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir = new File(dir + "." + getExtension());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!dir.exists()) {
|
if (!dir.exists()) {
|
||||||
if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input);
|
if (message) BBC.SCHEMATIC_NOT_FOUND.send(player, input);
|
||||||
|
|
|
@ -125,6 +125,16 @@ public class HeightMap {
|
||||||
return layers ? applyLayers(newData) : apply(newData);
|
return layers ? applyLayers(newData) : apply(newData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// public int averageFilter(int iterations) throws WorldEditException {
|
||||||
|
// Vector min = region.getMinimumPoint();
|
||||||
|
// Vector max = region.getMaximumPoint();
|
||||||
|
// int shift = layers ? 3 : 0;
|
||||||
|
// AverageHeightMapFilter filter = new AverageHeightMapFilter(data, width, height, min.getBlockY() << shift, max.getBlockY() << shift);
|
||||||
|
// int[] newData = filter.filter(iterations);
|
||||||
|
// return layers ? applyLayers(newData) : apply(newData);
|
||||||
|
// }
|
||||||
|
|
||||||
public int applyLayers(int[] data) throws WorldEditException {
|
public int applyLayers(int[] data) throws WorldEditException {
|
||||||
checkNotNull(data);
|
checkNotNull(data);
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
package com.sk89q.worldedit.world.registry;
|
package com.sk89q.worldedit.world.registry;
|
||||||
|
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
import com.google.common.io.Resources;
|
import com.google.common.io.Resources;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
@ -43,6 +44,7 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
@ -62,9 +64,9 @@ public class BundledBlockData {
|
||||||
private static final Logger log = Logger.getLogger(BundledBlockData.class.getCanonicalName());
|
private static final Logger log = Logger.getLogger(BundledBlockData.class.getCanonicalName());
|
||||||
private static final BundledBlockData INSTANCE = new BundledBlockData();
|
private static final BundledBlockData INSTANCE = new BundledBlockData();
|
||||||
|
|
||||||
private final Map<String, BlockEntry> idMap = new HashMap<String, BlockEntry>();
|
private final Map<String, BlockEntry> idMap = new ConcurrentHashMap<>();
|
||||||
private final Map<String, BaseBlock> stateMap = new HashMap<String, BaseBlock>();
|
public final Map<String, BaseBlock> stateMap = new ConcurrentHashMap<>();
|
||||||
private final Map<String, BlockEntry> localIdMap = new HashMap<String, BlockEntry>();
|
private final Map<String, BlockEntry> localIdMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final BlockEntry[] legacyMap = new BlockEntry[4096];
|
private final BlockEntry[] legacyMap = new BlockEntry[4096];
|
||||||
|
|
||||||
|
@ -102,6 +104,10 @@ public class BundledBlockData {
|
||||||
return localIdMap.keySet();
|
return localIdMap.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getStateNames() {
|
||||||
|
return stateMap.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
public List<String> getBlockNames(String partial) {
|
public List<String> getBlockNames(String partial) {
|
||||||
partial = partial.toLowerCase();
|
partial = partial.toLowerCase();
|
||||||
List<String> blocks = new ArrayList<>();
|
List<String> blocks = new ArrayList<>();
|
||||||
|
@ -142,19 +148,33 @@ public class BundledBlockData {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
idMap.put(entry.id, entry);
|
idMap.put(entry.id, entry);
|
||||||
String id = (entry.id.contains(":") ? entry.id.split(":")[1] : entry.id).toLowerCase().replace(" ", "_");
|
String modId, id;
|
||||||
localIdMap.putIfAbsent(id, entry);
|
if (entry.id.contains(":")) {
|
||||||
|
String[] split = entry.id.split(":");
|
||||||
|
id = split[1];
|
||||||
|
modId = split[0];
|
||||||
|
} else {
|
||||||
|
modId = "";
|
||||||
|
id = entry.id;
|
||||||
|
}
|
||||||
idMap.putIfAbsent(id, entry);
|
idMap.putIfAbsent(id, entry);
|
||||||
|
localIdMap.putIfAbsent(id, entry);
|
||||||
legacyMap[entry.legacyId] = entry;
|
legacyMap[entry.legacyId] = entry;
|
||||||
|
stateMap.putIfAbsent(id, FaweCache.getBlock(entry.legacyId, 0));
|
||||||
|
stateMap.putIfAbsent(entry.id, FaweCache.getBlock(entry.legacyId, 0));
|
||||||
if (entry.states == null) {
|
if (entry.states == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (Map.Entry<String, FaweState> stateEntry : entry.states.entrySet()) {
|
for (Map.Entry<String, FaweState> stateEntry : entry.states.entrySet()) {
|
||||||
for (Map.Entry<String, FaweStateValue> valueEntry : stateEntry.getValue().valueMap().entrySet()) {
|
for (Map.Entry<String, FaweStateValue> valueEntry : stateEntry.getValue().valueMap().entrySet()) {
|
||||||
String key = valueEntry.getKey();
|
String key = valueEntry.getKey();
|
||||||
if (!stateMap.containsKey(key)) {
|
if (key.equals("true")) {
|
||||||
stateMap.put(key, new BaseBlock(entry.legacyId, valueEntry.getValue().data));
|
key = stateEntry.getKey();
|
||||||
}
|
}
|
||||||
|
stateMap.putIfAbsent(id + ":" + key, FaweCache.getBlock(entry.legacyId, valueEntry.getValue().data));
|
||||||
|
stateMap.putIfAbsent(entry.id + ":" + key, FaweCache.getBlock(entry.legacyId, valueEntry.getValue().data));
|
||||||
|
stateMap.putIfAbsent(modId + ":" + key, FaweCache.getBlock(entry.legacyId, valueEntry.getValue().data));
|
||||||
|
stateMap.putIfAbsent(key, FaweCache.getBlock(entry.legacyId, valueEntry.getValue().data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FaweState half = entry.states.get("half");
|
FaweState half = entry.states.get("half");
|
||||||
|
@ -275,11 +295,22 @@ public class BundledBlockData {
|
||||||
@Nullable
|
@Nullable
|
||||||
public Integer toLegacyId(String id) {
|
public Integer toLegacyId(String id) {
|
||||||
BlockEntry entry = findById(id);
|
BlockEntry entry = findById(id);
|
||||||
if (entry != null) {
|
if (entry == null) {
|
||||||
return entry.legacyId;
|
entry = localIdMap.get(id);
|
||||||
} else {
|
if (entry == null) {
|
||||||
return null;
|
int index = id.lastIndexOf('_');
|
||||||
|
if (index == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String data = id.substring(index + 1, id.length());
|
||||||
|
id = id.substring(0, index);
|
||||||
|
entry = localIdMap.get(id + ":" + data);
|
||||||
|
if (entry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return entry.legacyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
// Add blocks here if you need block names and rotation to work
|
// Add blocks here if you need block names, rotation and textures to work
|
||||||
// See: https://github.com/sk89q/WorldEdit/blob/master/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json
|
// The following blocks are already bundled with FAWE: https://github.com/sk89q/WorldEdit/blob/master/worldedit-core/src/main/resources/com/sk89q/worldedit/world/registry/blocks.json
|
||||||
// - WorldEdit only uses the id/names + rotation/facing properties.
|
// To generating the blocks from forge mods see:
|
||||||
|
// - https://github.com/wizjany/ForgeUtils
|
||||||
|
//
|
||||||
|
// Help with ForgeUtils: wizjany @ http://webchat.esper.net/?nick=&channels=sk89q
|
||||||
[
|
[
|
||||||
|
|
||||||
]
|
]
|
Loading…
Reference in New Issue