mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-07-01 09:05:08 +02:00
Fix entity y value not within chunk Fix combined stages CPUOptimizedHistory not restoring air in existing sections on undo Change EditSession to wait for completion on flush (you should be flushing it async) Added setting for edit session history with no session
596 lines
24 KiB
Java
596 lines
24 KiB
Java
package com.boydti.fawe.bukkit.v1_8;
|
|
|
|
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.StringTag;
|
|
import com.sk89q.jnbt.Tag;
|
|
import com.sk89q.worldedit.internal.Constants;
|
|
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.Set;
|
|
import java.util.UUID;
|
|
import net.minecraft.server.v1_8_R3.BlockPosition;
|
|
import net.minecraft.server.v1_8_R3.ChunkCoordIntPair;
|
|
import net.minecraft.server.v1_8_R3.ChunkSection;
|
|
import net.minecraft.server.v1_8_R3.Entity;
|
|
import net.minecraft.server.v1_8_R3.EntityPlayer;
|
|
import net.minecraft.server.v1_8_R3.EntityTracker;
|
|
import net.minecraft.server.v1_8_R3.EntityTrackerEntry;
|
|
import net.minecraft.server.v1_8_R3.EntityTypes;
|
|
import net.minecraft.server.v1_8_R3.LongHashMap;
|
|
import net.minecraft.server.v1_8_R3.NBTTagCompound;
|
|
import net.minecraft.server.v1_8_R3.NibbleArray;
|
|
import net.minecraft.server.v1_8_R3.PacketPlayOutEntityDestroy;
|
|
import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk;
|
|
import net.minecraft.server.v1_8_R3.PlayerChunkMap;
|
|
import net.minecraft.server.v1_8_R3.TileEntity;
|
|
import net.minecraft.server.v1_8_R3.WorldServer;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.Chunk;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.World;
|
|
import org.bukkit.craftbukkit.v1_8_R3.CraftChunk;
|
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
|
|
|
public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]> {
|
|
|
|
public BukkitQueue18R3(final String world) {
|
|
super(world);
|
|
checkVersion("v1_8_R3");
|
|
}
|
|
|
|
@Override
|
|
public boolean isChunkLoaded(int x, int z) {
|
|
return getWorld().isChunkLoaded(x, z);
|
|
}
|
|
|
|
public World getWorld(String world) {
|
|
return Bukkit.getWorld(world);
|
|
}
|
|
|
|
@Override
|
|
public boolean regenerateChunk(World world, int x, int z) {
|
|
return world.regenerateChunk(x, z);
|
|
}
|
|
|
|
@Override
|
|
public boolean loadChunk(World world, int x, int z, boolean generate) {
|
|
return getCachedSections(world, x, z) != null;
|
|
}
|
|
|
|
@Override
|
|
public ChunkSection[] getCachedSections(World world, int x, int z) {
|
|
Chunk chunk = world.getChunkAt(x, z);
|
|
if (chunk == null) {
|
|
return null;
|
|
}
|
|
if (!chunk.isLoaded()) {
|
|
chunk.load(true);
|
|
}
|
|
return ((CraftChunk) chunk).getHandle().getSections();
|
|
}
|
|
|
|
@Override
|
|
public int getCombinedId4Data(char[] ls, int x, int y, int z) {
|
|
return ls[FaweCache.CACHE_J[y][x & 15][z & 15]];
|
|
}
|
|
|
|
@Override
|
|
public boolean isChunkLoaded(World world, int x, int z) {
|
|
return world.isChunkLoaded(x, z);
|
|
}
|
|
|
|
@Override
|
|
public char[] getCachedSection(ChunkSection[] chunkSections, int cy) {
|
|
ChunkSection section = chunkSections[cy];
|
|
return section == null ? null : section.getIdArray();
|
|
}
|
|
|
|
@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());
|
|
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) {
|
|
idPrevious[layer] = section.getIdArray().clone();
|
|
short solid = 0;
|
|
for (int combined : idPrevious[layer]) {
|
|
if (combined > 1) {
|
|
solid++;
|
|
}
|
|
}
|
|
previous.count[layer] = solid;
|
|
previous.air[layer] = (short) (4096 - solid);
|
|
}
|
|
}
|
|
}
|
|
previous.ids = idPrevious;
|
|
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);
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
public CompoundTag getTag(TileEntity tile) {
|
|
try {
|
|
NBTTagCompound tag = new NBTTagCompound();
|
|
tile.b(tag); // readTagIntoEntity
|
|
return (CompoundTag) methodToNative.invoke(adapter, tag);
|
|
} catch (Exception e) {
|
|
MainUtil.handleError(e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
@Override
|
|
public Chunk getChunk(World world, int x, int z) {
|
|
return world.getChunkAt(x, z);
|
|
}
|
|
|
|
@Override
|
|
public boolean setComponents(FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
|
|
CharFaweChunk<Chunk> fs = (CharFaweChunk<Chunk>) fc;
|
|
CraftChunk chunk = (CraftChunk) fs.getChunk();
|
|
net.minecraft.server.v1_8_R3.Chunk nmsChunk = chunk.getHandle();
|
|
net.minecraft.server.v1_8_R3.World nmsWorld = nmsChunk.getWorld();
|
|
try {
|
|
final boolean flag = getWorld().getEnvironment() == World.Environment.NORMAL;
|
|
// Sections
|
|
ChunkSection[] sections = nmsChunk.getSections();
|
|
Map<BlockPosition, TileEntity> tiles = nmsChunk.getTileEntities();
|
|
Collection<net.minecraft.server.v1_8_R3.Entity>[] entities = nmsChunk.getEntitySlices();
|
|
|
|
// Remove entities
|
|
for (int i = 0; i < 16; 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) {
|
|
continue;
|
|
}
|
|
if (y < 0 || y > 255 || array[FaweCache.CACHE_J[y][x][z]] != 0) {
|
|
nmsWorld.removeEntity(entity);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Set entities
|
|
Set<UUID> createdEntities = new HashSet<>();
|
|
Set<CompoundTag> entitiesToSpawn = fs.getEntities();
|
|
for (CompoundTag nativeTag : entitiesToSpawn) {
|
|
Map<String, Tag> entityTagMap = 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) {
|
|
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());
|
|
}
|
|
}
|
|
// Run change task if applicable
|
|
if (changeTask != null) {
|
|
CharFaweChunk previous = getPrevious(fs, sections, tiles, entities, createdEntities, false);
|
|
changeTask.run(previous);
|
|
}
|
|
// Trim tiles
|
|
Set<Map.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().E();
|
|
iterator.remove();
|
|
}
|
|
}
|
|
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 blocks
|
|
for (int j = 0; j < sections.length; j++) {
|
|
if (fs.getCount(j) == 0) {
|
|
continue;
|
|
}
|
|
char[] newArray = fs.getIdArray(j);
|
|
if (newArray == null) {
|
|
continue;
|
|
}
|
|
ChunkSection section = sections[j];
|
|
if ((section == null) || (fs.getCount(j) >= 4096)) {
|
|
section = new ChunkSection(j << 4, flag, newArray);
|
|
sections[j] = section;
|
|
continue;
|
|
}
|
|
char[] currentArray = section.getIdArray();
|
|
int solid = 0;
|
|
for (int k = 0; k < newArray.length; k++) {
|
|
char n = newArray[k];
|
|
switch (n) {
|
|
case 0:
|
|
continue;
|
|
case 1:
|
|
if (currentArray[k] > 1) {
|
|
solid++;
|
|
currentArray[k] = 0;
|
|
}
|
|
continue;
|
|
default:
|
|
solid++;
|
|
currentArray[k] = n;
|
|
continue;
|
|
}
|
|
}
|
|
setCount(0, solid, 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);
|
|
}
|
|
sendChunk(fc, null);
|
|
return true;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
@Override
|
|
public void refreshChunk(World world, Chunk chunk) {
|
|
if (!chunk.isLoaded()) {
|
|
return;
|
|
}
|
|
try {
|
|
net.minecraft.server.v1_8_R3.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
|
|
ChunkCoordIntPair pos = nmsChunk.j(); // getPosition()
|
|
WorldServer w = (WorldServer) nmsChunk.getWorld();
|
|
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
|
|
int x = pos.x;
|
|
int z = pos.z;
|
|
if (!chunkMap.isChunkInUse(x, z)) {
|
|
return;
|
|
}
|
|
HashSet<EntityPlayer> set = new HashSet<EntityPlayer>();
|
|
EntityTracker tracker = w.getTracker();
|
|
// Get players
|
|
|
|
Field fieldChunkMap = chunkMap.getClass().getDeclaredField("d");
|
|
fieldChunkMap.setAccessible(true);
|
|
LongHashMap<Object> map = (LongHashMap<Object>) fieldChunkMap.get(chunkMap);
|
|
long pair = (long) x + 2147483647L | (long) z + 2147483647L << 32;
|
|
Object playerChunk = map.getEntry(pair);
|
|
Field fieldPlayers = playerChunk.getClass().getDeclaredField("b");
|
|
fieldPlayers.setAccessible(true);
|
|
HashSet<EntityPlayer> players = new HashSet<>((Collection<EntityPlayer>)fieldPlayers.get(playerChunk));
|
|
if (players.size() == 0) {
|
|
return;
|
|
}
|
|
HashSet<EntityTrackerEntry> entities = new HashSet<>();
|
|
List<Entity>[] entitieSlices = nmsChunk.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);
|
|
}
|
|
}
|
|
}
|
|
// Send chunks
|
|
PacketPlayOutMapChunk packet = new PacketPlayOutMapChunk(nmsChunk, false, 65535);
|
|
for (EntityPlayer player : players) {
|
|
player.playerConnection.sendPacket(packet);
|
|
}
|
|
// send ents
|
|
for (EntityTrackerEntry entry : entities) {
|
|
try {
|
|
TaskManager.IMP.later(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
for (EntityPlayer player : players) {
|
|
boolean result = entry.trackedPlayers.remove(player);
|
|
if (result && entry.tracker != player) {
|
|
entry.updatePlayer(player);
|
|
}
|
|
}
|
|
}
|
|
}, 2);
|
|
} catch (Throwable e) {
|
|
MainUtil.handleError(e);
|
|
}
|
|
}
|
|
} catch (Throwable e) {
|
|
MainUtil.handleError(e);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean fixLighting(FaweChunk chunk, RelightMode mode) {
|
|
if (mode == RelightMode.NONE) {
|
|
return true;
|
|
}
|
|
try {
|
|
CharFaweChunk<Chunk> fc = (CharFaweChunk<Chunk>) chunk;
|
|
CraftChunk craftChunk = (CraftChunk) fc.getChunk();
|
|
net.minecraft.server.v1_8_R3.Chunk nmsChunk = craftChunk.getHandle();
|
|
if (!craftChunk.isLoaded()) {
|
|
return false;
|
|
}
|
|
ChunkSection[] sections = nmsChunk.getSections();
|
|
if (mode == RelightMode.ALL) {
|
|
for (int i = 0; i < sections.length; i++) {
|
|
ChunkSection section = sections[i];
|
|
if (section != null) {
|
|
section.a(new NibbleArray());
|
|
section.b(new NibbleArray());
|
|
}
|
|
}
|
|
}
|
|
nmsChunk.initLighting();
|
|
if (fc.getTotalRelight() == 0 && mode == RelightMode.MINIMAL) {
|
|
return true;
|
|
}
|
|
net.minecraft.server.v1_8_R3.World nmsWorld = nmsChunk.getWorld();
|
|
|
|
int X = fc.getX() << 4;
|
|
int Z = fc.getZ() << 4;
|
|
|
|
for (int j = 0; j < sections.length; j++) {
|
|
ChunkSection section = sections[j];
|
|
if (section == null) {
|
|
continue;
|
|
}
|
|
if (((fc.getRelight(j) == 0) && mode == RelightMode.MINIMAL) || (fc.getCount(j) == 0 && mode != RelightMode.ALL) || ((fc.getCount(j) >= 4096) && (fc.getAir(j) == 0)) || fc.getAir(j) == 4096) {
|
|
continue;
|
|
}
|
|
char[] array = section.getIdArray();
|
|
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 (isSurrounded(sections, x, y, z)) {
|
|
continue;
|
|
}
|
|
pos.c(X + x, y, Z + z);
|
|
nmsWorld.x(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 (isSurrounded(sections, x, y, z)) {
|
|
continue;
|
|
}
|
|
pos.c(X + x, y, Z + z);
|
|
nmsWorld.x(pos);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
} catch (Throwable e) {
|
|
if (Thread.currentThread() == Fawe.get().getMainThread()) {
|
|
MainUtil.handleError(e);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public boolean isSurrounded(ChunkSection[] sections, int x, int y, int z) {
|
|
return isSolid(getId(sections, x, y + 1, z))
|
|
&& isSolid(getId(sections, x + 1, y - 1, z))
|
|
&& isSolid(getId(sections, x - 1, y, z))
|
|
&& isSolid(getId(sections, x, y, z + 1))
|
|
&& isSolid(getId(sections, x, y, z - 1));
|
|
}
|
|
|
|
public boolean isSolid(int i) {
|
|
return Material.getMaterial(i).isOccluding();
|
|
}
|
|
|
|
public int getId(ChunkSection[] sections, int x, int y, int z) {
|
|
if (x < 0 || x > 15 || z < 0 || z > 15) {
|
|
return 1;
|
|
}
|
|
if (y < 0 || y > 255) {
|
|
return 1;
|
|
}
|
|
int i = FaweCache.CACHE_I[y][x][z];
|
|
ChunkSection section = sections[i];
|
|
if (section == null) {
|
|
return 0;
|
|
}
|
|
char[] array = section.getIdArray();
|
|
int j = FaweCache.CACHE_J[y][x][z];
|
|
return array[j] >> 4;
|
|
}
|
|
}
|