Update to 1.10
This commit is contained in:
parent
a43cef7b2d
commit
40c6e781a6
32
bukkit110/build.gradle
Normal file
32
bukkit110/build.gradle
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
dependencies {
|
||||||
|
compile project(':bukkit0')
|
||||||
|
compile 'org.bukkit.craftbukkitv1_10:craftbukkitv1_10:1.10'
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
from('src/main/resources') {
|
||||||
|
include 'plugin.yml'
|
||||||
|
expand(
|
||||||
|
name: project.parent.name,
|
||||||
|
version: project.parent.version
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply plugin: 'com.github.johnrengelman.shadow'
|
||||||
|
// We only want the shadow jar produced
|
||||||
|
jar.enabled = false
|
||||||
|
shadowJar {
|
||||||
|
dependencies {
|
||||||
|
include(dependency(':bukkit0'))
|
||||||
|
include(dependency(':core'))
|
||||||
|
}
|
||||||
|
archiveName = "${parent.name}-${project.name}-${parent.version}.jar"
|
||||||
|
destinationDir = file '../target'
|
||||||
|
}
|
||||||
|
shadowJar.doLast {
|
||||||
|
task ->
|
||||||
|
ant.checksum file: task.archivePath
|
||||||
|
}
|
||||||
|
|
||||||
|
build.dependsOn(shadowJar);
|
@ -0,0 +1,128 @@
|
|||||||
|
package com.boydti.fawe.bukkit.v1_10;
|
||||||
|
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.example.CharFaweChunk;
|
||||||
|
import com.boydti.fawe.object.FaweQueue;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import net.minecraft.server.v1_10_R1.Block;
|
||||||
|
import net.minecraft.server.v1_10_R1.DataBits;
|
||||||
|
import net.minecraft.server.v1_10_R1.DataPalette;
|
||||||
|
import net.minecraft.server.v1_10_R1.DataPaletteBlock;
|
||||||
|
import net.minecraft.server.v1_10_R1.DataPaletteGlobal;
|
||||||
|
import net.minecraft.server.v1_10_R1.IBlockData;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
|
||||||
|
public class BukkitChunk_1_10 extends CharFaweChunk<Chunk> {
|
||||||
|
|
||||||
|
public DataPaletteBlock[] sectionPalettes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
|
||||||
|
*
|
||||||
|
* @param parent
|
||||||
|
* @param x
|
||||||
|
* @param z
|
||||||
|
*/
|
||||||
|
public BukkitChunk_1_10(FaweQueue parent, int x, int z) {
|
||||||
|
super(parent, x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Chunk getNewChunk() {
|
||||||
|
return ((com.boydti.fawe.bukkit.v1_10.BukkitQueue_1_10) getParent()).getWorld().getChunkAt(getX(), getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharFaweChunk<Chunk> copy(boolean shallow) {
|
||||||
|
BukkitChunk_1_10 value = (BukkitChunk_1_10) super.copy(shallow);
|
||||||
|
if (sectionPalettes != null) {
|
||||||
|
value.sectionPalettes = new DataPaletteBlock[16];
|
||||||
|
try {
|
||||||
|
Field fieldBits = DataPaletteBlock.class.getDeclaredField("b");
|
||||||
|
fieldBits.setAccessible(true);
|
||||||
|
Field fieldPalette = DataPaletteBlock.class.getDeclaredField("c");
|
||||||
|
fieldPalette.setAccessible(true);
|
||||||
|
Field fieldSize = DataPaletteBlock.class.getDeclaredField("e");
|
||||||
|
fieldSize.setAccessible(true);
|
||||||
|
for (int i = 0; i < sectionPalettes.length; i++) {
|
||||||
|
DataPaletteBlock current = sectionPalettes[i];
|
||||||
|
if (current == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Clone palette
|
||||||
|
DataPalette currentPalette = (DataPalette) fieldPalette.get(current);
|
||||||
|
if (!(currentPalette instanceof DataPaletteGlobal)) {
|
||||||
|
current.a(128, null);
|
||||||
|
}
|
||||||
|
DataPaletteBlock paletteBlock = newDataPaletteBlock();
|
||||||
|
currentPalette = (DataPalette) fieldPalette.get(current);
|
||||||
|
if (!(currentPalette instanceof DataPaletteGlobal)) {
|
||||||
|
throw new RuntimeException("Palette must be global!");
|
||||||
|
}
|
||||||
|
fieldPalette.set(paletteBlock, currentPalette);
|
||||||
|
// Clone size
|
||||||
|
fieldSize.set(paletteBlock, fieldSize.get(current));
|
||||||
|
// Clone palette
|
||||||
|
DataBits currentBits = (DataBits) fieldBits.get(current);
|
||||||
|
DataBits newBits = new DataBits(1, 0);
|
||||||
|
for (Field field : DataBits.class.getDeclaredFields()) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object currentValue = field.get(currentBits);
|
||||||
|
if (currentValue instanceof long[]) {
|
||||||
|
currentValue = ((long[]) currentValue).clone();
|
||||||
|
}
|
||||||
|
field.set(newBits, currentValue);
|
||||||
|
}
|
||||||
|
fieldBits.set(paletteBlock, newBits);
|
||||||
|
value.sectionPalettes[i] = paletteBlock;
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataPaletteBlock newDataPaletteBlock() {
|
||||||
|
try {
|
||||||
|
return new DataPaletteBlock();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
try {
|
||||||
|
Constructor<DataPaletteBlock> constructor = DataPaletteBlock.class.getDeclaredConstructor(IBlockData[].class);
|
||||||
|
return constructor.newInstance((Object) null);
|
||||||
|
} catch (Throwable e2) {
|
||||||
|
throw new RuntimeException(e2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void optimize() {
|
||||||
|
if (sectionPalettes != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
char[][] arrays = getCombinedIdArrays();
|
||||||
|
IBlockData lastBlock = null;
|
||||||
|
char lastChar = Character.MAX_VALUE;
|
||||||
|
for (int layer = 0; layer < 16; layer++) {
|
||||||
|
if (getCount(layer) > 0) {
|
||||||
|
if (sectionPalettes == null) {
|
||||||
|
sectionPalettes = new DataPaletteBlock[16];
|
||||||
|
}
|
||||||
|
DataPaletteBlock palette = newDataPaletteBlock();
|
||||||
|
char[] blocks = getIdArray(layer);
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
char combinedId = blocks[FaweCache.CACHE_J[y][x][z]];
|
||||||
|
if (combinedId > 1) {
|
||||||
|
palette.setBlock(x, y, z, Block.getById(combinedId >> 4).fromLegacyData(combinedId & 0xF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.boydti.fawe.bukkit.v1_10;
|
||||||
|
|
||||||
|
import com.boydti.fawe.bukkit.ABukkitMain;
|
||||||
|
import com.boydti.fawe.bukkit.v0.BukkitEditSessionWrapper_0;
|
||||||
|
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
||||||
|
import com.boydti.fawe.object.EditSessionWrapper;
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
|
||||||
|
public class BukkitMain_110 extends ABukkitMain {
|
||||||
|
@Override
|
||||||
|
public BukkitQueue_0 getQueue(String world) {
|
||||||
|
return new com.boydti.fawe.bukkit.v1_10.BukkitQueue_1_10(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EditSessionWrapper getEditSessionWrapper(EditSession session) {
|
||||||
|
return new BukkitEditSessionWrapper_0(session);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,747 @@
|
|||||||
|
package com.boydti.fawe.bukkit.v1_10;
|
||||||
|
|
||||||
|
import com.boydti.fawe.Fawe;
|
||||||
|
import com.boydti.fawe.FaweCache;
|
||||||
|
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
|
||||||
|
import com.boydti.fawe.example.CharFaweChunk;
|
||||||
|
import com.boydti.fawe.object.BytePair;
|
||||||
|
import com.boydti.fawe.object.FaweChunk;
|
||||||
|
import com.boydti.fawe.object.PseudoRandom;
|
||||||
|
import com.boydti.fawe.object.RunnableVal;
|
||||||
|
import com.boydti.fawe.util.MainUtil;
|
||||||
|
import com.boydti.fawe.util.MathMan;
|
||||||
|
import com.boydti.fawe.util.ReflectionUtils;
|
||||||
|
import com.boydti.fawe.util.TaskManager;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.jnbt.ListTag;
|
||||||
|
import com.sk89q.jnbt.LongTag;
|
||||||
|
import com.sk89q.jnbt.StringTag;
|
||||||
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.internal.Constants;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.minecraft.server.v1_10_R1.Block;
|
||||||
|
import net.minecraft.server.v1_10_R1.BlockPosition;
|
||||||
|
import net.minecraft.server.v1_10_R1.Blocks;
|
||||||
|
import net.minecraft.server.v1_10_R1.ChunkCoordIntPair;
|
||||||
|
import net.minecraft.server.v1_10_R1.ChunkSection;
|
||||||
|
import net.minecraft.server.v1_10_R1.DataBits;
|
||||||
|
import net.minecraft.server.v1_10_R1.DataPalette;
|
||||||
|
import net.minecraft.server.v1_10_R1.DataPaletteBlock;
|
||||||
|
import net.minecraft.server.v1_10_R1.Entity;
|
||||||
|
import net.minecraft.server.v1_10_R1.EntityHuman;
|
||||||
|
import net.minecraft.server.v1_10_R1.EntityPlayer;
|
||||||
|
import net.minecraft.server.v1_10_R1.EntityTracker;
|
||||||
|
import net.minecraft.server.v1_10_R1.EntityTrackerEntry;
|
||||||
|
import net.minecraft.server.v1_10_R1.EntityTypes;
|
||||||
|
import net.minecraft.server.v1_10_R1.IBlockData;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagCompound;
|
||||||
|
import net.minecraft.server.v1_10_R1.NibbleArray;
|
||||||
|
import net.minecraft.server.v1_10_R1.PacketPlayOutEntityDestroy;
|
||||||
|
import net.minecraft.server.v1_10_R1.PacketPlayOutMapChunk;
|
||||||
|
import net.minecraft.server.v1_10_R1.PlayerChunk;
|
||||||
|
import net.minecraft.server.v1_10_R1.PlayerChunkMap;
|
||||||
|
import net.minecraft.server.v1_10_R1.TileEntity;
|
||||||
|
import net.minecraft.server.v1_10_R1.WorldServer;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.World.Environment;
|
||||||
|
import org.bukkit.block.Biome;
|
||||||
|
import org.bukkit.craftbukkit.v1_10_R1.CraftChunk;
|
||||||
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
|
||||||
|
public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], DataPaletteBlock> {
|
||||||
|
|
||||||
|
private IBlockData air;
|
||||||
|
|
||||||
|
public BukkitQueue_1_10(final String world) {
|
||||||
|
super(world);
|
||||||
|
checkVersion("v1_10_R1");
|
||||||
|
try {
|
||||||
|
Field fieldAir = DataPaletteBlock.class.getDeclaredField("a");
|
||||||
|
fieldAir.setAccessible(true);
|
||||||
|
air = (IBlockData) fieldAir.get(null);
|
||||||
|
if (adapter == null) {
|
||||||
|
setupAdapter(new com.boydti.fawe.bukkit.v1_10.FaweAdapter_1_10());
|
||||||
|
Fawe.debug("Using adapter: " + adapter);
|
||||||
|
Fawe.debug("=========================================");
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChunkSection[] getCachedSections(World world, int cx, int cz) {
|
||||||
|
CraftChunk chunk = (CraftChunk) world.getChunkAt(cx, cz);
|
||||||
|
return chunk.getHandle().getSections();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataPaletteBlock getCachedSection(ChunkSection[] chunkSections, int cy) {
|
||||||
|
ChunkSection nibble = chunkSections[cy];
|
||||||
|
return nibble != null ? nibble.getBlocks() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCombinedId4Data(DataPaletteBlock lastSection, int x, int y, int z) {
|
||||||
|
IBlockData ibd = lastSection.a(x & 15, y & 15, z & 15);
|
||||||
|
Block block = ibd.getBlock();
|
||||||
|
int id = Block.getId(block);
|
||||||
|
if (FaweCache.hasData(id)) {
|
||||||
|
return (id << 4) + block.toLegacyData(ibd);
|
||||||
|
} else {
|
||||||
|
return id << 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void refreshChunk(World world, Chunk chunk) {
|
||||||
|
if (!chunk.isLoaded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
net.minecraft.server.v1_10_R1.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
|
||||||
|
ChunkCoordIntPair pos = nmsChunk.k(); // getPosition()
|
||||||
|
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
||||||
|
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
||||||
|
PlayerChunk playerChunk = chunkMap.getChunk(pos.x, pos.z);
|
||||||
|
if (playerChunk == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HashSet<EntityPlayer> set = new HashSet<EntityPlayer>(playerChunk.c);
|
||||||
|
EntityTracker tracker = w.getTracker();
|
||||||
|
// Get players
|
||||||
|
HashSet<EntityPlayer> players = new HashSet<>();
|
||||||
|
for (EntityHuman human : w.players) {
|
||||||
|
if (set.contains(human)) {
|
||||||
|
players.add((EntityPlayer) human);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (players.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
||||||
|
List<Entity>[] entitieSlices = playerChunk.chunk.getEntitySlices();
|
||||||
|
for (List<Entity> slice : entitieSlices) {
|
||||||
|
if (slice == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Entity ent : slice) {
|
||||||
|
EntityTrackerEntry entry = tracker.trackedEntities.get(ent.getId());
|
||||||
|
if (entry == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
entities.add(entry);
|
||||||
|
PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(ent.getId());
|
||||||
|
for (EntityPlayer player : players) {
|
||||||
|
player.playerConnection.sendPacket(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (EntityPlayer player : players) {
|
||||||
|
player.playerConnection.networkManager.a();
|
||||||
|
}
|
||||||
|
// Send chunks
|
||||||
|
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(playerChunk.chunk, 65535);
|
||||||
|
for (EntityPlayer player : players) {
|
||||||
|
player.playerConnection.sendPacket(packet);
|
||||||
|
}
|
||||||
|
// send ents
|
||||||
|
for (List<Entity> slice : entitieSlices) {
|
||||||
|
if (slice == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Entity ent : slice) {
|
||||||
|
EntityTrackerEntry entry = tracker.trackedEntities.get(ent.getId());
|
||||||
|
if (entry == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
TaskManager.IMP.later(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (EntityPlayer player : players) {
|
||||||
|
boolean result = entry.trackedPlayers.remove(player);
|
||||||
|
if (result && ent != player) {
|
||||||
|
entry.updatePlayer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 2);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean fixLighting(final FaweChunk pc, RelightMode mode) {
|
||||||
|
if (mode == RelightMode.NONE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
CharFaweChunk bc = (CharFaweChunk) pc;
|
||||||
|
Chunk chunk = (Chunk) bc.getChunk();
|
||||||
|
if (!chunk.isLoaded()) {
|
||||||
|
if (Fawe.get().getMainThread() != Thread.currentThread()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
chunk.load(false);
|
||||||
|
}
|
||||||
|
net.minecraft.server.v1_10_R1.Chunk c = ((CraftChunk) chunk).getHandle();
|
||||||
|
final boolean flag = chunk.getWorld().getEnvironment() == Environment.NORMAL;
|
||||||
|
ChunkSection[] sections = c.getSections();
|
||||||
|
if (mode == RelightMode.ALL) {
|
||||||
|
for (int i = 0; i < sections.length; i++) {
|
||||||
|
ChunkSection section = sections[i];
|
||||||
|
if (section != null) {
|
||||||
|
section.a(new NibbleArray());
|
||||||
|
if (flag) {
|
||||||
|
section.b(new NibbleArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flag) {
|
||||||
|
if (mode == RelightMode.ALL) {
|
||||||
|
c.initLighting();
|
||||||
|
} else {
|
||||||
|
int i = c.g();
|
||||||
|
for (int x = 0; x < 16; ++x) {
|
||||||
|
for (int z = 0; z < 16; ++z) {
|
||||||
|
int l = 15;
|
||||||
|
int y = i + 16 - 1;
|
||||||
|
do {
|
||||||
|
int opacity = c.a(x, y, z).c();
|
||||||
|
if (opacity == 0 && l != 15) {
|
||||||
|
opacity = 1;
|
||||||
|
}
|
||||||
|
l -= opacity;
|
||||||
|
if (l > 0) {
|
||||||
|
ChunkSection section = sections[y >> 4];
|
||||||
|
if (section != null) {
|
||||||
|
section.a(x, y & 15, z, l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--y;
|
||||||
|
} while (y > 0 && l > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (((bc.getTotalRelight() == 0) && mode == RelightMode.MINIMAL)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (mode == RelightMode.ALL) {
|
||||||
|
bc = getPrevious(bc, c.getSections(), null, null, null, true);
|
||||||
|
}
|
||||||
|
int total = bc.getTotalCount();
|
||||||
|
net.minecraft.server.v1_10_R1.World w = c.world;
|
||||||
|
final int X = chunk.getX() << 4;
|
||||||
|
final int Z = chunk.getZ() << 4;
|
||||||
|
for (int j = sections.length - 1; j >= 0; j--) {
|
||||||
|
final Object section = sections[j];
|
||||||
|
if (section == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (((bc.getRelight(j) == 0) && mode == RelightMode.MINIMAL) || (bc.getCount(j) == 0 && mode != RelightMode.ALL) || ((bc.getCount(j) >= 4096) && (bc.getAir(j) == 0)) || bc.getAir(j) == 4096) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final char[] array = bc.getIdArray(j);
|
||||||
|
if (array == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (mode == RelightMode.ALL) {
|
||||||
|
for (int k = array.length - 1; k >= 0; k--) {
|
||||||
|
final int x = FaweCache.CACHE_X[j][k];
|
||||||
|
final int y = FaweCache.CACHE_Y[j][k];
|
||||||
|
final int z = FaweCache.CACHE_Z[j][k];
|
||||||
|
if (this.isSurrounded(bc.getCombinedIdArrays(), x, y, z)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pos.c(X + x, y, Z + z);
|
||||||
|
w.w(pos);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int k = array.length - 1; k >= 0; k--) {
|
||||||
|
final int i = array[k];
|
||||||
|
final short id = (short) (i >> 4);
|
||||||
|
switch (id) { // Lighting
|
||||||
|
case 0:
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
if (mode == RelightMode.MINIMAL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (PseudoRandom.random.random(3) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case 10:
|
||||||
|
case 11:
|
||||||
|
case 39:
|
||||||
|
case 40:
|
||||||
|
case 50:
|
||||||
|
case 51:
|
||||||
|
case 62:
|
||||||
|
case 74:
|
||||||
|
case 76:
|
||||||
|
case 89:
|
||||||
|
case 122:
|
||||||
|
case 124:
|
||||||
|
case 130:
|
||||||
|
case 138:
|
||||||
|
case 169:
|
||||||
|
final int x = FaweCache.CACHE_X[j][k];
|
||||||
|
final int y = FaweCache.CACHE_Y[j][k];
|
||||||
|
final int z = FaweCache.CACHE_Z[j][k];
|
||||||
|
if (this.isSurrounded(bc.getCombinedIdArrays(), x, y, z)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pos.c(X + x, y, Z + z);
|
||||||
|
w.w(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Throwable e) {
|
||||||
|
if (Thread.currentThread() == Fawe.get().getMainThread()) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSurrounded(final char[][] sections, final int x, final int y, final int z) {
|
||||||
|
return this.isSolid(this.getId(sections, x, y + 1, z))
|
||||||
|
&& this.isSolid(this.getId(sections, x + 1, y - 1, z))
|
||||||
|
&& this.isSolid(this.getId(sections, x - 1, y, z))
|
||||||
|
&& this.isSolid(this.getId(sections, x, y, z + 1))
|
||||||
|
&& this.isSolid(this.getId(sections, x, y, z - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSolid(final int i) {
|
||||||
|
if (i != 0) {
|
||||||
|
final Material material = Material.getMaterial(i);
|
||||||
|
return (material != null) && Material.getMaterial(i).isOccluding();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId(final char[][] sections, final int x, final int y, final int z) {
|
||||||
|
if ((x < 0) || (x > 15) || (z < 0) || (z > 15)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ((y < 0) || (y > 255)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
final int i = FaweCache.CACHE_I[y][x][z];
|
||||||
|
final char[] section = sections[i];
|
||||||
|
if (section == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
final int j = FaweCache.CACHE_J[y][x][z];
|
||||||
|
return section[j] >> 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ChunkSection section) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
Class<? extends ChunkSection> clazz = section.getClass();
|
||||||
|
Field fieldTickingBlockCount = clazz.getDeclaredField("tickingBlockCount");
|
||||||
|
Field fieldNonEmptyBlockCount = clazz.getDeclaredField("nonEmptyBlockCount");
|
||||||
|
fieldTickingBlockCount.setAccessible(true);
|
||||||
|
fieldNonEmptyBlockCount.setAccessible(true);
|
||||||
|
fieldTickingBlockCount.set(section, tickingBlockCount);
|
||||||
|
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPalette(ChunkSection section, DataPaletteBlock palette) throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
Field fieldSection = ChunkSection.class.getDeclaredField("blockIds");
|
||||||
|
fieldSection.setAccessible(true);
|
||||||
|
fieldSection.set(section, palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChunkSection newChunkSection(int y2, boolean flag, char[] array) {
|
||||||
|
try {
|
||||||
|
if (array == null) {
|
||||||
|
return new ChunkSection(y2, flag);
|
||||||
|
} else {
|
||||||
|
return new ChunkSection(y2, flag, array);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
try {
|
||||||
|
if (array == null) {
|
||||||
|
Constructor<ChunkSection> constructor = ChunkSection.class.getDeclaredConstructor(int.class, boolean.class, IBlockData[].class);
|
||||||
|
return constructor.newInstance(y2, flag, (IBlockData[]) null);
|
||||||
|
} else {
|
||||||
|
Constructor<ChunkSection> constructor = ChunkSection.class.getDeclaredConstructor(int.class, boolean.class, char[].class, IBlockData[].class);
|
||||||
|
return constructor.newInstance(y2, flag, array, (IBlockData[]) null);
|
||||||
|
}
|
||||||
|
} catch (Throwable e2) {
|
||||||
|
throw new RuntimeException(e2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharFaweChunk getPrevious(CharFaweChunk fs, ChunkSection[] sections, Map<?, ?> tilesGeneric, Collection<?>[] entitiesGeneric, Set<UUID> createdEntities, boolean all) throws Exception {
|
||||||
|
Map<BlockPosition, TileEntity> tiles = (Map<BlockPosition, TileEntity>) tilesGeneric;
|
||||||
|
Collection<Entity>[] entities = (Collection<Entity>[]) entitiesGeneric;
|
||||||
|
CharFaweChunk previous = (CharFaweChunk) getFaweChunk(fs.getX(), fs.getZ());
|
||||||
|
// Copy blocks
|
||||||
|
char[][] idPrevious = new char[16][];
|
||||||
|
for (int layer = 0; layer < sections.length; layer++) {
|
||||||
|
if (fs.getCount(layer) != 0 || all) {
|
||||||
|
ChunkSection section = sections[layer];
|
||||||
|
if (section != null) {
|
||||||
|
short solid = 0;
|
||||||
|
char[] previousLayer = idPrevious[layer] = new char[4096];
|
||||||
|
DataPaletteBlock blocks = section.getBlocks();
|
||||||
|
for (int j = 0; j < 4096; j++) {
|
||||||
|
int x = FaweCache.CACHE_X[0][j];
|
||||||
|
int y = FaweCache.CACHE_Y[0][j];
|
||||||
|
int z = FaweCache.CACHE_Z[0][j];
|
||||||
|
IBlockData ibd = blocks.a(x, y, z);
|
||||||
|
Block block = ibd.getBlock();
|
||||||
|
int combined = Block.getId(block);
|
||||||
|
if (FaweCache.hasData(combined)) {
|
||||||
|
combined = (combined << 4) + block.toLegacyData(ibd);
|
||||||
|
} else {
|
||||||
|
combined = combined << 4;
|
||||||
|
}
|
||||||
|
if (combined > 1) {
|
||||||
|
solid++;
|
||||||
|
}
|
||||||
|
previousLayer[j] = (char) combined;
|
||||||
|
}
|
||||||
|
previous.count[layer] = solid;
|
||||||
|
previous.air[layer] = (short) (4096 - solid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previous.ids = idPrevious;
|
||||||
|
// Copy tiles
|
||||||
|
if (tiles != null) {
|
||||||
|
for (Map.Entry<BlockPosition, TileEntity> entry : tiles.entrySet()) {
|
||||||
|
TileEntity tile = entry.getValue();
|
||||||
|
NBTTagCompound tag = new NBTTagCompound();
|
||||||
|
BlockPosition pos = entry.getKey();
|
||||||
|
CompoundTag nativeTag = getTag(tile);
|
||||||
|
previous.setTile(pos.getX() & 15, pos.getY(), pos.getZ() & 15, nativeTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Copy entities
|
||||||
|
if (entities != null) {
|
||||||
|
for (Collection<Entity> entityList : entities) {
|
||||||
|
for (Entity ent : entityList) {
|
||||||
|
if (ent instanceof EntityPlayer || (!createdEntities.isEmpty() && createdEntities.contains(ent.getUniqueID()))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int x = ((int) Math.round(ent.locX) & 15);
|
||||||
|
int z = ((int) Math.round(ent.locZ) & 15);
|
||||||
|
int y = (int) Math.round(ent.locY);
|
||||||
|
int i = FaweCache.CACHE_I[y][x][z];
|
||||||
|
char[] array = fs.getIdArray(i);
|
||||||
|
if (array == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int j = FaweCache.CACHE_J[y][x][z];
|
||||||
|
if (array[j] != 0) {
|
||||||
|
String id = EntityTypes.b(ent);
|
||||||
|
if (id != null) {
|
||||||
|
NBTTagCompound tag = new NBTTagCompound();
|
||||||
|
ent.e(tag); // readEntityIntoTag
|
||||||
|
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(adapter, tag);
|
||||||
|
Map<String, Tag> map = ReflectionUtils.getMap(nativeTag.getValue());
|
||||||
|
map.put("Id", new StringTag(id));
|
||||||
|
previous.setEntity(nativeTag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BlockPosition.MutableBlockPosition pos = new BlockPosition.MutableBlockPosition(0, 0, 0);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag getTileEntity(Chunk chunk, int x, int y, int z) {
|
||||||
|
Map<BlockPosition, TileEntity> tiles = ((CraftChunk) chunk).getHandle().getTileEntities();
|
||||||
|
pos.c(x, y, z);
|
||||||
|
TileEntity tile = tiles.get(pos);
|
||||||
|
return tile != null ? getTag(tile) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompoundTag getTag(TileEntity tile) {
|
||||||
|
try {
|
||||||
|
NBTTagCompound tag = new NBTTagCompound();
|
||||||
|
tile.save(tag); // readTagIntoEntity
|
||||||
|
return (CompoundTag) methodToNative.invoke(adapter, tag);
|
||||||
|
} catch (Exception e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Chunk getChunk(World world, int x, int z) {
|
||||||
|
return world.getChunkAt(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setComponents(final FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
|
||||||
|
final com.boydti.fawe.bukkit.v1_10.BukkitChunk_1_10 fs = (com.boydti.fawe.bukkit.v1_10.BukkitChunk_1_10) fc;
|
||||||
|
final Chunk chunk = (Chunk) fs.getChunk();
|
||||||
|
final World world = chunk.getWorld();
|
||||||
|
chunk.load(true);
|
||||||
|
try {
|
||||||
|
final boolean flag = world.getEnvironment() == Environment.NORMAL;
|
||||||
|
net.minecraft.server.v1_10_R1.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
|
||||||
|
net.minecraft.server.v1_10_R1.World nmsWorld = nmsChunk.world;
|
||||||
|
ChunkSection[] sections = nmsChunk.getSections();
|
||||||
|
Class<? extends net.minecraft.server.v1_10_R1.Chunk> clazzChunk = nmsChunk.getClass();
|
||||||
|
final Field ef = clazzChunk.getDeclaredField("entitySlices");
|
||||||
|
final Collection<Entity>[] entities = (Collection<Entity>[]) ef.get(nmsChunk);
|
||||||
|
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
|
||||||
|
// Remove entities
|
||||||
|
for (int i = 0; i < entities.length; i++) {
|
||||||
|
int count = fs.getCount(i);
|
||||||
|
if (count == 0) {
|
||||||
|
continue;
|
||||||
|
} else if (count >= 4096) {
|
||||||
|
entities[i].clear();
|
||||||
|
} else {
|
||||||
|
char[] array = fs.getIdArray(i);
|
||||||
|
Collection<Entity> ents = new ArrayList<>(entities[i]);
|
||||||
|
for (Entity entity : ents) {
|
||||||
|
if (entity instanceof EntityPlayer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int x = ((int) Math.round(entity.locX) & 15);
|
||||||
|
int z = ((int) Math.round(entity.locZ) & 15);
|
||||||
|
int y = (int) Math.round(entity.locY);
|
||||||
|
if (array == null || y < 0 || y > 255) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][x][z]] != 0) {
|
||||||
|
nmsWorld.removeEntity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HashSet<UUID> entsToRemove = fs.getEntityRemoves();
|
||||||
|
if (entsToRemove.size() > 0) {
|
||||||
|
for (int i = 0; i < entities.length; i++) {
|
||||||
|
Collection<Entity> ents = new ArrayList<>(entities[i]);
|
||||||
|
for (Entity entity : ents) {
|
||||||
|
if (entsToRemove.contains(entity.getUniqueID())) {
|
||||||
|
nmsWorld.removeEntity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set entities
|
||||||
|
Set<UUID> createdEntities = new HashSet<>();
|
||||||
|
Set<CompoundTag> entitiesToSpawn = fs.getEntities();
|
||||||
|
for (CompoundTag nativeTag : entitiesToSpawn) {
|
||||||
|
Map<String, Tag> entityTagMap = ReflectionUtils.getMap(nativeTag.getValue());
|
||||||
|
StringTag idTag = (StringTag) entityTagMap.get("Id");
|
||||||
|
ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
||||||
|
ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
||||||
|
if (idTag == null || posTag == null || rotTag == null) {
|
||||||
|
Fawe.debug("Unknown entity tag: " + nativeTag);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double x = posTag.getDouble(0);
|
||||||
|
double y = posTag.getDouble(1);
|
||||||
|
double z = posTag.getDouble(2);
|
||||||
|
float yaw = rotTag.getFloat(0);
|
||||||
|
float pitch = rotTag.getFloat(1);
|
||||||
|
String id = idTag.getValue();
|
||||||
|
Entity entity = EntityTypes.createEntityByName(id, nmsWorld);
|
||||||
|
if (entity != null) {
|
||||||
|
UUID uuid = entity.getUniqueID();
|
||||||
|
entityTagMap.put("UUIDMost", new LongTag(uuid.getMostSignificantBits()));
|
||||||
|
entityTagMap.put("UUIDLeast", new LongTag(uuid.getLeastSignificantBits()));
|
||||||
|
if (nativeTag != null) {
|
||||||
|
NBTTagCompound tag = (NBTTagCompound) methodFromNative.invoke(adapter, nativeTag);
|
||||||
|
for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||||
|
tag.remove(name);
|
||||||
|
}
|
||||||
|
entity.f(tag);
|
||||||
|
}
|
||||||
|
entity.setLocation(x, y, z, yaw, pitch);
|
||||||
|
nmsWorld.addEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||||
|
createdEntities.add(entity.getUniqueID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Change task?
|
||||||
|
if (changeTask != null) {
|
||||||
|
CharFaweChunk previous = getPrevious(fs, sections, tiles, entities, createdEntities, false);
|
||||||
|
changeTask.run(previous);
|
||||||
|
}
|
||||||
|
// Trim tiles
|
||||||
|
Set<Entry<BlockPosition, TileEntity>> entryset = tiles.entrySet();
|
||||||
|
Iterator<Map.Entry<BlockPosition, TileEntity>> iterator = entryset.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Map.Entry<BlockPosition, TileEntity> tile = iterator.next();
|
||||||
|
BlockPosition pos = tile.getKey();
|
||||||
|
int lx = pos.getX() & 15;
|
||||||
|
int ly = pos.getY();
|
||||||
|
int lz = pos.getZ() & 15;
|
||||||
|
int j = FaweCache.CACHE_I[ly][lx][lz];
|
||||||
|
char[] array = fs.getIdArray(j);
|
||||||
|
if (array == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int k = FaweCache.CACHE_J[ly][lx][lz];
|
||||||
|
if (array[k] != 0) {
|
||||||
|
tile.getValue().invalidateBlockCache();
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set blocks
|
||||||
|
for (int j = 0; j < sections.length; j++) {
|
||||||
|
int count = fs.getCount(j);
|
||||||
|
if (count == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final char[] array = fs.getIdArray(j);
|
||||||
|
if (array == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ChunkSection section = sections[j];
|
||||||
|
if (section == null) {
|
||||||
|
if (fs.sectionPalettes != null && fs.sectionPalettes[j] != null) {
|
||||||
|
section = sections[j] = newChunkSection(j << 4, flag, null);
|
||||||
|
setPalette(section, fs.sectionPalettes[j]);
|
||||||
|
setCount(0, count - fs.getAir(j), section);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
sections[j] = newChunkSection(j << 4, flag, array);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (count >= 4096) {
|
||||||
|
if (fs.sectionPalettes != null && fs.sectionPalettes[j] != null) {
|
||||||
|
setPalette(section, fs.sectionPalettes[j]);
|
||||||
|
setCount(0, count - fs.getAir(j), section);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
sections[j] = newChunkSection(j << 4, flag, array);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DataPaletteBlock nibble = section.getBlocks();
|
||||||
|
Field fieldBits = nibble.getClass().getDeclaredField("b");
|
||||||
|
fieldBits.setAccessible(true);
|
||||||
|
DataBits bits = (DataBits) fieldBits.get(nibble);
|
||||||
|
|
||||||
|
Field fieldPalette = nibble.getClass().getDeclaredField("c");
|
||||||
|
fieldPalette.setAccessible(true);
|
||||||
|
DataPalette palette = (DataPalette) fieldPalette.get(nibble);
|
||||||
|
int nonEmptyBlockCount = 0;
|
||||||
|
for (int y = 0; y < 16; y++) {
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
char combinedId = array[FaweCache.CACHE_J[y][x][z]];
|
||||||
|
switch (combinedId) {
|
||||||
|
case 0:
|
||||||
|
IBlockData existing = nibble.a(x, y, z);
|
||||||
|
if (existing != air) {
|
||||||
|
nonEmptyBlockCount++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case 1:
|
||||||
|
nibble.setBlock(x, y, z, Blocks.AIR.getBlockData());
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
nonEmptyBlockCount++;
|
||||||
|
nibble.setBlock(x, y, z, Block.getById(combinedId >> 4).fromLegacyData(combinedId & 0xF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setCount(0, nonEmptyBlockCount, section);
|
||||||
|
}
|
||||||
|
// Set biomes
|
||||||
|
int[][] biomes = fs.biomes;
|
||||||
|
if (biomes != null) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
int[] array = biomes[x];
|
||||||
|
if (array == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
int biome = array[z];
|
||||||
|
if (biome == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nmsChunk.getBiomeIndex()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Set tiles
|
||||||
|
Map<BytePair, CompoundTag> tilesToSpawn = fs.getTiles();
|
||||||
|
int bx = fs.getX() << 4;
|
||||||
|
int bz = fs.getZ() << 4;
|
||||||
|
|
||||||
|
for (Map.Entry<BytePair, CompoundTag> entry : tilesToSpawn.entrySet()) {
|
||||||
|
CompoundTag nativeTag = entry.getValue();
|
||||||
|
BytePair pair = entry.getKey();
|
||||||
|
BlockPosition pos = new BlockPosition(MathMan.unpair16x(pair.pair[0]) + bx, pair.pair[1] & 0xFF, MathMan.unpair16y(pair.pair[0]) + bz); // Set pos
|
||||||
|
TileEntity tileEntity = nmsWorld.getTileEntity(pos);
|
||||||
|
if (tileEntity != null) {
|
||||||
|
NBTTagCompound tag = (NBTTagCompound) methodFromNative.invoke(adapter, nativeTag);
|
||||||
|
tileEntity.a(tag); // ReadTagIntoTile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
MainUtil.handleError(e);
|
||||||
|
}
|
||||||
|
final int[][] biomes = fs.getBiomeArray();
|
||||||
|
final Biome[] values = Biome.values();
|
||||||
|
if (biomes != null) {
|
||||||
|
for (int x = 0; x < 16; x++) {
|
||||||
|
final int[] array = biomes[x];
|
||||||
|
if (array == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int z = 0; z < 16; z++) {
|
||||||
|
final int biome = array[z];
|
||||||
|
if (biome == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
chunk.getBlock(x, 0, z).setBiome(values[biome]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendChunk(fs, null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public boolean unloadChunk(final String world, final Chunk chunk) {
|
||||||
|
net.minecraft.server.v1_10_R1.Chunk c = ((CraftChunk) chunk).getHandle();
|
||||||
|
c.mustSave = false;
|
||||||
|
if (chunk.isLoaded()) {
|
||||||
|
chunk.unload(false, false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FaweChunk getFaweChunk(int x, int z) {
|
||||||
|
return new com.boydti.fawe.bukkit.v1_10.BukkitChunk_1_10(this, x, z);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,373 @@
|
|||||||
|
package com.boydti.fawe.bukkit.v1_10;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.sk89q.jnbt.ByteArrayTag;
|
||||||
|
import com.sk89q.jnbt.ByteTag;
|
||||||
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
|
import com.sk89q.jnbt.DoubleTag;
|
||||||
|
import com.sk89q.jnbt.EndTag;
|
||||||
|
import com.sk89q.jnbt.FloatTag;
|
||||||
|
import com.sk89q.jnbt.IntArrayTag;
|
||||||
|
import com.sk89q.jnbt.IntTag;
|
||||||
|
import com.sk89q.jnbt.ListTag;
|
||||||
|
import com.sk89q.jnbt.LongTag;
|
||||||
|
import com.sk89q.jnbt.NBTConstants;
|
||||||
|
import com.sk89q.jnbt.ShortTag;
|
||||||
|
import com.sk89q.jnbt.StringTag;
|
||||||
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.blocks.BaseBlock;
|
||||||
|
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||||
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
|
import com.sk89q.worldedit.internal.Constants;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import net.minecraft.server.v1_10_R1.BiomeBase;
|
||||||
|
import net.minecraft.server.v1_10_R1.BlockPosition;
|
||||||
|
import net.minecraft.server.v1_10_R1.EntityTypes;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTBase;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagByte;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagByteArray;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagCompound;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagDouble;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagEnd;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagFloat;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagInt;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagIntArray;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagList;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagLong;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagShort;
|
||||||
|
import net.minecraft.server.v1_10_R1.NBTTagString;
|
||||||
|
import net.minecraft.server.v1_10_R1.TileEntity;
|
||||||
|
import net.minecraft.server.v1_10_R1.World;
|
||||||
|
import net.minecraft.server.v1_10_R1.WorldServer;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Biome;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.craftbukkit.v1_10_R1.CraftServer;
|
||||||
|
import org.bukkit.craftbukkit.v1_10_R1.CraftWorld;
|
||||||
|
import org.bukkit.craftbukkit.v1_10_R1.block.CraftBlock;
|
||||||
|
import org.bukkit.craftbukkit.v1_10_R1.entity.CraftEntity;
|
||||||
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
|
||||||
|
public final class FaweAdapter_1_10 implements BukkitImplAdapter
|
||||||
|
{
|
||||||
|
private final Logger logger = Logger.getLogger(getClass().getCanonicalName());
|
||||||
|
private final Field nbtListTagListField;
|
||||||
|
private final Method nbtCreateTagMethod;
|
||||||
|
|
||||||
|
public FaweAdapter_1_10()
|
||||||
|
throws NoSuchFieldException, NoSuchMethodException
|
||||||
|
{
|
||||||
|
CraftServer.class.cast(Bukkit.getServer());
|
||||||
|
|
||||||
|
this.nbtListTagListField = NBTTagList.class.getDeclaredField("list");
|
||||||
|
this.nbtListTagListField.setAccessible(true);
|
||||||
|
|
||||||
|
this.nbtCreateTagMethod = NBTBase.class.getDeclaredMethod("createTag", new Class[] { Byte.TYPE });
|
||||||
|
this.nbtCreateTagMethod.setAccessible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readTagIntoTileEntity(NBTTagCompound tag, TileEntity tileEntity)
|
||||||
|
{
|
||||||
|
tileEntity.a(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readTileEntityIntoTag(TileEntity tileEntity, NBTTagCompound tag)
|
||||||
|
{
|
||||||
|
tileEntity.save(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static String getEntityId(net.minecraft.server.v1_10_R1.Entity entity)
|
||||||
|
{
|
||||||
|
return EntityTypes.b(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static net.minecraft.server.v1_10_R1.Entity createEntityFromId(String id, World world)
|
||||||
|
{
|
||||||
|
return EntityTypes.createEntityByName(id, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readTagIntoEntity(NBTTagCompound tag, net.minecraft.server.v1_10_R1.Entity entity)
|
||||||
|
{
|
||||||
|
entity.f(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readEntityIntoTag(net.minecraft.server.v1_10_R1.Entity entity, NBTTagCompound tag)
|
||||||
|
{
|
||||||
|
entity.e(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBlockId(Material material)
|
||||||
|
{
|
||||||
|
return material.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Material getMaterial(int id)
|
||||||
|
{
|
||||||
|
return Material.getMaterial(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBiomeId(Biome biome)
|
||||||
|
{
|
||||||
|
BiomeBase mcBiome = CraftBlock.biomeToBiomeBase(biome);
|
||||||
|
return mcBiome != null ? BiomeBase.a(mcBiome) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Biome getBiome(int id)
|
||||||
|
{
|
||||||
|
BiomeBase mcBiome = BiomeBase.getBiome(id);
|
||||||
|
return CraftBlock.biomeBaseToBiome(mcBiome);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseBlock getBlock(Location location)
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(location);
|
||||||
|
|
||||||
|
CraftWorld craftWorld = (CraftWorld)location.getWorld();
|
||||||
|
int x = location.getBlockX();
|
||||||
|
int y = location.getBlockY();
|
||||||
|
int z = location.getBlockZ();
|
||||||
|
|
||||||
|
Block bukkitBlock = location.getBlock();
|
||||||
|
BaseBlock block = new BaseBlock(bukkitBlock.getTypeId(), bukkitBlock.getData());
|
||||||
|
|
||||||
|
TileEntity te = craftWorld.getHandle().getTileEntity(new BlockPosition(x, y, z));
|
||||||
|
if (te != null)
|
||||||
|
{
|
||||||
|
NBTTagCompound tag = new NBTTagCompound();
|
||||||
|
readTileEntityIntoTag(te, tag);
|
||||||
|
block.setNbtData((CompoundTag)toNative(tag));
|
||||||
|
}
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setBlock(Location location, BaseBlock block, boolean notifyAndLight)
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(location);
|
||||||
|
Preconditions.checkNotNull(block);
|
||||||
|
|
||||||
|
CraftWorld craftWorld = (CraftWorld)location.getWorld();
|
||||||
|
int x = location.getBlockX();
|
||||||
|
int y = location.getBlockY();
|
||||||
|
int z = location.getBlockZ();
|
||||||
|
|
||||||
|
boolean changed = location.getBlock().setTypeIdAndData(block.getId(), (byte)block.getData(), notifyAndLight);
|
||||||
|
|
||||||
|
CompoundTag nativeTag = block.getNbtData();
|
||||||
|
if (nativeTag != null)
|
||||||
|
{
|
||||||
|
TileEntity tileEntity = craftWorld.getHandle().getTileEntity(new BlockPosition(x, y, z));
|
||||||
|
if (tileEntity != null)
|
||||||
|
{
|
||||||
|
NBTTagCompound tag = (NBTTagCompound)fromNative(nativeTag);
|
||||||
|
tag.set("x", new NBTTagInt(x));
|
||||||
|
tag.set("y", new NBTTagInt(y));
|
||||||
|
tag.set("z", new NBTTagInt(z));
|
||||||
|
readTagIntoTileEntity(tag, tileEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseEntity getEntity(org.bukkit.entity.Entity entity)
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(entity);
|
||||||
|
|
||||||
|
CraftEntity craftEntity = (CraftEntity)entity;
|
||||||
|
net.minecraft.server.v1_10_R1.Entity mcEntity = craftEntity.getHandle();
|
||||||
|
|
||||||
|
String id = getEntityId(mcEntity);
|
||||||
|
if (id != null)
|
||||||
|
{
|
||||||
|
NBTTagCompound tag = new NBTTagCompound();
|
||||||
|
readEntityIntoTag(mcEntity, tag);
|
||||||
|
return new BaseEntity(id, (CompoundTag)toNative(tag));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state)
|
||||||
|
{
|
||||||
|
Preconditions.checkNotNull(location);
|
||||||
|
Preconditions.checkNotNull(state);
|
||||||
|
|
||||||
|
CraftWorld craftWorld = (CraftWorld)location.getWorld();
|
||||||
|
WorldServer worldServer = craftWorld.getHandle();
|
||||||
|
|
||||||
|
net.minecraft.server.v1_10_R1.Entity createdEntity = createEntityFromId(state.getTypeId(), craftWorld.getHandle());
|
||||||
|
if (createdEntity != null)
|
||||||
|
{
|
||||||
|
CompoundTag nativeTag = state.getNbtData();
|
||||||
|
if (nativeTag != null)
|
||||||
|
{
|
||||||
|
NBTTagCompound tag = (NBTTagCompound)fromNative(nativeTag);
|
||||||
|
for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||||
|
tag.remove(name);
|
||||||
|
}
|
||||||
|
readTagIntoEntity(tag, createdEntity);
|
||||||
|
}
|
||||||
|
createdEntity.setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||||
|
|
||||||
|
worldServer.addEntity(createdEntity, CreatureSpawnEvent.SpawnReason.CUSTOM);
|
||||||
|
return createdEntity.getBukkitEntity();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tag toNative(NBTBase foreign)
|
||||||
|
{
|
||||||
|
if (foreign == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagCompound))
|
||||||
|
{
|
||||||
|
Map<String, Tag> values = new HashMap();
|
||||||
|
Set<String> foreignKeys = ((NBTTagCompound)foreign).c();
|
||||||
|
for (String str : foreignKeys)
|
||||||
|
{
|
||||||
|
NBTBase base = ((NBTTagCompound)foreign).get(str);
|
||||||
|
values.put(str, toNative(base));
|
||||||
|
}
|
||||||
|
return new CompoundTag(values);
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagByte)) {
|
||||||
|
return new ByteTag(((NBTTagByte)foreign).g());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagByteArray)) {
|
||||||
|
return new ByteArrayTag(((NBTTagByteArray)foreign).c());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagDouble)) {
|
||||||
|
return new DoubleTag(((NBTTagDouble)foreign).h());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagFloat)) {
|
||||||
|
return new FloatTag(((NBTTagFloat)foreign).i());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagInt)) {
|
||||||
|
return new IntTag(((NBTTagInt)foreign).e());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagIntArray)) {
|
||||||
|
return new IntArrayTag(((NBTTagIntArray)foreign).d());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagList)) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return toNativeList((NBTTagList)foreign);
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
this.logger.log(Level.WARNING, "Failed to convert NBTTagList", e);
|
||||||
|
return new ListTag(ByteTag.class, new ArrayList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagLong)) {
|
||||||
|
return new LongTag(((NBTTagLong)foreign).d());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagShort)) {
|
||||||
|
return new ShortTag(((NBTTagShort)foreign).f());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagString)) {
|
||||||
|
return new StringTag(((NBTTagString)foreign).c_());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof NBTTagEnd)) {
|
||||||
|
return new EndTag();
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Don't know how to make native " + foreign.getClass().getCanonicalName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ListTag toNativeList(NBTTagList foreign)
|
||||||
|
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException
|
||||||
|
{
|
||||||
|
List<Tag> values = new ArrayList();
|
||||||
|
int type = foreign.getTypeId();
|
||||||
|
|
||||||
|
List foreignList = (List)this.nbtListTagListField.get(foreign);
|
||||||
|
for (int i = 0; i < foreign.size(); i++)
|
||||||
|
{
|
||||||
|
NBTBase element = (NBTBase)foreignList.get(i);
|
||||||
|
values.add(toNative(element));
|
||||||
|
}
|
||||||
|
Class<? extends Tag> cls = NBTConstants.getClassFromType(type);
|
||||||
|
return new ListTag(cls, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NBTBase fromNative(Tag foreign)
|
||||||
|
{
|
||||||
|
if (foreign == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Map.Entry<String, Tag> entry;
|
||||||
|
if ((foreign instanceof CompoundTag))
|
||||||
|
{
|
||||||
|
NBTTagCompound tag = new NBTTagCompound();
|
||||||
|
for (Iterator localIterator = ((CompoundTag)foreign)
|
||||||
|
.getValue().entrySet().iterator(); localIterator.hasNext();)
|
||||||
|
{
|
||||||
|
entry = (Map.Entry)localIterator.next();
|
||||||
|
|
||||||
|
tag.set((String)entry.getKey(), fromNative((Tag)entry.getValue()));
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
if ((foreign instanceof ByteTag)) {
|
||||||
|
return new NBTTagByte(((ByteTag)foreign).getValue().byteValue());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof ByteArrayTag)) {
|
||||||
|
return new NBTTagByteArray(((ByteArrayTag)foreign).getValue());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof DoubleTag)) {
|
||||||
|
return new NBTTagDouble(((DoubleTag)foreign).getValue().doubleValue());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof FloatTag)) {
|
||||||
|
return new NBTTagFloat(((FloatTag)foreign).getValue().floatValue());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof IntTag)) {
|
||||||
|
return new NBTTagInt(((IntTag)foreign).getValue().intValue());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof IntArrayTag)) {
|
||||||
|
return new NBTTagIntArray(((IntArrayTag)foreign).getValue());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof ListTag))
|
||||||
|
{
|
||||||
|
NBTTagList tag = new NBTTagList();
|
||||||
|
ListTag foreignList = (ListTag)foreign;
|
||||||
|
for (Tag t : foreignList.getValue()) {
|
||||||
|
tag.add(fromNative(t));
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
if ((foreign instanceof LongTag)) {
|
||||||
|
return new NBTTagLong(((LongTag)foreign).getValue().longValue());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof ShortTag)) {
|
||||||
|
return new NBTTagShort(((ShortTag)foreign).getValue().shortValue());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof StringTag)) {
|
||||||
|
return new NBTTagString(((StringTag)foreign).getValue());
|
||||||
|
}
|
||||||
|
if ((foreign instanceof EndTag)) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (NBTBase)this.nbtCreateTagMethod.invoke(null, new Object[] { Byte.valueOf((byte) 0) });
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Don't know how to make NMS " + foreign.getClass().getCanonicalName());
|
||||||
|
}
|
||||||
|
}
|
49
bukkit110/src/main/resources/plugin.yml
Normal file
49
bukkit110/src/main/resources/plugin.yml
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
name: ${name}
|
||||||
|
main: com.boydti.fawe.bukkit.v1_10.BukkitMain_110
|
||||||
|
version: ${version}
|
||||||
|
description: Fast Async WorldEdit plugin
|
||||||
|
authors: [Empire92]
|
||||||
|
loadbefore: [WorldEdit]
|
||||||
|
load: STARTUP
|
||||||
|
database: false
|
||||||
|
#softdepend: [WorldGuard, PlotSquared, MCore, Factions, GriefPrevention, Residence, Towny, PlotMe, PreciousStones]
|
||||||
|
commands:
|
||||||
|
wea:
|
||||||
|
description: (FAWE) Bypass WorldEdit processing and area restrictions
|
||||||
|
aliases: [weanywhere,worldeditanywhere,/wea,/weanywhere,/worldeditanywhere]
|
||||||
|
usage: "Vault is required for the toggle. Optionally, you can set the permission fawe.bypass"
|
||||||
|
fixlighting:
|
||||||
|
description: (FAWE) Fix the lighting in your current chunk
|
||||||
|
aliases: [/fixlighting]
|
||||||
|
stream:
|
||||||
|
description: (FAWE) Stream a schematic into the world
|
||||||
|
aliases: [/stream]
|
||||||
|
fawe:
|
||||||
|
description: (FAWE) Reload the plugin
|
||||||
|
aliases: [/fawe,/fawereload]
|
||||||
|
select:
|
||||||
|
description: (FAWE) Select your current WorldEdit Region.
|
||||||
|
aliases: [/select,wer,/wer,worldeditregion,/worldeditregion,/region]
|
||||||
|
frb:
|
||||||
|
description: (FAWE) Rollback an edit
|
||||||
|
aliases: [fawerollback,fawerb,/uu,/rb,/frb,/fawerollback,/fawerb]
|
||||||
|
fcancel:
|
||||||
|
description: (FAWE) Cancel your edit
|
||||||
|
aliases: [fawecancel,/fcancel,/cancel,/fawecancel]
|
||||||
|
'/p':
|
||||||
|
description: VoxelSniper perform command
|
||||||
|
aliases: [perform,/perform]
|
||||||
|
'/d':
|
||||||
|
description: VoxelSniper default command
|
||||||
|
aliases: [default,/default]
|
||||||
|
permissions:
|
||||||
|
fawe.bypass:
|
||||||
|
default: false
|
||||||
|
fawe.admin:
|
||||||
|
default: false
|
||||||
|
fawe.stream:
|
||||||
|
default: false
|
||||||
|
fawe.fixlighting:
|
||||||
|
default: false
|
||||||
|
fawe.reload:
|
||||||
|
default: false
|
@ -18,7 +18,7 @@ public class SetQueue {
|
|||||||
*/
|
*/
|
||||||
public static final SetQueue IMP = new SetQueue();
|
public static final SetQueue IMP = new SetQueue();
|
||||||
|
|
||||||
public static enum QueueStage {
|
public enum QueueStage {
|
||||||
INACTIVE, ACTIVE, NONE;
|
INACTIVE, ACTIVE, NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
rootProject.name = 'FastAsyncWorldEdit'
|
rootProject.name = 'FastAsyncWorldEdit'
|
||||||
|
|
||||||
include 'core', 'bukkit0', 'bukkit19', 'bukkit18', 'forge189', 'forge1710', 'sponge'
|
include 'core', 'bukkit0', 'bukkit19', 'bukkit110', 'bukkit18', 'forge189', 'forge1710', 'sponge'
|
||||||
|
Loading…
Reference in New Issue
Block a user