Relight improvements + ports

6 lighting modes (0-5), see config
forge194
forge110
bukkit1710
(untested)
This commit is contained in:
Jesse Boyd 2016-07-15 09:53:30 +10:00
parent bdff04cff4
commit c52c1bee27
50 changed files with 5957 additions and 796 deletions

View File

@ -49,7 +49,6 @@ subprojects {
maven {url "http://maven.sk89q.com/repo/"}
maven {url "http://nexus.theyeticave.net/content/repositories/pub_releases"}
maven {url "http://repo.maven.apache.org/maven2"}
maven {url "http://hub.spigotmc.org/nexus/content/groups/public/"}
maven {url "http://ci.frostcast.net/plugin/repository/everything"}
maven {url "http://maven.sk89q.com/artifactory/repo/"}
maven {url "http://nexus.theyeticave.net/content/repositories/pub_releases"}

View File

@ -43,6 +43,32 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
}
}
@Override
public void setFullbright(CHUNKSECTIONS sections) {}
@Override
public boolean initLighting(CHUNK chunk, CHUNKSECTIONS sections, RelightMode mode) {
return false;
}
@Override
public int getEmmittedLight(CHUNKSECTIONS sections, int x, int y, int z) {
return 0;
}
@Override
public int getSkyLight(CHUNKSECTIONS sections, int x, int y, int z) {
return 15;
}
@Override
public void relight(int x, int y, int z) {}
@Override
public boolean removeLighting(CHUNKSECTIONS sections, RelightMode mode, boolean hasSky) {
return false;
}
public void checkVersion(String supported) {
String version = Bukkit.getServer().getClass().getPackage().getName();
if (!version.contains(supported)) {
@ -127,8 +153,8 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
}
@Override
public World getWorld(String world) {
return Bukkit.getWorld(world);
public World getImpWorld() {
return Bukkit.getWorld(getWorldName());
}
@Override
@ -153,9 +179,8 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
}
@Override
public boolean fixLighting(FaweChunk fc, RelightMode mode) {
// Not implemented
return true;
public boolean hasSky() {
return getWorld().getEnvironment() == World.Environment.NORMAL;
}
@Override

View File

@ -32,6 +32,11 @@ public class BukkitQueue_All extends BukkitQueue_0<Chunk, Chunk, Chunk> {
return combined;
}
@Override
public boolean fixLighting(FaweChunk<?> fc, RelightMode mode) {
return false;
}
@Override
public Chunk getCachedSections(World impWorld, int cx, int cz) {
return impWorld.getChunkAt(cx, cz);

View File

@ -6,7 +6,6 @@ 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;
@ -22,6 +21,7 @@ import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@ -65,13 +65,13 @@ import net.minecraft.server.v1_10_R1.WorldSettings;
import net.minecraft.server.v1_10_R1.WorldType;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.WorldCreator;
import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.v1_10_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_10_R1.CraftServer;
import org.bukkit.craftbukkit.v1_10_R1.CraftWorld;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.event.world.WorldLoadEvent;
@ -269,176 +269,98 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], DataP
}
@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();
boolean async = Fawe.get().getMainThread() != Thread.currentThread();
if (!chunk.isLoaded()) {
if (async) {
return false;
}
chunk.load(false);
}
net.minecraft.server.v1_10_R1.Chunk c = ((CraftChunk) chunk).getHandle();
c.e(false);
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());
}
public boolean removeLighting(ChunkSection[] sections, RelightMode mode, boolean sky) {
if (mode == RelightMode.ALL) {
for (int i = 0; i < sections.length; i++) {
ChunkSection section = sections[i];
if (section != null) {
section.a(new NibbleArray()); // Emitted
if (sky) {
section.b(new NibbleArray()); // Skylight
}
}
}
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:
case 213:
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;
return true;
}
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));
@Override
public boolean initLighting(Chunk chunk, ChunkSection[] sections, RelightMode mode) {
net.minecraft.server.v1_10_R1.Chunk c = ((CraftChunk) chunk).getHandle();
if (mode == RelightMode.ALL) {
c.initLighting();
} else {
final int i = c.g();
final int i2 = i + 15;
int l;
int opacity;
int y;
for (int x = 0; x < 16; ++x) {
for (int z = 0; z < 16; ++z) {
y = i2;
l = 15;
do {
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);
}
}
}
return true;
}
public boolean isSolid(final int i) {
if (i != 0) {
final Material material = Material.getMaterial(i);
return (material != null) && Material.getMaterial(i).isOccluding();
@Override
public void setFullbright(ChunkSection[] sections) {
for (int i = 0; i < sections.length; i++) {
ChunkSection section = sections[i];
if (section != null) {
byte[] bytes = section.getSkyLightArray().asBytes();
Arrays.fill(bytes, (byte) 255);
}
}
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;
@Override
public int getSkyLight(ChunkSection[] sections, int x, int y, int z) {
ChunkSection section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 15;
}
if ((y < 0) || (y > 255)) {
return 1;
}
final int i = FaweCache.CACHE_I[y][x][z];
final char[] section = sections[i];
return section.b(x, y & 15, z);
}
@Override
public int getEmmittedLight(ChunkSection[] sections, int x, int y, int z) {
ChunkSection section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 0;
}
final int j = FaweCache.CACHE_J[y][x][z];
return section[j] >> 4;
return section.c(x, y & 15, z);
}
@Override
public void relight(int x, int y, int z) {
pos.c(x, y, z);
nmsWorld.w(pos);
}
private WorldServer nmsWorld;
@Override
public World getImpWorld() {
World world = super.getImpWorld();
this.nmsWorld = ((CraftWorld) world).getHandle();
return super.getImpWorld();
}
public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ChunkSection section) throws NoSuchFieldException, IllegalAccessException {
@ -594,6 +516,9 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], DataP
try {
final boolean flag = world.getEnvironment() == Environment.NORMAL;
net.minecraft.server.v1_10_R1.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
nmsChunk.f(true); // Set Modified
nmsChunk.mustSave = true;
System.out.println(nmsChunk.mustSave);
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();

32
bukkit1710/build.gradle Normal file
View File

@ -0,0 +1,32 @@
dependencies {
compile project(':bukkit0')
compile 'org.bukkit.craftbukkit:Craftbukkit:1.7.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);

View File

@ -0,0 +1,169 @@
package com.boydti.fawe.bukkit.v1_7;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.util.MainUtil;
import net.minecraft.server.v1_7_R4.NibbleArray;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
public class BukkitChunk_1_7 extends CharFaweChunk<Chunk> {
@Override
public Chunk getNewChunk() {
return Bukkit.getWorld(getParent().getWorldName()).getChunkAt(getX(), getZ());
}
public byte[][] byteIds;
public NibbleArray[] datas;
public BukkitChunk_1_7(FaweQueue parent, int x, int z) {
super(parent, x, z);
this.byteIds = new byte[16][];
this.datas = new NibbleArray[16];
}
public byte[] getByteIdArray(int i) {
return this.byteIds[i];
}
public NibbleArray getDataArray(int i) {
return datas[i];
}
@Override
public void setBlock(int x, int y, int z, int id, int data) {
int i = FaweCache.CACHE_I[y][x][z];
int j = FaweCache.CACHE_J[y][x][z];
byte[] vs = this.byteIds[i];
char[] vs2 = this.ids[i];
if (vs2 == null) {
vs2 = this.ids[i] = new char[4096];
}
if (vs == null) {
vs = this.byteIds[i] = new byte[4096];
}
this.count[i]++;
switch (id) {
case 0:
this.air[i]++;
vs[j] = -1;
vs2[j] = (char) 1;
return;
case 11:
case 39:
case 40:
case 51:
case 74:
case 89:
case 122:
case 124:
case 138:
case 169:
case 213:
this.relight[i]++;
case 2:
case 4:
case 13:
case 14:
case 15:
case 20:
case 21:
case 22:
case 30:
case 32:
case 37:
case 41:
case 42:
case 45:
case 46:
case 47:
case 48:
case 49:
case 55:
case 56:
case 57:
case 58:
case 60:
case 7:
case 73:
case 79:
case 80:
case 81:
case 82:
case 83:
case 85:
case 87:
case 88:
case 101:
case 102:
case 103:
case 110:
case 112:
case 113:
case 121:
case 129:
case 133:
case 165:
case 166:
case 170:
case 172:
case 173:
case 174:
case 188:
case 189:
case 190:
case 191:
case 192:
vs[j] = (byte) (id);
vs2[j] = (char) (id << 4);
return;
case 130:
case 76:
case 62:
case 50:
case 10:
this.relight[i]++;
case 54:
case 146:
case 61:
case 65:
case 68: // removed
default:
vs2[j] = (char) ((id << 4) + data);
vs[j] = (byte) id;
if (data != 0) {
NibbleArray dataArray = datas[i];
if (dataArray == null) {
datas[i] = dataArray = new NibbleArray(4096, 4);
}
dataArray.a(x, y & 15, z, data);
}
return;
}
}
@Override
public CharFaweChunk<Chunk> copy(boolean shallow) {
BukkitChunk_1_7 copy = new BukkitChunk_1_7(getParent(), getX(), getZ());
if (shallow) {
copy.byteIds = byteIds;
copy.datas = datas;
copy.air = air;
copy.biomes = biomes;
copy.chunk = chunk;
copy.count = count;
copy.relight = relight;
} else {
copy.byteIds = (byte[][]) MainUtil.copyNd(byteIds);
copy.datas = datas.clone();
copy.air = air.clone();
copy.biomes = biomes.clone();
copy.chunk = chunk;
copy.count = count.clone();
copy.relight = relight.clone();
}
return copy;
}
}

View File

@ -0,0 +1,12 @@
package com.boydti.fawe.bukkit.v1_7;
import com.boydti.fawe.bukkit.ABukkitMain;
import com.boydti.fawe.bukkit.v0.BukkitQueue_0;
public class BukkitMain_17 extends ABukkitMain {
@Override
public BukkitQueue_0 getQueue(String world) {
return new BukkitQueue17(world);
}
}

View File

@ -0,0 +1,676 @@
package com.boydti.fawe.bukkit.v1_7;
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.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.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
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_7_R4.ChunkCoordIntPair;
import net.minecraft.server.v1_7_R4.ChunkPosition;
import net.minecraft.server.v1_7_R4.ChunkSection;
import net.minecraft.server.v1_7_R4.Entity;
import net.minecraft.server.v1_7_R4.EntityPlayer;
import net.minecraft.server.v1_7_R4.EntityTracker;
import net.minecraft.server.v1_7_R4.EntityTrackerEntry;
import net.minecraft.server.v1_7_R4.EntityTypes;
import net.minecraft.server.v1_7_R4.EnumDifficulty;
import net.minecraft.server.v1_7_R4.EnumGamemode;
import net.minecraft.server.v1_7_R4.LongHashMap;
import net.minecraft.server.v1_7_R4.MinecraftServer;
import net.minecraft.server.v1_7_R4.NBTTagCompound;
import net.minecraft.server.v1_7_R4.NibbleArray;
import net.minecraft.server.v1_7_R4.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_7_R4.PacketPlayOutMapChunk;
import net.minecraft.server.v1_7_R4.PlayerChunkMap;
import net.minecraft.server.v1_7_R4.ServerNBTManager;
import net.minecraft.server.v1_7_R4.TileEntity;
import net.minecraft.server.v1_7_R4.WorldManager;
import net.minecraft.server.v1_7_R4.WorldServer;
import net.minecraft.server.v1_7_R4.WorldSettings;
import net.minecraft.server.v1_7_R4.WorldType;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.craftbukkit.v1_7_R4.CraftChunk;
import org.bukkit.craftbukkit.v1_7_R4.CraftServer;
import org.bukkit.craftbukkit.v1_7_R4.CraftWorld;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.generator.ChunkGenerator;
public class BukkitQueue17 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkSection> {
public BukkitQueue17(final String world) {
super(world);
checkVersion("v1_7_R4");
}
@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 void setFullbright(ChunkSection[] sections) {
for (int i = 0; i < sections.length; i++) {
ChunkSection section = sections[i];
if (section != null) {
byte[] bytes = section.getSkyLightArray().a;
Arrays.fill(bytes, Byte.MAX_VALUE);
}
}
}
@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(ChunkSection ls, int x, int y, int z) {
byte[] ids = ls.getIdArray();
NibbleArray datasNibble = ls.getDataArray();
int i = FaweCache.CACHE_J[y & 15][x & 15][z & 15];
int combined = (ids[i] << 4) + (datasNibble == null ? 0 : datasNibble.a(x & 15, y & 15, z & 15));
return combined;
}
@Override
public boolean isChunkLoaded(World world, int x, int z) {
return world.isChunkLoaded(x, z);
}
@Override
public ChunkSection getCachedSection(ChunkSection[] chunkSections, int cy) {
return chunkSections[cy];
}
@Override
public CharFaweChunk getPrevious(CharFaweChunk fs, ChunkSection[] sections, Map<?, ?> tilesGeneric, Collection<?>[] entitiesGeneric, Set<UUID> createdEntities, boolean all) throws Exception {
Map<ChunkPosition, TileEntity> tiles = (Map<ChunkPosition, 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) {
byte[] currentIdArray = section.getIdArray();
NibbleArray currentDataArray = section.getDataArray();
char[] array = new char[4096];
for (int j = 0; j < currentIdArray.length; j++) {
int x = FaweCache.CACHE_X[layer][j];
int y = FaweCache.CACHE_Y[layer][j];
int z = FaweCache.CACHE_Z[layer][j];
int id = currentIdArray[j] & 0xFF;
byte data = (byte) currentDataArray.a(x, y & 15, z);
previous.setBlock(x, y, z, id, data);
}
}
}
}
previous.ids = idPrevious;
if (tiles != null) {
for (Map.Entry<ChunkPosition, TileEntity> entry : tiles.entrySet()) {
TileEntity tile = entry.getValue();
NBTTagCompound tag = new NBTTagCompound();
ChunkPosition pos = entry.getKey();
CompoundTag nativeTag = getTag(tile);
previous.setTile(pos.x & 15, pos.y, pos.z & 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;
}
}
@Override
public CompoundTag getTileEntity(Chunk chunk, int x, int y, int z) {
Map<ChunkPosition, TileEntity> tiles = ((CraftChunk) chunk).getHandle().tileEntities;
ChunkPosition pos = new ChunkPosition(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) {
BukkitChunk_1_7 fs = (BukkitChunk_1_7) fc;
CraftChunk chunk = (CraftChunk) fs.getChunk();
net.minecraft.server.v1_7_R4.Chunk nmsChunk = chunk.getHandle();
nmsChunk.e(); // Modified
nmsChunk.mustSave = true;
net.minecraft.server.v1_7_R4.World nmsWorld = nmsChunk.world;
try {
final boolean flag = getWorld().getEnvironment() == World.Environment.NORMAL;
// Sections
ChunkSection[] sections = nmsChunk.getSections();
Map<ChunkPosition, TileEntity> tiles = nmsChunk.tileEntities;
Collection<net.minecraft.server.v1_7_R4.Entity>[] entities = nmsChunk.entitySlices;
// 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
Iterator<Map.Entry<ChunkPosition, TileEntity>> iterator = tiles.entrySet().iterator();
HashMap<ChunkPosition, TileEntity> toRemove = null;
while (iterator.hasNext()) {
Map.Entry<ChunkPosition, TileEntity> tile = iterator.next();
ChunkPosition pos = tile.getKey();
int lx = pos.x & 15;
int ly = pos.y;
int lz = pos.z & 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) {
if (toRemove == null) {
toRemove = new HashMap<>();
}
toRemove.put(tile.getKey(), tile.getValue());
}
}
if (toRemove != null) {
for (Map.Entry<ChunkPosition, TileEntity> entry : toRemove.entrySet()) {
ChunkPosition bp = entry.getKey();
TileEntity tile = entry.getValue();
tiles.remove(bp);
tile.s();
nmsWorld.p(bp.x, bp.y, bp.z);
tile.u();
}
}
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;
}
byte[] newIdArray = fs.getByteIdArray(j);
if (newIdArray == null) {
continue;
}
NibbleArray newDataArray = fs.getDataArray(j);
ChunkSection section = sections[j];
if ((section == null) || (fs.getCount(j) >= 4096)) {
sections[j] = section = new ChunkSection(j << 4, flag);
section.setIdArray(newIdArray);
section.setDataArray(newDataArray);
continue;
}
byte[] currentIdArray = section.getIdArray();
NibbleArray currentDataArray = section.getDataArray();
boolean data = currentDataArray != null;
if (!data) {
section.setDataArray(newDataArray);
}
boolean fill = true;
int solid = 0;
for (int k = 0; k < newIdArray.length; k++) {
byte n = newIdArray[k];
switch (n) {
case 0:
fill = false;
continue;
case -1:
fill = false;
if (currentIdArray[k] != 0) {
solid++;
}
currentIdArray[k] = 0;
continue;
default:
solid++;
currentIdArray[k] = n;
if (data) {
int x = FaweCache.CACHE_X[0][k];
int y = FaweCache.CACHE_Y[0][k];
int z = FaweCache.CACHE_Z[0][k];
int newData = newDataArray == null ? 0 : newDataArray.a(x, y, z);
int currentData = currentDataArray == null ? 0 : currentDataArray.a(x, y, z);
if (newData != currentData) {
currentDataArray.a(x, y, z, newData);
}
}
continue;
}
}
setCount(0, solid, section);
if (fill) {
fs.setCount(j, Short.MAX_VALUE);
}
}
// 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.m()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome; // Biome array
}
}
}
// 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();
TileEntity tileEntity = nmsWorld.getTileEntity(MathMan.unpair16x(pair.pair[0]) + bx, pair.pair[1] & 0xFF, MathMan.unpair16y(pair.pair[0]) + bz);
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_7_R4.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
ChunkCoordIntPair pos = nmsChunk.l(); // getPosition()
WorldServer w = (WorldServer) nmsChunk.world;
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 map = (LongHashMap) 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);
final HashSet<EntityPlayer> players = new HashSet<>((Collection<EntityPlayer>)fieldPlayers.get(playerChunk));
if (players.size() == 0) {
return;
}
HashSet<EntityTrackerEntry> entities = new HashSet<>();
List<Entity>[] entitieSlices = nmsChunk.entitySlices;
for (List<Entity> slice : entitieSlices) {
if (slice == null) {
continue;
}
for (Entity ent : slice) {
EntityTrackerEntry entry = (EntityTrackerEntry) 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, 25);
for (EntityPlayer player : players) {
player.playerConnection.sendPacket(packet);
}
// send ents
for (final 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 removeLighting(ChunkSection[] sections, RelightMode mode, boolean sky) {
if (mode == RelightMode.ALL) {
for (int i = 0; i < sections.length; i++) {
ChunkSection section = sections[i];
if (section != null) {
section.setEmittedLightArray(null);
if (sky) {
section.setSkyLightArray(null);
}
}
}
}
return true;
}
@Override
public World createWorld(final WorldCreator creator) {
final String name = creator.name();
ChunkGenerator generator = creator.generator();
final CraftServer server = (CraftServer) Bukkit.getServer();
final MinecraftServer console = server.getServer();
final File folder = new File(server.getWorldContainer(), name);
final World world = server.getWorld(name);
final WorldType type = WorldType.getType(creator.type().getName());
final boolean generateStructures = creator.generateStructures();
if (world != null) {
return world;
}
if (folder.exists() && !folder.isDirectory()) {
throw new IllegalArgumentException("File exists with the name '" + name + "' and isn't a folder");
}
if (generator == null) {
generator = server.getGenerator(name);
}
int dimension = 10 + console.worlds.size();
boolean used = false;
do {
for (final WorldServer ws : console.worlds) {
used = (ws.dimension == dimension);
if (used) {
++dimension;
break;
}
}
} while (used);
final boolean hardcore = false;
ServerNBTManager sdm = new ServerNBTManager(server.getWorldContainer(), name, true);
final WorldSettings worldSettings = new WorldSettings(creator.seed(), EnumGamemode.getById(server.getDefaultGameMode().getValue()), generateStructures, hardcore, type);
startSet(true);
final WorldServer internal = new WorldServer(console, sdm, name, dimension, worldSettings, console.methodProfiler, creator.environment(), generator);
endSet(true);
internal.scoreboard = server.getScoreboardManager().getMainScoreboard().getHandle();
internal.tracker = new EntityTracker(internal);
internal.addIWorldAccess(new WorldManager(console, internal));
internal.difficulty = EnumDifficulty.EASY;
internal.setSpawnFlags(true, true);
if (generator != null) {
internal.getWorld().getPopulators().addAll(generator.getDefaultPopulators(internal.getWorld()));
}
// Add the world
return TaskManager.IMP.sync(new RunnableVal<World>() {
@Override
public void run(World value) {
console.worlds.add(internal);
server.getPluginManager().callEvent(new WorldInitEvent(internal.getWorld()));
server.getPluginManager().callEvent(new WorldLoadEvent(internal.getWorld()));
this.value = internal.getWorld();
}
});
}
@Override
public boolean initLighting(Chunk chunk, ChunkSection[] sections, RelightMode mode) {
net.minecraft.server.v1_7_R4.Chunk c = ((CraftChunk) chunk).getHandle();
if (mode == RelightMode.ALL) {
c.initLighting();
} else {
int i = c.h();
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.b(x, y, z);
if (opacity == 0 && l != 15) {
opacity = 1;
}
l -= opacity;
if (l > 0) {
ChunkSection section = sections[y >> 4];
if (section != null) {
section.setSkyLight(x, y & 15, z, l);
}
}
--y;
} while (y > 0 && l > 0);
}
}
}
return true;
}
@Override
public int getSkyLight(ChunkSection[] sections, int x, int y, int z) {
ChunkSection section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 15;
}
return section.getSkyLight(x, y & 15, z);
}
@Override
public int getEmmittedLight(ChunkSection[] sections, int x, int y, int z) {
ChunkSection section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 0;
}
return section.getEmittedLight(x, y & 15, z);
}
@Override
public void relight(int x, int y, int z) {
nmsWorld.t(x, y, z);
}
private WorldServer nmsWorld;
@Override
public World getImpWorld() {
World world = super.getImpWorld();
this.nmsWorld = ((CraftWorld) world).getHandle();
return super.getImpWorld();
}
@Override
public FaweChunk getFaweChunk(int x, int z) {
return new CharFaweChunk<Chunk>(this, x, z) {
@Override
public Chunk getNewChunk() {
return BukkitQueue17.this.getWorld().getChunkAt(getX(), getZ());
}
};
}
}

View File

@ -0,0 +1,122 @@
name: FastAsyncWorldEdit
main: com.boydti.fawe.bukkit.v1_7.BukkitMain_17
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
fawe.voxelbrush:
default: op
children:
voxelsniper.brush.ball: true
voxelsniper.brush.biome: true
voxelsniper.brush.blendball: true
voxelsniper.brush.blenddisc: true
voxelsniper.brush.blendvoxel: true
voxelsniper.brush.blendvoxeldisc: true
voxelsniper.brush.blob: true
voxelsniper.brush.blockreset: true
voxelsniper.brush.blockresetsurface: true
voxelsniper.brush.canyon: true
voxelsniper.brush.canyonselection: true
voxelsniper.brush.checkervoxeldisc: true
voxelsniper.brush.cleansnow: true
voxelsniper.brush.clonestamp: true
voxelsniper.brush.copypasta: true
voxelsniper.brush.cylinder: true
voxelsniper.brush.disc: true
voxelsniper.brush.discface: true
voxelsniper.brush.dome: true
voxelsniper.brush.drain: true
voxelsniper.brush.ellipse: true
voxelsniper.brush.ellipsoid: true
voxelsniper.brush.eraser: true
voxelsniper.brush.erode: true
voxelsniper.brush.extrude: true
voxelsniper.brush.filldown: true
voxelsniper.brush.flatocean: true
voxelsniper.brush.heatray: true
voxelsniper.brush.jaggedline: true
voxelsniper.brush.line: true
voxelsniper.brush.move: true
voxelsniper.brush.ocean: true
voxelsniper.brush.overlay: true
voxelsniper.brush.pull: true
voxelsniper.brush.randomerode: true
voxelsniper.brush.ring: true
voxelsniper.brush.rot2d: true
voxelsniper.brush.rot2dvert: true
voxelsniper.brush.rot3d: true
voxelsniper.brush.ruler: true
voxelsniper.brush.scanner: true
voxelsniper.brush.set: true
voxelsniper.brush.setredstoneflip: true
voxelsniper.brush.setredstonerotate: true
voxelsniper.brush.shellball: true
voxelsniper.brush.shellset: true
voxelsniper.brush.shellvoxel: true
voxelsniper.brush.signoverwrite: true
voxelsniper.brush.snipe: true
voxelsniper.brush.snowcone: true
voxelsniper.brush.spiralstaircase: true
voxelsniper.brush.splatterball: true
voxelsniper.brush.splatterdisc: true
voxelsniper.brush.splatteroverlay: true
voxelsniper.brush.splattervoxel: true
voxelsniper.brush.splattervoxeldisc: true
voxelsniper.brush.spline: true
voxelsniper.brush.stamp: true
voxelsniper.brush.stencil: true
voxelsniper.brush.stencillist: true
voxelsniper.brush.threepointcircle: true
voxelsniper.brush.triangle: true
voxelsniper.brush.underlay: true
voxelsniper.brush.voltmeter: true
voxelsniper.brush.voxel: true
voxelsniper.brush.voxeldisc: true
voxelsniper.brush.voxeldiscface: true
voxelsniper.brush.warp: true
voxelsniper.goto: true
voxelsniper.sniper: true

View File

@ -6,7 +6,6 @@ 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;
@ -17,8 +16,10 @@ import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.internal.Constants;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@ -35,20 +36,32 @@ 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.EnumDifficulty;
import net.minecraft.server.v1_8_R3.LongHashMap;
import net.minecraft.server.v1_8_R3.MinecraftServer;
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.ServerNBTManager;
import net.minecraft.server.v1_8_R3.TileEntity;
import net.minecraft.server.v1_8_R3.WorldData;
import net.minecraft.server.v1_8_R3.WorldManager;
import net.minecraft.server.v1_8_R3.WorldServer;
import net.minecraft.server.v1_8_R3.WorldSettings;
import net.minecraft.server.v1_8_R3.WorldType;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.craftbukkit.v1_8_R3.CraftChunk;
import org.bukkit.craftbukkit.v1_8_R3.CraftServer;
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.generator.ChunkGenerator;
public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]> {
@ -76,6 +89,17 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
return getCachedSections(world, x, z) != null;
}
@Override
public void setFullbright(ChunkSection[] sections) {
for (int i = 0; i < sections.length; i++) {
ChunkSection section = sections[i];
if (section != null) {
byte[] bytes = section.getSkyLightArray().a();
Arrays.fill(bytes, Byte.MAX_VALUE);
}
}
}
@Override
public ChunkSection[] getCachedSections(World world, int x, int z) {
Chunk chunk = world.getChunkAt(x, z);
@ -200,6 +224,8 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
CharFaweChunk<Chunk> fs = (CharFaweChunk<Chunk>) fc;
CraftChunk chunk = (CraftChunk) fs.getChunk();
net.minecraft.server.v1_8_R3.Chunk nmsChunk = chunk.getHandle();
nmsChunk.f(true); // Modified
nmsChunk.mustSave = true;
net.minecraft.server.v1_8_R3.World nmsWorld = nmsChunk.getWorld();
try {
final boolean flag = getWorld().getEnvironment() == World.Environment.NORMAL;
@ -478,167 +504,150 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
}
@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();
final boolean flag = craftChunk.getWorld().getEnvironment() == World.Environment.NORMAL;
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());
}
public boolean removeLighting(ChunkSection[] sections, RelightMode mode, boolean sky) {
if (mode == RelightMode.ALL) {
for (int i = 0; i < sections.length; i++) {
ChunkSection section = sections[i];
if (section != null) {
section.a(new NibbleArray());
if (sky) {
section.b(new NibbleArray());
}
}
}
if (flag) {
if (mode == RelightMode.ALL) {
nmsChunk.initLighting();
} else {
int i = nmsChunk.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 = nmsChunk.getTypeAbs(x, y, z).p();
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 (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 (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 (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:
case 213:
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;
return true;
}
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));
@Override
public World createWorld(final WorldCreator creator) {
final String name = creator.name();
ChunkGenerator generator = creator.generator();
final CraftServer server = (CraftServer) Bukkit.getServer();
final MinecraftServer console = server.getServer();
final File folder = new File(server.getWorldContainer(), name);
final World world = server.getWorld(name);
final WorldType type = WorldType.getType(creator.type().getName());
final boolean generateStructures = creator.generateStructures();
if (world != null) {
return world;
}
if (folder.exists() && !folder.isDirectory()) {
throw new IllegalArgumentException("File exists with the name '" + name + "' and isn't a folder");
}
if (generator == null) {
generator = server.getGenerator(name);
}
int dimension = 10 + console.worlds.size();
boolean used = false;
do {
for (final WorldServer ws : console.worlds) {
used = (ws.dimension == dimension);
if (used) {
++dimension;
break;
}
}
} while (used);
final boolean hardcore = false;
ServerNBTManager sdm = new ServerNBTManager(server.getWorldContainer(), name, true);
WorldData worlddata = sdm.getWorldData();
final WorldSettings worldSettings;
if (worlddata == null) {
worldSettings = new WorldSettings(creator.seed(), WorldSettings.EnumGamemode.getById(server.getDefaultGameMode().getValue()), generateStructures, hardcore, type);
worldSettings.setGeneratorSettings(creator.generatorSettings());
worlddata = new WorldData(worldSettings, name);
} else {
worldSettings = null;
}
worlddata.checkName(name);
final WorldServer internal = (WorldServer)new WorldServer(console, sdm, worlddata, dimension, console.methodProfiler, creator.environment(), generator).b();
startSet(true); // Temporarily allow async chunk load since the world isn't added yet
internal.a(worldSettings);
endSet(true);
internal.scoreboard = server.getScoreboardManager().getMainScoreboard().getHandle();
internal.tracker = new EntityTracker(internal);
internal.addIWorldAccess(new WorldManager(console, internal));
internal.worldData.setDifficulty(EnumDifficulty.EASY);
internal.setSpawnFlags(true, true);
if (generator != null) {
internal.getWorld().getPopulators().addAll(generator.getDefaultPopulators(internal.getWorld()));
}
// Add the world
return TaskManager.IMP.sync(new RunnableVal<World>() {
@Override
public void run(World value) {
console.worlds.add(internal);
server.getPluginManager().callEvent(new WorldInitEvent(internal.getWorld()));
server.getPluginManager().callEvent(new WorldLoadEvent(internal.getWorld()));
this.value = internal.getWorld();
}
});
}
public boolean isSolid(int i) {
return Material.getMaterial(i).isOccluding();
@Override
public boolean initLighting(Chunk chunk, ChunkSection[] sections, RelightMode mode) {
net.minecraft.server.v1_8_R3.Chunk c = ((CraftChunk) chunk).getHandle();
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.getTypeAbs(x, y, z).p();
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);
}
}
}
return true;
}
public int getId(ChunkSection[] sections, int x, int y, int z) {
if (x < 0 || x > 15 || z < 0 || z > 15) {
return 1;
@Override
public int getSkyLight(ChunkSection[] sections, int x, int y, int z) {
ChunkSection section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 15;
}
if (y < 0 || y > 255) {
return 1;
}
int i = FaweCache.CACHE_I[y][x][z];
ChunkSection section = sections[i];
return section.d(x, y & 15, z);
}
@Override
public int getEmmittedLight(ChunkSection[] sections, int x, int y, int z) {
ChunkSection section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 0;
}
char[] array = section.getIdArray();
int j = FaweCache.CACHE_J[y][x][z];
return array[j] >> 4;
return section.e(x, y & 15, z);
}
@Override
public void relight(int x, int y, int z) {
pos.c(x, y, z);
nmsWorld.x(pos);
}
private WorldServer nmsWorld;
@Override
public World getImpWorld() {
World world = super.getImpWorld();
this.nmsWorld = ((CraftWorld) world).getHandle();
return super.getImpWorld();
}
@Override

View File

@ -6,7 +6,6 @@ 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;
@ -18,9 +17,11 @@ import com.sk89q.jnbt.LongTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.internal.Constants;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@ -44,22 +45,36 @@ import net.minecraft.server.v1_9_R2.EntityPlayer;
import net.minecraft.server.v1_9_R2.EntityTracker;
import net.minecraft.server.v1_9_R2.EntityTrackerEntry;
import net.minecraft.server.v1_9_R2.EntityTypes;
import net.minecraft.server.v1_9_R2.EnumDifficulty;
import net.minecraft.server.v1_9_R2.IBlockData;
import net.minecraft.server.v1_9_R2.IDataManager;
import net.minecraft.server.v1_9_R2.MinecraftServer;
import net.minecraft.server.v1_9_R2.NBTTagCompound;
import net.minecraft.server.v1_9_R2.NibbleArray;
import net.minecraft.server.v1_9_R2.PacketPlayOutEntityDestroy;
import net.minecraft.server.v1_9_R2.PacketPlayOutMapChunk;
import net.minecraft.server.v1_9_R2.PlayerChunk;
import net.minecraft.server.v1_9_R2.PlayerChunkMap;
import net.minecraft.server.v1_9_R2.ServerNBTManager;
import net.minecraft.server.v1_9_R2.TileEntity;
import net.minecraft.server.v1_9_R2.WorldData;
import net.minecraft.server.v1_9_R2.WorldManager;
import net.minecraft.server.v1_9_R2.WorldServer;
import net.minecraft.server.v1_9_R2.WorldSettings;
import net.minecraft.server.v1_9_R2.WorldType;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.WorldCreator;
import org.bukkit.block.Biome;
import org.bukkit.craftbukkit.v1_9_R2.CraftChunk;
import org.bukkit.craftbukkit.v1_9_R2.CraftServer;
import org.bukkit.craftbukkit.v1_9_R2.CraftWorld;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.world.WorldInitEvent;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.generator.ChunkGenerator;
public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], DataPaletteBlock> {
@ -187,142 +202,161 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
}
@Override
public boolean fixLighting(final FaweChunk pc, RelightMode mode) {
if (mode == RelightMode.NONE) {
return true;
public World createWorld(final WorldCreator creator) {
final String name = creator.name();
ChunkGenerator generator = creator.generator();
final CraftServer server = (CraftServer) Bukkit.getServer();
final MinecraftServer console = server.getServer();
final File folder = new File(server.getWorldContainer(), name);
final World world = server.getWorld(name);
final WorldType type = WorldType.getType(creator.type().getName());
final boolean generateStructures = creator.generateStructures();
if (world != null) {
return world;
}
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_9_R2.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 (folder.exists() && !folder.isDirectory()) {
throw new IllegalArgumentException("File exists with the name '" + name + "' and isn't a folder");
}
if (generator == null) {
generator = server.getGenerator(name);
}
int dimension = 10 + console.worlds.size();
boolean used = false;
do {
for (final WorldServer ws : console.worlds) {
used = (ws.dimension == dimension);
if (used) {
++dimension;
break;
}
}
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);
}
}
}
} while (used);
final boolean hardcore = false;
final IDataManager sdm = new ServerNBTManager(server.getWorldContainer(), name, true, server.getHandle().getServer().getDataConverterManager());
WorldData worlddata = sdm.getWorldData();
final WorldSettings worldSettings;
if (worlddata == null) {
worldSettings = new WorldSettings(creator.seed(), WorldSettings.EnumGamemode.getById(server.getDefaultGameMode().getValue()), generateStructures, hardcore, type);
worldSettings.setGeneratorSettings(creator.generatorSettings());
worlddata = new WorldData(worldSettings, name);
} else {
worldSettings = null;
}
worlddata.checkName(name);
final WorldServer internal = (WorldServer)new WorldServer(console, sdm, worlddata, dimension, console.methodProfiler, creator.environment(), generator).b();
startSet(true); // Temporarily allow async chunk load since the world isn't added yet
internal.a(worldSettings);
endSet(true);
internal.scoreboard = server.getScoreboardManager().getMainScoreboard().getHandle();
internal.tracker = new EntityTracker(internal);
internal.addIWorldAccess(new WorldManager(console, internal));
internal.worldData.setDifficulty(EnumDifficulty.EASY);
internal.setSpawnFlags(true, true);
if (generator != null) {
internal.getWorld().getPopulators().addAll(generator.getDefaultPopulators(internal.getWorld()));
}
// Add the world
return TaskManager.IMP.sync(new RunnableVal<World>() {
@Override
public void run(World value) {
console.worlds.add(internal);
server.getPluginManager().callEvent(new WorldInitEvent(internal.getWorld()));
server.getPluginManager().callEvent(new WorldLoadEvent(internal.getWorld()));
this.value = internal.getWorld();
}
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_9_R2.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:
case 213:
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);
});
}
@Override
public void setFullbright(ChunkSection[] sections) {
for (int i = 0; i < sections.length; i++) {
ChunkSection section = sections[i];
if (section != null) {
byte[] bytes = section.getSkyLightArray().asBytes();
Arrays.fill(bytes, Byte.MAX_VALUE);
}
}
return false;
}
@Override
public boolean removeLighting(ChunkSection[] sections, RelightMode mode, boolean sky) {
if (mode == RelightMode.ALL) {
for (int i = 0; i < sections.length; i++) {
ChunkSection section = sections[i];
if (section != null) {
section.a(new NibbleArray());
if (sky) {
section.b(new NibbleArray());
}
}
}
}
return true;
}
@Override
public boolean initLighting(Chunk chunk, ChunkSection[] sections, RelightMode mode) {
net.minecraft.server.v1_9_R2.Chunk c = ((CraftChunk) chunk).getHandle();
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);
}
}
}
return true;
}
@Override
public int getSkyLight(ChunkSection[] sections, int x, int y, int z) {
ChunkSection section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 15;
}
return section.b(x, y & 15, z);
}
@Override
public int getEmmittedLight(ChunkSection[] sections, int x, int y, int z) {
ChunkSection section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 0;
}
return section.c(x, y & 15, z);
}
@Override
public void relight(int x, int y, int z) {
pos.c(x, y, z);
nmsWorld.w(pos);
}
private WorldServer nmsWorld;
@Override
public World getImpWorld() {
World world = super.getImpWorld();
this.nmsWorld = ((CraftWorld) world).getHandle();
return super.getImpWorld();
}
public boolean isSurrounded(final char[][] sections, final int x, final int y, final int z) {
@ -333,12 +367,8 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
&& 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 boolean isSolid(final int id) {
return !FaweCache.isTransparent(id);
}
public int getId(final char[][] sections, final int x, final int y, final int z) {
@ -510,6 +540,8 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
try {
final boolean flag = world.getEnvironment() == Environment.NORMAL;
net.minecraft.server.v1_9_R2.Chunk nmsChunk = ((CraftChunk) chunk).getHandle();
nmsChunk.f(true); // Modified
nmsChunk.mustSave = true;
net.minecraft.server.v1_9_R2.World nmsWorld = nmsChunk.world;
ChunkSection[] sections = nmsChunk.getSections();
Class<? extends net.minecraft.server.v1_9_R2.Chunk> clazzChunk = nmsChunk.getClass();

View File

@ -2,6 +2,8 @@ package com.boydti.fawe;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweLocation;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue;
@ -24,12 +26,14 @@ import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.ShortTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.World;
import java.io.File;
@ -368,6 +372,86 @@ public class FaweAPI {
queue.fixLighting(queue.getFaweChunk(chunk.getX(), chunk.getZ()), mode);
}
/**
* Fix the lighting in a selection<br>
* - First removes all lighting, then relights
* - Relights in parallel (if enabled) for best performance<br>
* - Also resends chunks<br>
* @param world
* @param selection (assumes cuboid)
* @return
*/
public static int fixLighting(String world, Region selection) {
final Vector bot = selection.getMinimumPoint();
final Vector top = selection.getMaximumPoint();
final int minX = bot.getBlockX() >> 4;
final int minZ = bot.getBlockZ() >> 4;
final int maxX = top.getBlockX() >> 4;
final int maxZ = top.getBlockZ() >> 4;
int count = 0;
final FaweQueue queue = SetQueue.IMP.getNewQueue(world, true, false);
// Remove existing lighting first
if (queue instanceof NMSMappedFaweQueue) {
final NMSMappedFaweQueue nmsQueue = (NMSMappedFaweQueue) queue;
boolean sky = nmsQueue.hasSky();
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z ++) {
if (!nmsQueue.isChunkLoaded(x, z)) {
final int xf = x;
final int zf = z;
if (!TaskManager.IMP.syncWhenFree(new RunnableVal<Boolean>() {
@Override
public void run(Boolean value) {
this.value = nmsQueue.loadChunk(nmsQueue.getWorld(), xf, zf, false);
}
})) {
continue;
}
}
Object sections = nmsQueue.getCachedSections(nmsQueue.getWorld(), x, z);
nmsQueue.removeLighting(sections, FaweQueue.RelightMode.ALL, sky);
}
}
}
ArrayList<Thread> threads = new ArrayList<>();
for (int X = 0; X < 2; X++) {
for (int Z = 0; Z < 2; Z++) {
for (int x = minX + X; x <= maxX; x += 2) {
for (int z = minZ + Z; z <= maxZ; z += 2) {
final FaweChunk<?> chunk = queue.getFaweChunk(x, z);
if (Settings.LIGHTING.ASYNC) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
queue.fixLightingSafe(chunk, FaweQueue.RelightMode.ALL);
queue.sendChunk(chunk, FaweQueue.RelightMode.NONE);
}
});
thread.start();
threads.add(thread);
} else {
queue.fixLightingSafe(chunk, FaweQueue.RelightMode.ALL);
queue.sendChunk(chunk, FaweQueue.RelightMode.NONE);
}
count++;
}
}
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
threads.clear();
}
}
return count;
}
/**
* If a schematic is too large to be pasted normally<br>
* - Skips any block history

View File

@ -245,6 +245,138 @@ public class FaweCache {
CACHE_COLOR[getCombined(35, 15)] = new Color(0, 0, 0); // Black
}
public static LightType getLight(int id) {
switch (id) { // Lighting
case 0:
case 6:
case 27:
case 28:
case 31:
case 32:
case 37:
case 38:
case 55:
case 59:
case 65:
case 66:
case 69:
case 75:
case 77:
case 78:
case 83:
case 90:
case 93:
case 94:
case 104:
case 105:
case 106:
case 111:
case 115:
case 119:
case 127:
case 131:
case 132:
case 140:
case 141:
case 142:
case 143:
case 144:
case 149:
case 150:
case 157:
case 171:
case 175:
case 198:
case 199:
case 200:
case 207:
case 209:
case 217:
return LightType.TRANSPARENT;
case 39:
case 40:
case 50:
case 51:
case 76:
return LightType.TRANSPARENT_EMIT;
case 10:
case 11:
case 62:
case 74:
case 89:
case 122:
case 124:
case 130:
case 138:
case 169:
case 213:
return LightType.SOLID_EMIT;
default:
return LightType.OCCLUDING;
}
}
public enum LightType {
TRANSPARENT, OCCLUDING, SOLID_EMIT, TRANSPARENT_EMIT
}
public static boolean isTransparent(int id) {
switch (id) {
case 0:
case 6:
case 27:
case 28:
case 31:
case 32:
case 37:
case 38:
case 39:
case 40:
case 50:
case 51:
case 55:
case 59:
case 65:
case 66:
case 69:
case 75:
case 76:
case 77:
case 78:
case 83:
case 90:
case 93:
case 94:
case 104:
case 105:
case 106:
case 111:
case 115:
case 119:
case 127:
case 131:
case 132:
case 140:
case 141:
case 142:
case 143:
case 144:
case 149:
case 150:
case 157:
case 171:
case 175:
case 198:
case 199:
case 200:
case 207:
case 209:
case 217:
return true;
default: return false;
}
}
/**
* Check if an id might have data
* @param id

View File

@ -1,11 +1,10 @@
package com.boydti.fawe.command;
import com.boydti.fawe.FaweAPI;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FaweLocation;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.util.SetQueue;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
@ -29,25 +28,8 @@ public class FixLighting extends FaweCommand {
if (selection == null) {
selection = new CuboidRegion(new Vector(cx - 8, 0, cz - 8).multiply(16), new Vector(cx + 8, 0, cz + 8).multiply(16));
}
final Vector bot = selection.getMinimumPoint();
final Vector top = selection.getMaximumPoint();
final int minX = bot.getBlockX() >> 4;
final int minZ = bot.getBlockZ() >> 4;
final int maxX = top.getBlockX() >> 4;
final int maxZ = top.getBlockZ() >> 4;
int count = 0;
FaweQueue queue = SetQueue.IMP.getNewQueue(loc.world, true, false);
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
queue.sendChunk(queue.getFaweChunk(x, z), FaweQueue.RelightMode.ALL);
count++;
}
}
int count = FaweAPI.fixLighting(loc.world, selection);
BBC.FIX_LIGHTING_SELECTION.send(player, count);
return true;
}
}

View File

@ -202,10 +202,21 @@ public class Settings extends Config {
}
public static class LIGHTING {
@Comment("If chunk lighting should be done asynchronously")
@Comment({
"If chunk lighting should be done asynchronously:",
" - Async lighting is less intense, but more likely to glitch"
})
public static boolean ASYNC = true;
@Comment("If all lighting should be fixed in a chunk that is edited")
public static boolean FIX_ALL = true;
@Comment({
"The relighting mode to use:",
" - 0 = None (Do no relighting)",
" - 1 = Shadowless (Removes shadows)",
" - 2 = Minimal (Relight changed light sources)",
" - 3 = Fullbright (Relight changed light sources, remove shadows)",
" - 4 = Optimal (Relight changed light sources and changed blocks)",
" - 5 = All (Slowly relight every blocks)"
})
public static int MODE = 4;
}
public static void save(File file) {

View File

@ -120,6 +120,15 @@ public abstract class CharFaweChunk<T> extends FaweChunk<T> {
return this.biomes;
}
public int getCombinedId(int x, int y, int z) {
short i = FaweCache.CACHE_I[y][x][z];
char[] array = getIdArray(i);
if (array == null) {
return 0;
}
return array[FaweCache.CACHE_J[y][x][z]];
}
public HashMap<BytePair, CompoundTag> tiles;
@Override

View File

@ -69,7 +69,7 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
super(world);
}
public abstract WORLD getWorld(String world);
public abstract WORLD getImpWorld();
public abstract boolean isChunkLoaded(WORLD world, int x, int z);
@ -93,7 +93,7 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
if (impWorld != null) {
return impWorld;
}
return impWorld = getWorld(super.getWorldName());
return impWorld = getImpWorld();
}
@Override

View File

@ -1,5 +1,7 @@
package com.boydti.fawe.example;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.FaweQueue;
@ -29,7 +31,7 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
@Override
public void sendChunk(final FaweChunk fc, RelightMode mode) {
if (mode == null) {
mode = Settings.LIGHTING.FIX_ALL ? FaweQueue.RelightMode.OPTIMAL : FaweQueue.RelightMode.MINIMAL;
mode = FaweQueue.RelightMode.values()[Settings.LIGHTING.MODE];
}
final RelightMode finalMode = mode;
TaskManager.IMP.taskSoonMain(new Runnable() {
@ -56,6 +58,197 @@ public abstract class NMSMappedFaweQueue<WORLD, CHUNK, CHUNKSECTION, SECTION> ex
}, Settings.LIGHTING.ASYNC);
}
public abstract boolean hasSky();
public abstract void setFullbright(CHUNKSECTION sections);
public abstract boolean removeLighting(CHUNKSECTION sections, RelightMode mode, boolean hasSky);
public abstract boolean initLighting(CHUNK chunk, CHUNKSECTION sections, RelightMode mode);
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 id) {
return !FaweCache.isTransparent(id);
}
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 abstract void relight(int x, int y, int z);
public abstract int getSkyLight(CHUNKSECTION sections, int x, int y, int z);
public abstract int getEmmittedLight(CHUNKSECTION sections, int x, int y, int z);
public int getLight(CHUNKSECTION sections, int x, int y, int z) {
if (!hasSky()) {
return getEmmittedLight(sections, x, y, z);
}
return Math.max(getSkyLight(sections, x, y, z), getEmmittedLight(sections, x, y, z));
}
@Override
public boolean fixLighting(FaweChunk<?> fc, RelightMode mode) {
if (mode == RelightMode.NONE) {
return true;
}
try {
boolean async = Fawe.get().getMainThread() != Thread.currentThread();
int cx = fc.getX();
int cz = fc.getZ();
if (!isChunkLoaded(cx, cz)) {
if (async) {
return false;
}
loadChunk(getWorld(), cx, cz, false);
}
CHUNKSECTION sections = getCachedSections(getWorld(), cx, cz);
boolean hasSky = hasSky();
if (mode.ordinal() < 3) {
if (hasSky) {
setFullbright(sections);
}
}
CHUNK impChunk = (CHUNK) fc.getChunk();
removeLighting(sections, mode, hasSky);
if (hasSky) {
initLighting(impChunk, sections, mode);
}
if (mode == RelightMode.SHADOWLESS) {
return true;
}
CharFaweChunk bc = (CharFaweChunk) fc;
if (((bc.getTotalRelight() != 0) || mode.ordinal() > 3)) {
if (mode == RelightMode.ALL) {
bc = getPrevious(bc, sections, null, null, null, true);
}
int total = bc.getTotalCount();
final int X = cx << 4;
final int Z = cz << 4;
for (int j = 15; j >= 0; j--) {
if (((bc.getRelight(j) == 0) && mode.ordinal() <= 3) || (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;
}
switch (mode) {
case ALL: {
for (int k = 4095; k >= 0; k--) {
final int x = FaweCache.CACHE_X[j][k];
final int y = FaweCache.CACHE_Y[j][k];
if (y == 0) {
continue;
}
final int z = FaweCache.CACHE_Z[j][k];
final int i = array[k];
final short id = (short) (i >> 4);
switch (FaweCache.getLight(id)) {
case OCCLUDING:
if (y == 0 || !FaweCache.isTransparent(bc.getCombinedId(x, y - 1, z) >> 4)) {
continue;
}
break;
case TRANSPARENT_EMIT:
case SOLID_EMIT:
if (this.isSurrounded(bc.getCombinedIdArrays(), x, y, z)) {
continue;
}
break;
case TRANSPARENT:
if (y >= 255) {
continue;
}
int light = getSkyLight(sections, x, y, z);
if (light != 0) {
continue;
}
break;
}
relight(X + x, y, Z + z);
}
break;
}
case OPTIMAL: {
for (int k = 4095; k >= 0; k--) {
final int x = FaweCache.CACHE_X[j][k];
final int y = FaweCache.CACHE_Y[j][k];
if (y == 0) {
continue;
}
final int z = FaweCache.CACHE_Z[j][k];
final int i = array[k];
final short id = (short) (i >> 4);
switch (FaweCache.getLight(id)) {
case OCCLUDING:
if (y == 0 || !FaweCache.isTransparent(bc.getCombinedId(x, y - 1, z) >> 4)) {
continue;
}
break;
case TRANSPARENT_EMIT:
case SOLID_EMIT:
if (this.isSurrounded(bc.getCombinedIdArrays(), x, y, z)) {
continue;
}
break;
case TRANSPARENT:
continue;
}
relight(X + x, y, Z + z);
}
break;
}
case FULLBRIGHT:
case MINIMAL: {
for (int k = 4095; 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];
final int i = array[k];
final short id = (short) (i >> 4);
switch (FaweCache.getLight(id)) {
case TRANSPARENT:
case OCCLUDING:
continue;
case TRANSPARENT_EMIT:
case SOLID_EMIT:
if (this.isSurrounded(bc.getCombinedIdArrays(), x, y, z)) {
continue;
}
}
relight(X + x, y, Z + z);
}
break;
}
}
}
}
return true;
} catch (Throwable ignore) {}
return false;
}
public abstract void refreshChunk(WORLD world, CHUNK chunk);
public abstract CharFaweChunk getPrevious(CharFaweChunk fs, CHUNKSECTION sections, Map<?, ?> tiles, Collection<?>[] entities, Set<UUID> createdEntities, boolean all) throws Exception;

View File

@ -82,7 +82,7 @@ public abstract class FaweChunk<T> {
* Fix the lighting in this chunk
*/
public void fixLighting() {
parent.fixLighting(this, Settings.LIGHTING.FIX_ALL ? FaweQueue.RelightMode.OPTIMAL : FaweQueue.RelightMode.MINIMAL);
parent.fixLighting(this, FaweQueue.RelightMode.values()[Settings.LIGHTING.MODE]);
}
/**

View File

@ -23,9 +23,16 @@ public abstract class FaweCommand<T> {
public boolean executeSafe(final FawePlayer<T> player, final String... args) {
try {
if (player == null || !safe) {
if (!safe) {
execute(player, args);
return true;
} else if (player == null) {
TaskManager.IMP.async(new Runnable() {
@Override
public void run() {
execute(player, args);
}
});
} else {
if (player.getMeta("fawe_action") != null) {
BBC.WORLDEDIT_COMMAND_LIMIT.send(player);

View File

@ -104,6 +104,9 @@ public abstract class FawePlayer<T> {
public FawePlayer(final T parent) {
this.parent = parent;
Fawe.get().register(this);
if (Settings.CLIPBOARD.USE_DISK) {
loadClipboardFromDisk();
}
if (getSession() == null || getPlayer() == null || session.getSize() != 0 || !Settings.HISTORY.USE_DISK) {
return;
}
@ -117,7 +120,6 @@ public abstract class FawePlayer<T> {
loadSessionsFromDisk(world);
}
}
loadClipboardFromDisk();
} catch (Exception e) {
MainUtil.handleError(e);
Fawe.debug("Failed to load history for: " + getName());
@ -125,7 +127,8 @@ public abstract class FawePlayer<T> {
}
public void loadClipboardFromDisk() {
File file = new File(Fawe.imp().getDirectory(), "clipboard" + File.separator + getUUID());
System.out.println("LOADING CLIPBOARD FROM DISK");
File file = new File(Fawe.imp().getDirectory(), "clipboard" + File.separator + getUUID() + ".bd");
try {
if (file.exists() && file.length() > 5) {
DiskOptimizedClipboard doc = new DiskOptimizedClipboard(file);
@ -143,6 +146,8 @@ public abstract class FawePlayer<T> {
ClipboardHolder holder = new ClipboardHolder(clip, worldData);
getSession().setClipboard(holder);
}
} else {
System.out.println("FILE: " + file.exists() + " | " + file + " | " + file.length());
}
} catch (Exception ignore) {
Fawe.debug("====== INVALID CLIPBOARD ======");

View File

@ -2,6 +2,7 @@ package com.boydti.fawe.object;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.exception.FaweException;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MemUtil;
@ -36,7 +37,9 @@ public abstract class FaweQueue {
public enum RelightMode {
NONE,
SHADOWLESS,
MINIMAL,
FULLBRIGHT,
OPTIMAL,
ALL,
}
@ -129,6 +132,25 @@ public abstract class FaweQueue {
public abstract void setChunk(final FaweChunk<?> chunk);
public boolean fixLightingSafe(final FaweChunk<?> chunk, final RelightMode mode) {
if (Settings.LIGHTING.ASYNC || Fawe.get().isMainThread()) {
try {
if (fixLighting(chunk, mode)) {
return true;
}
if (Fawe.get().isMainThread()) {
return false;
}
} catch (Throwable ignore) {}
}
return TaskManager.IMP.syncWhenFree(new RunnableVal<Boolean>() {
@Override
public void run(Boolean value) {
this.value = fixLighting(chunk, mode);
}
});
}
public abstract boolean fixLighting(final FaweChunk<?> chunk, RelightMode mode);
public abstract boolean isChunkLoaded(final int x, final int z);

View File

@ -31,7 +31,7 @@ import java.util.UUID;
/**
* A clipboard with disk backed storage. (lower memory + loads on crash)
* - Uses an auto closable RandomAccessFile for getting / setting id / data
* - I don't know how to reduce nbt / entities to O(1) complexity, so it is stored in memory.
* - I don't know how to reduce nbt / entities to O(2) complexity, so it is stored in memory.
*
* TODO load on join
*/
@ -69,9 +69,10 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
long size = (raf.length() - HEADER_SIZE) >> 1;
raf.seek(2);
last = -1;
width = raf.readChar();
height = raf.readChar();
length = raf.readChar();
width = (int) raf.readChar();
height = (int) raf.readChar();
length = (int) raf.readChar();
System.out.println("DIMENSIONS " + width + " | " + height + " | " + length);
area = width * length;
autoCloseTask();
}
@ -151,11 +152,13 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
length = dimensions.getBlockZ();
long size = width * height * length * 2l + HEADER_SIZE;
raf.setLength(size);
raf.seek(1);
last = -0;
raf.seek(2);
last = -1;
System.out.println("SET DIMENSIONS: " + width + "," + height + "," + length);
raf.writeChar(width);
raf.writeChar(height);
raf.writeChar(length);
raf.flush();
} catch (IOException e) {
MainUtil.handleError(e);
}
@ -198,8 +201,9 @@ public class DiskOptimizedClipboard extends FaweClipboard implements Closeable {
if (raf.length() != size) {
raf.setLength(size);
// write length etc
raf.seek(1);
raf.seek(2);
last = -1;
System.out.println("SET DIMENSIONS 2: " + width + "," + height + "," + length);
raf.writeChar(width);
raf.writeChar(height);
raf.writeChar(length);

View File

@ -6,7 +6,8 @@ public class FaweTimer implements Runnable {
private int historyIndex = 0;
private long lastPoll = System.currentTimeMillis();
private long tickStart = System.currentTimeMillis();
private final long tickInterval = 50;
private final long tickInterval = 5;
private final double millisPer20Interval = tickInterval * 50 * 20;
private long tick = 0;
private long tickMod = 0;
@ -24,7 +25,7 @@ public class FaweTimer implements Runnable {
{
timeSpent = 1;
}
double tps = tickInterval * 1000000.0 / timeSpent;
double tps = millisPer20Interval / timeSpent;
history[historyIndex++] = tps;
if (historyIndex >= history.length) {
historyIndex = 0;
@ -66,7 +67,7 @@ public class FaweTimer implements Runnable {
}
return false;
}
if (getTickMillis() < 50 || getTPS() < tps) {
if (getTickMillis() > 100 || getTPS() < tps) {
skip = 10;
skipTick = tick;
}

View File

@ -47,6 +47,10 @@ public class MathMan {
return (((long)x) << 32) | (y & 0xffffffffL);
}
public static long chunkXZ2Int(int x, int z) {
return (long)x & 4294967295L | ((long)z & 4294967295L) << 32;
}
public static int unpairIntX(long pair) {
return (int)(pair >> 32);
}

View File

@ -62,7 +62,7 @@ public class SetQueue {
@Override
public void run() {
while (!tasks.isEmpty() && Fawe.get().getTimer().isAbove(18.5)) {
Runnable task = tasks.poll();
tasks.poll().run();
}
if (inactiveQueues.isEmpty() && activeQueues.isEmpty()) {
lastSuccess = System.currentTimeMillis();

View File

@ -236,6 +236,10 @@ public abstract class TaskManager {
}
}
public <T> T syncWhenFree(final RunnableVal<T> function) {
return syncWhenFree(function, Integer.MAX_VALUE);
}
/**
* Run a task on the main thread when the TPS is high enough, and wait for execution to finish:<br>
* - Useful if you need to access something from the Bukkit API from another thread<br>

88
forge110/build.gradle Normal file
View File

@ -0,0 +1,88 @@
buildscript {
repositories {
jcenter()
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
}
maven {url = "https://oss.sonatype.org/content/repositories/snapshots/"}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
apply plugin: 'com.github.johnrengelman.shadow'
dependencies {
compile project(':core')
compile 'org.spongepowered:spongeapi:4.+'
compile 'org.mcstats.sponge:metrics:R8-SNAPSHOT'
compile 'com.sk89q.worldedit:worldedit-forge-mc1.8.9:6.1.1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
maven {
name = 'forge'
url = 'http://files.minecraftforge.net/maven'
}
maven {
name = "Sponge"
url = "https://repo.spongepowered.org/maven"
}
maven {
name = "Sponge Metrics"
url = "http://repo.mcstats.org/content/repositories/releases/"
}
}
minecraft {
version = "2014"
mappings = "snapshot_20160629"
runDir = 'run'
}
project.archivesBaseName = "${project.archivesBaseName}-mc${minecraft.version}"
processResources {
from(sourceSets.main.resources.srcDirs) {
expand 'version': project.version,
'mcVersion': project.minecraft.version
exclude 'mcmod.info'
}
}
shadowJar {
relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
dependencies {
include(dependency(':core'))
include(dependency('org.yaml:snakeyaml:1.16'))
}
archiveName = "${parent.name}-${project.name}-${parent.version}.jar"
destinationDir = file '../target'
}
shadowJar.doLast {
task ->
ant.checksum file: task.archivePath
}
reobf {
shadowJar {
mappingType = 'SEARGE'
}
}
task deobfJar(type: Jar) {
from sourceSets.main.output
classifier = 'dev'
}
artifacts {
archives deobfJar
}
build.dependsOn(shadowJar)

View File

@ -0,0 +1,161 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.IFawe;
import com.boydti.fawe.forge.v0.ForgeQueue_All;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.wrappers.WorldWrapper;
import com.mojang.authlib.GameProfile;
import com.sk89q.worldedit.forge.ForgeWorld;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.UUID;
import javax.management.InstanceAlreadyExistsException;
import net.minecraft.command.ServerCommandManager;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.fml.common.FMLCommonHandler;
import org.apache.logging.log4j.Logger;
public class FaweForge implements IFawe {
private final ForgeMain parent;
private final File directory;
private final Logger logger;
public FaweForge(ForgeMain plugin, Logger logger, File directory) {
this.parent = plugin;
this.logger = logger;
this.directory = directory;
try {
Fawe.set(this);
} catch (InstanceAlreadyExistsException e) {
MainUtil.handleError(e);
}
}
@Override
public void debug(String s) {
logger.debug(s);
}
@Override
public File getDirectory() {
return directory;
}
@Override
public void setupCommand(String label, FaweCommand cmd) {
if (TaskManager.IMP != null) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
ServerCommandManager scm = (ServerCommandManager) FMLCommonHandler.instance().getMinecraftServerInstance().getCommandManager();
scm.registerCommand(new ForgeCommand(label, cmd));
}
});
}
}
@Override
public FawePlayer wrap(Object obj) {
EntityPlayerMP player = null;
if (obj instanceof String) {
MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
player = server.getPlayerList().getPlayerByUsername((String) obj);
} else if (obj instanceof UUID) {
MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
player = server.getPlayerList().getPlayerByUUID((UUID) obj);
} else if (obj instanceof EntityPlayerMP) {
player = (EntityPlayerMP) obj;
}
if (player == null) {
return null;
}
FawePlayer existing = Fawe.get().getCachedPlayer(player.getName());
return existing != null ? existing : new ForgePlayer(player);
}
@Override
public void setupVault() {
// Do nothing
}
@Override
public TaskManager getTaskManager() {
return new com.boydti.fawe.forge.ForgeTaskMan(512);
}
@Override
public int[] getVersion() {
String[] version = FMLCommonHandler.instance().getMinecraftServerInstance().getMinecraftVersion().split("\\.");
return new int[] {Integer.parseInt(version[0]), Integer.parseInt(version[1]), Integer.parseInt(version[2])};
}
@Override
public String getWorldName(World world) {
if (world instanceof WorldWrapper) {
world = ((WorldWrapper) world).getParent();
}
return ((ForgeWorld) world).getWorld().getWorldInfo().getWorldName();
}
@Override
public FaweQueue getNewQueue(String world, boolean dontCareIfFast) {
return new ForgeQueue_All(world);
}
@Override
public Collection<FaweMaskManager> getMaskManagers() {
return new ArrayList<>();
}
@Override
public void startMetrics() {
try {
com.boydti.fawe.forge.ForgeMetrics metrics = new com.boydti.fawe.forge.ForgeMetrics("FastAsyncWorldEdit", "3.5.1");
metrics.start();
debug("[FAWE] &6Metrics enabled.");
} catch (Throwable e) {
debug("[FAWE] &cFailed to load up metrics.");
}
}
@Override
public String getPlatform() {
return "forge";
}
@Override
public UUID getUUID(String name) {
try {
GameProfile profile = FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerProfileCache().getGameProfileForUsername(name);
return profile.getId();
} catch (Throwable e) {
return null;
}
}
@Override
public String getName(UUID uuid) {
try {
GameProfile profile = FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerProfileCache().getProfileByUUID(uuid);
return profile.getName();
} catch (Throwable e) {
return null;
}
}
@Override
public Object getBlocksHubApi() {
return null;
}
}

View File

@ -0,0 +1,42 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
public class ForgeCommand extends CommandBase {
private final String name;
private final FaweCommand cmd;
public ForgeCommand(String name, FaweCommand cmd) {
this.name = name;
this.cmd = cmd;
}
@Override
public String getCommandName() {
return name;
}
@Override
public String getCommandUsage(ICommandSender iCommandSender) {
return "/" + name;
}
@Override
public void execute(MinecraftServer minecraftServer, ICommandSender sender, String[] args) throws CommandException {
if ((sender instanceof EntityPlayerMP)) {
EntityPlayerMP player = (EntityPlayerMP) sender;
if (player.worldObj.isRemote) {
return;
}
FawePlayer<Object> fp = FawePlayer.wrap(player);
cmd.executeSafe(fp, args);
}
}
}

View File

@ -0,0 +1,75 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FawePlayer;
import java.io.File;
import java.util.List;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStoppingEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import org.apache.logging.log4j.Logger;
@Mod(modid = "com.boydti.fawe", name = "FastAsyncWorldEdit", version = "3.5.1", acceptableRemoteVersions = "*")
public class ForgeMain {
private static com.boydti.fawe.forge.FaweForge IMP;
private Logger logger;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
this.logger = event.getModLog();
File directory = new File(event.getModConfigurationDirectory() + File.separator + "FastAsyncWorldEdit");
MinecraftForge.EVENT_BUS.register(this);
FMLCommonHandler.instance().bus().register(this);
this.IMP = new com.boydti.fawe.forge.FaweForge(this, event.getModLog(), directory);
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onPlayerQuit(PlayerEvent.PlayerLoggedOutEvent event) {
if (event.player.worldObj.isRemote) {
return;
}
handleQuit((EntityPlayerMP) event.player);
}
@Mod.EventHandler
public void serverStopping(FMLServerStoppingEvent event) {
for (EntityPlayerMP player : (List<EntityPlayerMP>)FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayerList()) {
handleQuit(player);
}
}
public void handleQuit(EntityPlayerMP player) {
FawePlayer fp = FawePlayer.wrap(player);
fp.unregister();
Fawe.get().unregister(player.getName());
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onPlayerChangedWorld(EntityJoinWorldEvent event) {
Entity entity = event.getEntity();
if (!(entity instanceof EntityPlayerMP)) {
return;
}
EntityPlayerMP player = (EntityPlayerMP) entity;
if (player.worldObj.isRemote) {
return;
}
FawePlayer fp = FawePlayer.wrap(player);
if (fp.getMeta("lastWorld") != event.getWorld()) {
fp.setMeta("lastWorld", event.getWorld());
if (Settings.HISTORY.USE_DISK) {
fp.getSession().clearHistory();
fp.loadSessionsFromDisk(fp.getWorld());
}
}
}
}

View File

@ -0,0 +1,481 @@
/*
* Copyright 2011-2013 Tyler Blair. All rights reserved.
* Ported to Minecraft Forge by Mike Primm
* 1.7.x update by Dries007
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package com.boydti.fawe.forge;
import com.boydti.fawe.util.MainUtil;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.UUID;
import java.util.zip.GZIPOutputStream;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
public class ForgeMetrics {
/**
* The current revision number
*/
private final static int REVISION = 7;
/**
* The base url of the metrics domain
*/
private static final String BASE_URL = "http://report.mcstats.org";
/**
* The url used to report a server's status
*/
private static final String REPORT_URL = "/plugin/%s";
/**
* Interval of time to ping (in minutes)
*/
private static final int PING_INTERVAL = 15;
/**
* The mod this metrics submits for
*/
private final String modName;
private final String modVersion;
/**
* The metrics configuration file
*/
private final Configuration configuration;
/**
* The metrics configuration file
*/
private final File configurationFile;
/**
* Unique server id
*/
private final String guid;
/**
* Debug mode
*/
private final boolean debug;
private Thread thread = null;
private boolean firstPost = true;
int tickCount;
public ForgeMetrics(final String modName, final String modVersion) throws IOException {
if (modName == null || modVersion == null) {
throw new IllegalArgumentException("modName and modVersion cannot be null");
}
this.modName = modName;
this.modVersion = modVersion;
// load the config
configurationFile = getConfigFile();
configuration = new Configuration(configurationFile);
// Get values, and add some defaults, if needed
configuration.get(Configuration.CATEGORY_GENERAL, "opt-out", false, "Set to true to disable all reporting");
guid = configuration.get(Configuration.CATEGORY_GENERAL, "guid", UUID.randomUUID().toString(), "Server unique ID").getString();
debug = configuration.get(Configuration.CATEGORY_GENERAL, "debug", false, "Set to true for verbose debug").getBoolean(false);
configuration.save();
}
/**
* Start measuring statistics. This will immediately create an async
* repeating task as the plugin and send the initial data to the metrics
* backend, and then after that it will post in increments of PING_INTERVAL
* * 1200 ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
// Did we opt out?
if (isOptOut()) {
return false;
}
FMLCommonHandler.instance().bus().register(this);
return true;
}
@SubscribeEvent
public void tick(TickEvent.ServerTickEvent tick) {
if (tick.phase != TickEvent.Phase.END) return;
if (tickCount++ % (PING_INTERVAL * 1200) != 0) return;
if (thread == null) {
thread = new Thread(new Runnable() {
public void run() {
try {
// Disable Task, if it is running and the server owner decided
// to opt-out
if (isOptOut()) {
FMLCommonHandler.instance().bus().unregister(ForgeMetrics.this);
return;
}
// We use the inverse of firstPost because if it
// is the first time we are posting,
// it is not a interval ping, so it evaluates to
// FALSE
// Each time thereafter it will evaluate to
// TRUE, i.e PING!
postPlugin(!firstPost);
// After the first post we set firstPost to
// false
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
if (debug) {
FMLLog.info("[Metrics] Exception - %s", e.getMessage());
}
} finally {
thread = null;
}
}
});
thread.start();
}
}
/**
* Stop processing
*/
public void stop() {
}
/**
* Has the server owner denied plugin metrics?
*
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
// Reload the metrics file
configuration.load();
return configuration.get(Configuration.CATEGORY_GENERAL, "opt-out", false).getBoolean(false);
}
/**
* Enables metrics for the server by setting "opt-out" to false in the
* config file and starting the metrics task.
*
* @throws java.io.IOException
*/
public void enable() throws IOException {
// Check if the server owner has already set opt-out, if not, set it.
if (isOptOut()) {
configuration.getCategory(Configuration.CATEGORY_GENERAL).get("opt-out").set("false");
configuration.save();
}
// Enable Task, if it is not running
FMLCommonHandler.instance().bus().register(this);
}
/**
* Disables metrics for the server by setting "opt-out" to true in the
* config file and canceling the metrics task.
*
* @throws java.io.IOException
*/
public void disable() throws IOException {
// Check if the server owner has already set opt-out, if not, set it.
if (!isOptOut()) {
configuration.getCategory(Configuration.CATEGORY_GENERAL).get("opt-out").set("true");
configuration.save();
}
FMLCommonHandler.instance().bus().unregister(this);
}
/**
* Gets the File object of the config file that should be used to store data
* such as the GUID and opt-out status
*
* @return the File object for the config file
*/
public File getConfigFile() {
return new File(Loader.instance().getConfigDir(), "PluginMetrics.cfg");
}
/**
* Generic method that posts a plugin to the metrics website
*/
private void postPlugin(final boolean isPing) throws IOException {
// Server software specific section
String pluginName = modName;
MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
boolean onlineMode = server.isServerInOnlineMode();
String pluginVersion = modVersion;
String serverVersion;
if (server.isDedicatedServer()) {
serverVersion = "MinecraftForge (MC: " + server.getMinecraftVersion() + ")";
} else {
serverVersion = "MinecraftForgeSSP (MC: " + server.getMinecraftVersion() + ")";
}
int playersOnline = server.getCurrentPlayerCount();
// END server software specific section -- all code below does not use any code outside of this class / Java
// Construct the post data
StringBuilder json = new StringBuilder(1024);
json.append('{');
// The plugin's description file containg all of the plugin data such as name, version, author, etc
appendJSONPair(json, "guid", guid);
appendJSONPair(json, "plugin_version", pluginVersion);
appendJSONPair(json, "server_version", serverVersion);
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String java_version = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if (osarch.equals("amd64")) {
osarch = "x86_64";
}
appendJSONPair(json, "osname", osname);
appendJSONPair(json, "osarch", osarch);
appendJSONPair(json, "osversion", osversion);
appendJSONPair(json, "cores", Integer.toString(coreCount));
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
appendJSONPair(json, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
appendJSONPair(json, "ping", "1");
}
// close json
json.append('}');
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
// Connect to the website
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if (isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
byte[] uncompressed = json.toString().getBytes();
byte[] compressed = gzip(json.toString());
// Headers
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.setDoOutput(true);
// Write the data
OutputStream os = connection.getOutputStream();
os.write(compressed);
os.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String response = reader.readLine();
// close resources
os.close();
reader.close();
if (response == null || response.startsWith("ERR") || response.startsWith("7")) {
if (response == null) {
response = "null";
} else if (response.startsWith("7")) {
response = response.substring(response.startsWith("7,") ? 2 : 1);
}
throw new IOException(response);
}
}
/**
* GZip compress a string of bytes
*
* @param input
* @return
*/
public static byte[] gzip(String input) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = null;
try {
gzos = new GZIPOutputStream(baos);
gzos.write(input.getBytes("UTF-8"));
} catch (IOException e) {
MainUtil.handleError(e);
} finally {
if (gzos != null) try {
gzos.close();
} catch (IOException ignore) {
}
}
return baos.toByteArray();
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
*
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
/**
* Appends a json encoded key/value pair to the given string builder.
*
* @param json
* @param key
* @param value
* @throws java.io.UnsupportedEncodingException
*/
private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException {
boolean isValueNumeric = false;
try {
if (value.equals("0") || !value.endsWith("0")) {
Double.parseDouble(value);
isValueNumeric = true;
}
} catch (NumberFormatException e) {
isValueNumeric = false;
}
if (json.charAt(json.length() - 1) != '{') {
json.append(',');
}
json.append(escapeJSON(key));
json.append(':');
if (isValueNumeric) {
json.append(value);
} else {
json.append(escapeJSON(value));
}
}
/**
* Escape a string to create a valid JSON string
*
* @param text
* @return
*/
private static String escapeJSON(String text) {
StringBuilder builder = new StringBuilder();
builder.append('"');
for (int index = 0; index < text.length(); index++) {
char chr = text.charAt(index);
switch (chr) {
case '"':
case '\\':
builder.append('\\');
builder.append(chr);
break;
case '\b':
builder.append("\\b");
break;
case '\t':
builder.append("\\t");
break;
case '\n':
builder.append("\\n");
break;
case '\r':
builder.append("\\r");
break;
default:
if (chr < ' ') {
String t = "000" + Integer.toHexString(chr);
builder.append("\\u" + t.substring(t.length() - 4));
} else {
builder.append(chr);
}
break;
}
}
builder.append('"');
return builder.toString();
}
/**
* Encode text as UTF-8
*
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
private static String urlEncode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
}

View File

@ -0,0 +1,78 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FaweLocation;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.wrappers.PlayerWrapper;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.forge.ForgeWorldEdit;
import java.util.UUID;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentBase;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
public class ForgePlayer extends FawePlayer<EntityPlayerMP> {
public ForgePlayer(EntityPlayerMP parent) {
super(parent);
}
@Override
public void sendTitle(String head, String sub) { // Not supported
Settings.QUEUE.PROGRESS.DISPLAY = false;
}
@Override
public void resetTitle() { // Not supported
Settings.QUEUE.PROGRESS.DISPLAY = false;
}
@Override
public String getName() {
return parent.getName();
}
@Override
public UUID getUUID() {
return parent.getUniqueID();
}
@Override
public boolean hasPermission(String perm) {
Object meta = getMeta(perm);
return meta instanceof Boolean ? (boolean) meta : ForgeWorldEdit.inst.getPermissionsProvider().hasPermission(parent, perm);
}
@Override
public void setPermission(String perm, boolean flag) {
setMeta(perm, flag);
}
@Override
public void sendMessage(String msg) {
for (String part : msg.split("\n")) {
part = BBC.color(part);
TextComponentBase text = new TextComponentString(part);
this.parent.addChatMessage(text);
}
}
@Override
public void executeCommand(String substring) {
throw new UnsupportedOperationException("NOT IMPLEMENTED");
}
@Override
public FaweLocation getLocation() {
World world = parent.worldObj;
BlockPos pos = parent.getPosition();
return new FaweLocation(world.getWorldInfo().getWorldName(), pos.getX(), pos.getY(), pos.getZ());
}
@Override
public Player getPlayer() {
return PlayerWrapper.wrap(ForgeWorldEdit.inst.wrap(this.parent));
}
}

View File

@ -0,0 +1,168 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.TaskManager;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
public class ForgeTaskMan extends TaskManager {
private final ConcurrentLinkedDeque<Runnable> syncTasks = new ConcurrentLinkedDeque<>();
private final ConcurrentLinkedDeque<Runnable> asyncTasks = new ConcurrentLinkedDeque<>();
private final ConcurrentHashMap<Integer, Runnable> taskIdMap = new ConcurrentHashMap<>();
private final AtomicInteger taskId = new AtomicInteger();
private final ExecutorService executor;
public ForgeTaskMan(int size) {
this.executor = Executors.newFixedThreadPool(size);
FMLCommonHandler.instance().bus().register(this);
}
@Override
public int repeat(final Runnable r, final int interval) {
if (r == null) {
return -1;
}
int id = taskId.incrementAndGet();
taskIdMap.put(id, r);
task(new Runnable() {
@Override
public void run() {
if (!taskIdMap.containsKey(id)) {
return;
}
try {
r.run();
} catch (Throwable e) {
MainUtil.handleError(e);
}
later(this, interval);
}
});
return id;
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onServerTick(TickEvent.ServerTickEvent event) {
Fawe.get().setMainThread();
int asyncSize = asyncTasks.size();
for (int i = 0; i < asyncSize; i++) {
Runnable item = asyncTasks.poll();
if (item != null) {
async(item);
}
}
int syncSize = syncTasks.size();
for (int i = 0; i < syncSize; i++) {
Runnable item = syncTasks.poll();
if (item != null) {
try {
item.run();
} catch (Throwable e) {
MainUtil.handleError(e);
}
}
}
}
@Override
public int repeatAsync(Runnable r, int interval) {
if (r == null) {
return -1;
}
int id = taskId.incrementAndGet();
taskIdMap.put(id, r);
async(new Runnable() {
@Override
public void run() {
if (!taskIdMap.containsKey(id)) {
return;
}
try {
r.run();
} catch (Throwable e) {
MainUtil.handleError(e);
}
laterAsync(this, interval);
}
});
return id;
}
@Override
public void async(Runnable r) {
if (r == null) {
return;
}
executor.execute(r);
}
@Override
public void task(Runnable r) {
if (r == null) {
return;
}
syncTasks.add(r);
}
@Override
public void later(Runnable r, int delay) {
if (r == null) {
return;
}
AtomicInteger remaining = new AtomicInteger(delay);
task(new Runnable() {
@Override
public void run() {
if (remaining.decrementAndGet() <= 0) {
try {
r.run();
} catch (Throwable e) {
MainUtil.handleError(e);
}
return;
}
task(this);
}
});
}
@Override
public void laterAsync(Runnable r, int delay) {
if (r == null) {
return;
}
AtomicInteger remaining = new AtomicInteger(delay);
task(new Runnable() {
@Override
public void run() {
if (remaining.decrementAndGet() <= 0) {
try {
async(r);
} catch (Throwable e) {
MainUtil.handleError(e);
}
return;
}
task(this);
}
});
}
@Override
public void cancel(int task) {
taskIdMap.remove(task);
}
}

View File

@ -0,0 +1,114 @@
package com.boydti.fawe.forge.v0;
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.Field;
import net.minecraft.block.Block;
import net.minecraft.util.BitArray;
import net.minecraft.world.World;
import net.minecraft.world.chunk.BlockStateContainer;
import net.minecraft.world.chunk.BlockStatePaletteRegistry;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IBlockStatePalette;
public class ForgeChunk_All extends CharFaweChunk<Chunk> {
public BlockStateContainer[] sectionPalettes;
/**
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
*
* @param parent
* @param x
* @param z
*/
public ForgeChunk_All(FaweQueue parent, int x, int z) {
super(parent, x, z);
}
@Override
public Chunk getNewChunk() {
World world = ((ForgeQueue_All) getParent()).getWorld();
return world.getChunkProvider().provideChunk(getX(), getZ());
}
@Override
public CharFaweChunk<Chunk> copy(boolean shallow) {
ForgeChunk_All value = (ForgeChunk_All) super.copy(shallow);
if (sectionPalettes != null) {
value.sectionPalettes = new BlockStateContainer[16];
try {
Field fieldBits = BlockStateContainer.class.getDeclaredField("storage");
fieldBits.setAccessible(true);
Field fieldPalette = BlockStateContainer.class.getDeclaredField("palette");
fieldPalette.setAccessible(true);
Field fieldSize = BlockStateContainer.class.getDeclaredField("bits");
fieldSize.setAccessible(true);
for (int i = 0; i < sectionPalettes.length; i++) {
BlockStateContainer current = sectionPalettes[i];
if (current == null) {
continue;
}
// Clone palette
IBlockStatePalette currentPalette = (IBlockStatePalette) fieldPalette.get(current);
if (!(currentPalette instanceof BlockStatePaletteRegistry)) {
current.onResize(128, null);
}
BlockStateContainer paletteBlock = new BlockStateContainer();
currentPalette = (IBlockStatePalette) fieldPalette.get(current);
if (!(currentPalette instanceof BlockStatePaletteRegistry)) {
throw new RuntimeException("Palette must be global!");
}
fieldPalette.set(paletteBlock, currentPalette);
// Clone size
fieldSize.set(paletteBlock, fieldSize.get(current));
// Clone palette
BitArray currentBits = (BitArray) fieldBits.get(current);
BitArray newBits = new BitArray(1, 0);
for (Field field : BitArray.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 void optimize() {
if (sectionPalettes != null) {
return;
}
char[][] arrays = getCombinedIdArrays();
char lastChar = Character.MAX_VALUE;
for (int layer = 0; layer < 16; layer++) {
if (getCount(layer) > 0) {
if (sectionPalettes == null) {
sectionPalettes = new BlockStateContainer[16];
}
BlockStateContainer palette = new BlockStateContainer();
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.set(x, y, z, Block.getBlockById(combinedId >> 4).getStateFromMeta(combinedId & 0xF));
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,702 @@
package com.boydti.fawe.forge.v0;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.BytePair;
import com.boydti.fawe.object.FaweChunk;
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 java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
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.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityTracker;
import net.minecraft.entity.EntityTrackerEntry;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.play.server.SPacketChunkData;
import net.minecraft.network.play.server.SPacketDestroyEntities;
import net.minecraft.server.management.PlayerChunkMap;
import net.minecraft.server.management.PlayerChunkMapEntry;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BitArray;
import net.minecraft.util.ClassInheritanceMultiMap;
import net.minecraft.util.IntHashMap;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.BlockStateContainer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IBlockStatePalette;
import net.minecraft.world.chunk.IChunkGenerator;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.chunk.NibbleArray;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.gen.ChunkProviderServer;
import net.minecraftforge.fml.common.FMLCommonHandler;
public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlockStorage[], BlockStateContainer> {
private Method methodFromNative;
private Method methodToNative;
public ForgeQueue_All(String world) {
super(world);
try {
Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter");
this.methodFromNative = converter.getDeclaredMethod("toNative", Tag.class);
this.methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class);
methodFromNative.setAccessible(true);
methodToNative.setAccessible(true);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
private BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(0, 0, 0);
@Override
public CompoundTag getTileEntity(Chunk chunk, int x, int y, int z) {
Map<BlockPos, TileEntity> tiles = chunk.getTileEntityMap();
pos.setPos(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.readFromNBT(tag); // readTagIntoEntity
return (CompoundTag) methodToNative.invoke(null, tag);
} catch (Exception e) {
MainUtil.handleError(e);
return null;
}
}
@Override
public Chunk getChunk(World world, int x, int z) {
Chunk chunk = world.getChunkProvider().provideChunk(x, z);
if (chunk != null && !chunk.isLoaded()) {
chunk.onChunkLoad();
}
return chunk;
}
@Override
public boolean isChunkLoaded(int x, int z) {
return getWorld().getChunkProvider().getLoadedChunk(x, z) != null;
}
@Override
public boolean regenerateChunk(World world, int x, int z) {
IChunkProvider provider = world.getChunkProvider();
if (!(provider instanceof ChunkProviderServer)) {
return false;
}
try {
ChunkProviderServer chunkServer = (ChunkProviderServer) provider;
IChunkGenerator gen = chunkServer.chunkGenerator;
long pos = ChunkPos.chunkXZ2Int(x, z);
Chunk mcChunk;
if (chunkServer.chunkExists(x, z)) {
mcChunk = chunkServer.loadChunk(x, z);
mcChunk.onChunkUnload();
}
PlayerChunkMap playerManager = ((WorldServer) getWorld()).getPlayerChunkMap();
List<EntityPlayerMP> oldWatchers = null;
if (chunkServer.chunkExists(x, z)) {
mcChunk = chunkServer.loadChunk(x, z);
PlayerChunkMapEntry entry = playerManager.getEntry(x, z);
if (entry != null) {
Field fieldPlayers = PlayerChunkMap.class.getDeclaredField("players");
fieldPlayers.setAccessible(true);
oldWatchers = (List<EntityPlayerMP>) fieldPlayers.get(entry);
playerManager.removeEntry(entry);
}
mcChunk.onChunkUnload();
}
try {
Field droppedChunksSetField = chunkServer.getClass().getDeclaredField("field_73248_b");
droppedChunksSetField.setAccessible(true);
Set droppedChunksSet = (Set) droppedChunksSetField.get(chunkServer);
droppedChunksSet.remove(pos);
} catch (Throwable e) {
MainUtil.handleError(e);
}
chunkServer.id2ChunkMap.remove(pos);
mcChunk = gen.provideChunk(x, z);
chunkServer.id2ChunkMap.put(pos, mcChunk);
if (mcChunk != null) {
mcChunk.onChunkLoad();
mcChunk.populateChunk(chunkServer, chunkServer.chunkGenerator);
}
if (oldWatchers != null) {
for (EntityPlayerMP player : oldWatchers) {
playerManager.addPlayer(player);
}
}
return true;
} catch (Throwable t) {
MainUtil.handleError(t);
return false;
}
}
@Override
public boolean loadChunk(World world, int x, int z, boolean generate) {
return getCachedSections(world, x, z) != null;
}
@Override
public ExtendedBlockStorage[] getCachedSections(World world, int x, int z) {
Chunk chunk = world.getChunkProvider().provideChunk(x, z);
if (chunk != null && !chunk.isLoaded()) {
chunk.onChunkLoad();
}
return chunk == null ? null : chunk.getBlockStorageArray();
}
@Override
public BlockStateContainer getCachedSection(ExtendedBlockStorage[] chunk, int cy) {
ExtendedBlockStorage value = chunk[cy];
return value == null ? null : value.getData();
}
@Override
public int getCombinedId4Data(BlockStateContainer ls, int x, int y, int z) {
IBlockState ibd = lastSection.get(x & 15, y & 15, z & 15);
Block block = ibd.getBlock();
int id = Block.getIdFromBlock(block);
if (FaweCache.hasData(id)) {
return (id << 4) + block.getMetaFromState(ibd);
} else {
return id << 4;
}
}
@Override
public boolean isChunkLoaded(World world, int x, int z) {
return world.getChunkProvider().getLoadedChunk(x, z) != null;
}
public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ExtendedBlockStorage section) throws NoSuchFieldException, IllegalAccessException {
Class<? extends ExtendedBlockStorage> clazz = section.getClass();
Field fieldTickingBlockCount = clazz.getDeclaredField("field_76683_c");
Field fieldNonEmptyBlockCount = clazz.getDeclaredField("field_76682_b");
fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount.setAccessible(true);
fieldTickingBlockCount.set(section, tickingBlockCount);
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
}
@Override
public CharFaweChunk getPrevious(CharFaweChunk fs, ExtendedBlockStorage[] sections, Map<?, ?> tilesGeneric, Collection<?>[] entitiesGeneric, Set<UUID> createdEntities, boolean all) throws Exception {
Map<BlockPos, TileEntity> tiles = (Map<BlockPos, TileEntity>) tilesGeneric;
ClassInheritanceMultiMap<Entity>[] entities = (ClassInheritanceMultiMap<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) {
ExtendedBlockStorage section = sections[layer];
if (section != null) {
short solid = 0;
char[] previousLayer = idPrevious[layer] = new char[4096];
BlockStateContainer blocks = section.getData();
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];
IBlockState ibd = blocks.get(x, y, z);
Block block = ibd.getBlock();
int combined = Block.getIdFromBlock(block);
if (FaweCache.hasData(combined)) {
combined = (combined << 4) + block.getMetaFromState(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;
if (tiles != null) {
for (Map.Entry<BlockPos, TileEntity> entry : tiles.entrySet()) {
TileEntity tile = entry.getValue();
NBTTagCompound tag = new NBTTagCompound();
tile.readFromNBT(tag); // readTileEntityIntoTag
BlockPos pos = entry.getKey();
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(null, tag);
previous.setTile(pos.getX(), pos.getY(), pos.getZ(), 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.posX) & 15);
int z = ((int) Math.round(ent.posZ) & 15);
int y = (int) Math.round(ent.posY);
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 = EntityList.getEntityString(ent);
if (id != null) {
NBTTagCompound tag = ent.getEntityData(); // readEntityIntoTag
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(null, tag);
Map<String, Tag> map = ReflectionUtils.getMap(nativeTag.getValue());
map.put("Id", new StringTag(id));
previous.setEntity(nativeTag);
}
}
}
}
}
return previous;
}
private final IBlockState air = Blocks.AIR.getDefaultState();
@Override
public boolean setComponents(FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
ForgeChunk_All fs = (ForgeChunk_All) fc;
net.minecraft.world.chunk.Chunk nmsChunk = fs.getChunk();
nmsChunk.setModified(true);
net.minecraft.world.World nmsWorld = nmsChunk.getWorld();
try {
boolean flag = !nmsWorld.provider.getHasNoSky();
// Sections
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
Map<BlockPos, TileEntity> tiles = nmsChunk.getTileEntityMap();
ClassInheritanceMultiMap<Entity>[] entities = nmsChunk.getEntityLists();
// Remove entities
for (int i = 0; i < 16; i++) {
int count = fs.getCount(i);
if (count == 0) {
continue;
} else if (count >= 4096) {
entities[i] = new ClassInheritanceMultiMap<>(Entity.class);
} 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.posX) & 15);
int z = ((int) Math.round(entity.posZ) & 15);
int y = (int) Math.round(entity.posY);
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();
NBTTagCompound tag = (NBTTagCompound)methodFromNative.invoke(null, nativeTag);
Entity entity = EntityList.createEntityFromNBT(tag, nmsWorld);
if (entity != null) {
entity.setPositionAndRotation(x, y, z, yaw, pitch);
nmsWorld.spawnEntityInWorld(entity);
}
}
// 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<BlockPos, TileEntity>> entryset = tiles.entrySet();
Iterator<Map.Entry<BlockPos, TileEntity>> iterator = entryset.iterator();
while (iterator.hasNext()) {
Map.Entry<BlockPos, TileEntity> tile = iterator.next();
BlockPos 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().invalidate();;
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);
}
}
}
}
// Efficiently merge sections
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;
}
ExtendedBlockStorage section = sections[j];
if (section == null) {
if (fs.sectionPalettes != null && fs.sectionPalettes[j] != null) {
section = sections[j] = new ExtendedBlockStorage(j << 4, flag);
setPalette(section, fs.sectionPalettes[j]);
setCount(0, count - fs.getAir(j), section);
} else {
sections[j] = new ExtendedBlockStorage(j << 4, flag);
}
} 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] = new ExtendedBlockStorage(j << 4, flag);
}
}
BlockStateContainer nibble = section.getData();
Field fieldBits = BlockStateContainer.class.getDeclaredField("storage");
fieldBits.setAccessible(true);
BitArray bits = (BitArray) fieldBits.get(nibble);
Field fieldPalette = BlockStateContainer.class.getDeclaredField("palette");
fieldPalette.setAccessible(true);
IBlockStatePalette palette = (IBlockStatePalette) 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:
IBlockState existing = nibble.get(x, y, z);
if (existing != air) {
nonEmptyBlockCount++;
}
continue;
case 1:
nibble.set(x, y, z, air);
continue;
default:
nonEmptyBlockCount++;
nibble.set(x, y, z, Block.getBlockById(combinedId >> 4).getStateFromMeta(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.getBiomeArray()[((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();
BlockPos pos = new BlockPos(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(null, nativeTag);
tileEntity.readFromNBT(tag); // ReadTagIntoTile
}
}
} catch (Throwable e) {
MainUtil.handleError(e);
}
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.getBiomeArray()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome;
}
}
}
sendChunk(fs, null);
return true;
}
public void setPalette(ExtendedBlockStorage section, BlockStateContainer palette) throws NoSuchFieldException, IllegalAccessException {
Field fieldSection = ExtendedBlockStorage.class.getDeclaredField("data");
fieldSection.setAccessible(true);
fieldSection.set(section, palette);
}
@Override
public void refreshChunk(World world, net.minecraft.world.chunk.Chunk nmsChunk) {
if (!nmsChunk.isLoaded()) {
return;
}
try {
ChunkPos pos = nmsChunk.getChunkCoordIntPair();
WorldServer w = (WorldServer) nmsChunk.getWorld();
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
int x = pos.chunkXPos;
int z = pos.chunkZPos;
if (!chunkMap.contains(x, z)) {
return;
}
EntityTracker tracker = w.getEntityTracker();
HashSet<EntityPlayerMP> players = new HashSet<>();
for (EntityPlayer player : w.playerEntities) {
if (player instanceof EntityPlayerMP) {
if (chunkMap.isPlayerWatchingChunk((EntityPlayerMP) player, x, z)) {
players.add((EntityPlayerMP) player);
}
}
}
if (players.size() == 0) {
return;
}
HashSet<EntityTrackerEntry> entities = new HashSet<>();
ClassInheritanceMultiMap<Entity>[] entitieSlices = nmsChunk.getEntityLists();
IntHashMap<EntityTrackerEntry> entries = null;
for (Field field : tracker.getClass().getDeclaredFields()) {
if (field.getType() == IntHashMap.class) {
field.setAccessible(true);
entries = (IntHashMap<EntityTrackerEntry>) field.get(tracker);
}
}
for (ClassInheritanceMultiMap<Entity> slice : entitieSlices) {
if (slice == null) {
continue;
}
for (Entity ent : slice) {
EntityTrackerEntry entry = entries != null ? entries.lookup(ent.getEntityId()) : null;
if (entry == null) {
continue;
}
entities.add(entry);
SPacketDestroyEntities packet = new SPacketDestroyEntities(ent.getEntityId());
for (EntityPlayerMP player : players) {
player.connection.sendPacket(packet);
}
}
}
// Send chunks
SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65535);
for (EntityPlayerMP player : players) {
player.connection.sendPacket(packet);
}
// send ents
for (EntityTrackerEntry entry : entities) {
try {
TaskManager.IMP.later(new Runnable() {
@Override
public void run() {
for (EntityPlayerMP player : players) {
boolean result = entry.trackingPlayers.remove(player);
if (result && entry.getTrackedEntity() != player) {
entry.updatePlayerEntity(player);
}
}
}
}, 2);
} catch (Throwable e) {
MainUtil.handleError(e);
}
}
} catch (Throwable e) {
MainUtil.handleError(e);
}
}
@Override
public FaweChunk<Chunk> getFaweChunk(int x, int z) {
return new ForgeChunk_All(this, x, z);
}
@Override
public boolean removeLighting(ExtendedBlockStorage[] sections, RelightMode mode, boolean sky) {
if (mode == RelightMode.ALL) {
for (int i = 0; i < sections.length; i++) {
ExtendedBlockStorage section = sections[i];
if (section != null) {
section.setBlocklightArray(new NibbleArray());
if (sky) {
section.setSkylightArray(new NibbleArray());
}
}
}
}
return true;
}
@Override
public boolean hasSky() {
return nmsWorld.provider.getHasNoSky();
}
@Override
public boolean initLighting(Chunk nmsChunk, ExtendedBlockStorage[] sections, RelightMode mode) {
if (mode == RelightMode.ALL) {
nmsChunk.generateSkylightMap();
} else {
int i = nmsChunk.getTopFilledSegment();
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 = nmsChunk.getBlockLightOpacity(new BlockPos(x, y, z));
if (opacity == 0 && l != 15) {
opacity = 1;
}
l -= opacity;
if (l > 0) {
ExtendedBlockStorage section = sections[y >> 4];
if (section != null) {
section.setExtSkylightValue(x, y & 15, z, l);
}
}
--y;
} while (y > 0 && l > 0);
}
}
}
return true;
}
@Override
public void setFullbright(ExtendedBlockStorage[] sections) {
for (int i = 0; i < sections.length; i++) {
ExtendedBlockStorage section = sections[i];
if (section != null) {
byte[] bytes = section.getSkylightArray().getData();
Arrays.fill(bytes, (byte) 255);
}
}
}
@Override
public int getSkyLight(ExtendedBlockStorage[] sections, int x, int y, int z) {
ExtendedBlockStorage section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 15;
}
return section.getExtSkylightValue(x, y & 15, z);
}
@Override
public int getEmmittedLight(ExtendedBlockStorage[] sections, int x, int y, int z) {
ExtendedBlockStorage section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 0;
}
return section.getExtBlocklightValue(x, y & 15, z);
}
@Override
public void relight(int x, int y, int z) {
pos.setPos(x, y, z);
nmsWorld.checkLight(pos);
}
private WorldServer nmsWorld;
@Override
public World getImpWorld() {
WorldServer[] worlds = FMLCommonHandler.instance().getMinecraftServerInstance().worldServers;
for (WorldServer ws : worlds) {
if (ws.getWorldInfo().getWorldName().equals(getWorldName())) {
return nmsWorld = ws;
}
}
return null;
}
}

View File

View File

@ -7,7 +7,6 @@ import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.BytePair;
import com.boydti.fawe.object.FaweChunk;
import com.boydti.fawe.object.IntegerPair;
import com.boydti.fawe.object.PseudoRandom;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.MathMan;
@ -20,6 +19,7 @@ import com.sk89q.jnbt.Tag;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
@ -27,7 +27,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityTracker;
@ -132,17 +131,6 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
return world.getChunkProvider().chunkExists(x, z);
}
@Override
public World getWorld(String world) {
WorldServer[] worlds = MinecraftServer.getServer().worldServers;
for (WorldServer ws : worlds) {
if (ws.provider.getDimensionName().equals(world)) {
return ws;
}
}
return null;
}
@Override
public boolean regenerateChunk(World world, int x, int z) {
try {
@ -305,6 +293,8 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
ForgeChunk_All fs = (ForgeChunk_All) fc;
net.minecraft.world.chunk.Chunk nmsChunk = fs.getChunk();
net.minecraft.world.World nmsWorld = nmsChunk.worldObj;
nmsChunk.setChunkModified();
nmsChunk.sendUpdates = true;
try {
boolean flag = !nmsWorld.provider.hasNoSky;
// Sections
@ -598,158 +588,100 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
}
@Override
public boolean fixLighting(FaweChunk<?> fc, RelightMode mode) {
if (mode == RelightMode.NONE) {
return true;
}
try {
ForgeChunk_All bc = (ForgeChunk_All) fc;
net.minecraft.world.chunk.Chunk nmsChunk = bc.getChunk();
if (!nmsChunk.isChunkLoaded) {
return false;
}
World nmsWorld = nmsChunk.worldObj;
boolean flag = !nmsWorld.provider.hasNoSky;
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
if (mode == RelightMode.ALL) {
for (int i = 0; i < sections.length; i++) {
ExtendedBlockStorage section = sections[i];
if (section != null) {
section.setBlocklightArray(new NibbleArray(4096, 4));
if (flag) {
section.setSkylightArray(new NibbleArray(4096, 4));
}
public boolean removeLighting(ExtendedBlockStorage[] sections, RelightMode mode, boolean sky) {
if (mode == RelightMode.ALL) {
for (int i = 0; i < sections.length; i++) {
ExtendedBlockStorage section = sections[i];
if (section != null) {
section.setBlocklightArray(new NibbleArray(4096, 4));
if (sky) {
section.setSkylightArray(new NibbleArray(4096, 4));
}
}
}
if (flag) {
if (mode == RelightMode.ALL) {
nmsChunk.generateSkylightMap();
} else {
int i = nmsChunk.getTopFilledSegment();
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 = nmsChunk.func_150808_b(x, y, z);
if (opacity == 0 && l != 15) {
opacity = 1;
}
l -= opacity;
if (l > 0) {
ExtendedBlockStorage section = sections[y >> 4];
if (section != null) {
section.setExtSkylightValue(x, y & 15, z, l);
}
}
--y;
} while (y > 0 && l > 0);
}
}
}
}
if (bc.getTotalRelight() == 0 && mode == RelightMode.MINIMAL) {
return true;
}
int X = fc.getX() << 4;
int Z = fc.getZ() << 4;
for (int j = 0; j < sections.length; j++) {
ExtendedBlockStorage 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;
}
byte[] array = section.getBlockLSBArray();
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;
}
nmsWorld.func_147451_t(X + x, y, Z + z);
}
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:
case 213:
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;
}
nmsWorld.func_147451_t(X + x, y, Z + z);
}
}
}
return true;
} catch (Throwable e) {
if (Thread.currentThread() == Fawe.get().getMainThread()) {
MainUtil.handleError(e);
}
}
return false;
return true;
}
public boolean isSurrounded(ExtendedBlockStorage[] 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));
@Override
public boolean hasSky() {
return nmsWorld.provider.hasNoSky;
}
public boolean isSolid(int i) {
return i != 0 && Block.getBlockById(i).isOpaqueCube();
@Override
public boolean initLighting(Chunk nmsChunk, ExtendedBlockStorage[] sections, RelightMode mode) {
if (mode == RelightMode.ALL) {
nmsChunk.generateSkylightMap();
} else {
int i = nmsChunk.getTopFilledSegment();
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 = nmsChunk.func_150808_b(x, y, z);
if (opacity == 0 && l != 15) {
opacity = 1;
}
l -= opacity;
if (l > 0) {
ExtendedBlockStorage section = sections[y >> 4];
if (section != null) {
section.setExtSkylightValue(x, y & 15, z, l);
}
}
--y;
} while (y > 0 && l > 0);
}
}
}
return true;
}
public int getId(ExtendedBlockStorage[] sections, int x, int y, int z) {
if (x < 0 || x > 15 || z < 0 || z > 15) {
return 1;
@Override
public void setFullbright(ExtendedBlockStorage[] sections) {
for (int i = 0; i < sections.length; i++) {
ExtendedBlockStorage section = sections[i];
if (section != null) {
byte[] bytes = section.getSkylightArray().data;
Arrays.fill(bytes, (byte) 255);
}
}
if (y < 0 || y > 255) {
return 1;
}
@Override
public int getSkyLight(ExtendedBlockStorage[] sections, int x, int y, int z) {
ExtendedBlockStorage section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 15;
}
int i = FaweCache.CACHE_I[y][x][z];
ExtendedBlockStorage section = sections[i];
return section.getExtSkylightValue(x, y & 15, z);
}
@Override
public int getEmmittedLight(ExtendedBlockStorage[] sections, int x, int y, int z) {
ExtendedBlockStorage section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 0;
}
byte[] array = section.getBlockLSBArray();
int j = FaweCache.CACHE_J[y][x][z];
return array[j];
return section.getExtBlocklightValue(x, y & 15, z);
}
@Override
public void relight(int x, int y, int z) {
nmsWorld.func_147451_t(x, y, z);
}
private WorldServer nmsWorld;
@Override
public World getImpWorld() {
WorldServer[] worlds = MinecraftServer.getServer().worldServers;
for (WorldServer ws : worlds) {
if (ws.provider.getDimensionName().equals(getWorldName())) {
return nmsWorld = ws;
}
}
return null;
}
}

View File

@ -6,7 +6,6 @@ import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.example.NMSMappedFaweQueue;
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;
@ -19,13 +18,13 @@ import com.sk89q.jnbt.Tag;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import net.minecraft.block.Block;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityTracker;
@ -104,16 +103,6 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
return getWorld().getChunkProvider().chunkExists(x, z);
}
public World getWorld(String world) {
WorldServer[] worlds = MinecraftServer.getServer().worldServers;
for (WorldServer ws : worlds) {
if (ws.provider.getDimensionName().equals(world)) {
return ws;
}
}
return null;
}
@Override
public boolean regenerateChunk(World world, int x, int z) {
IChunkProvider provider = world.getChunkProvider();
@ -188,135 +177,6 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
}
@Override
public boolean fixLighting(FaweChunk<?> fc, RelightMode mode) {
if (mode == RelightMode.NONE) {
return true;
}
try {
CharFaweChunk<Chunk> bc = (CharFaweChunk) fc;
Chunk nmsChunk = bc.getChunk();
if (!nmsChunk.isLoaded()) {
return false;
}
World nmsWorld = nmsChunk.getWorld();
boolean flag = !nmsWorld.provider.getHasNoSky();
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
if (mode == RelightMode.ALL) {
for (int i = 0; i < sections.length; i++) {
ExtendedBlockStorage section = sections[i];
if (section != null) {
section.setBlocklightArray(new NibbleArray());
if (flag) {
section.setSkylightArray(new NibbleArray());
}
}
}
}
if (flag) {
if (mode == RelightMode.ALL) {
nmsChunk.generateSkylightMap();
} else {
int i = nmsChunk.getTopFilledSegment();
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 = nmsChunk.getBlockLightOpacity(new BlockPos(x, y, z));
if (opacity == 0 && l != 15) {
opacity = 1;
}
l -= opacity;
if (l > 0) {
ExtendedBlockStorage section = sections[y >> 4];
if (section != null) {
section.setExtSkylightValue(x, y & 15, z, l);
}
}
--y;
} while (y > 0 && l > 0);
}
}
}
}
if (bc.getTotalRelight() == 0 && mode == RelightMode.MINIMAL) {
return true;
}
int X = fc.getX() << 4;
int Z = fc.getZ() << 4;
for (int j = 0; j < sections.length; j++) {
ExtendedBlockStorage 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;
}
char[] array = section.getData();
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.set(X + x, y, Z + z);
nmsWorld.checkLight(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:
case 213:
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.set(X + x, y, Z + z);
nmsWorld.checkLight(pos);
}
}
}
return true;
} catch (Throwable e) {
if (Thread.currentThread() == Fawe.get().getMainThread()) {
MainUtil.handleError(e);
}
}
return false;
}
@Override
public CharFaweChunk getPrevious(CharFaweChunk fs, ExtendedBlockStorage[] sections, Map<?, ?> tilesGeneric, Collection<?>[] entitiesGeneric, Set<UUID> createdEntities, boolean all) throws Exception {
Map<BlockPos, TileEntity> tiles = (Map<BlockPos, TileEntity>) tilesGeneric;
@ -385,6 +245,8 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
public boolean setComponents(FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
CharFaweChunk<Chunk> fs = (CharFaweChunk) fc;
net.minecraft.world.chunk.Chunk nmsChunk = fs.getChunk();
nmsChunk.setModified(true);
nmsChunk.setHasEntities(true);
net.minecraft.world.World nmsWorld = nmsChunk.getWorld();
try {
boolean flag = !nmsWorld.provider.getHasNoSky();
@ -670,18 +532,6 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
return new ForgeChunk_All(this, x, z);
}
public boolean isSurrounded(ExtendedBlockStorage[] 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 i != 0 && Block.getBlockById(i).isOpaqueCube();
}
public int getId(ExtendedBlockStorage[] sections, int x, int y, int z) {
if (x < 0 || x > 15 || z < 0 || z > 15) {
return 1;
@ -698,4 +548,103 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
int j = FaweCache.CACHE_J[y][x][z];
return array[j] >> 4;
}
@Override
public boolean removeLighting(ExtendedBlockStorage[] sections, RelightMode mode, boolean sky) {
if (mode == RelightMode.ALL) {
for (int i = 0; i < sections.length; i++) {
ExtendedBlockStorage section = sections[i];
if (section != null) {
section.setBlocklightArray(new NibbleArray());
if (sky) {
section.setSkylightArray(new NibbleArray());
}
}
}
}
return true;
}
@Override
public boolean hasSky() {
return nmsWorld.provider.getHasNoSky();
}
@Override
public boolean initLighting(Chunk nmsChunk, ExtendedBlockStorage[] sections, RelightMode mode) {
if (mode == RelightMode.ALL) {
nmsChunk.generateSkylightMap();
} else {
int i = nmsChunk.getTopFilledSegment();
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 = nmsChunk.getBlockLightOpacity(new BlockPos(x, y, z));
if (opacity == 0 && l != 15) {
opacity = 1;
}
l -= opacity;
if (l > 0) {
ExtendedBlockStorage section = sections[y >> 4];
if (section != null) {
section.setExtSkylightValue(x, y & 15, z, l);
}
}
--y;
} while (y > 0 && l > 0);
}
}
}
return true;
}
@Override
public void setFullbright(ExtendedBlockStorage[] sections) {
for (int i = 0; i < sections.length; i++) {
ExtendedBlockStorage section = sections[i];
if (section != null) {
byte[] bytes = section.getSkylightArray().getData();
Arrays.fill(bytes, (byte) 255);
}
}
}
@Override
public int getSkyLight(ExtendedBlockStorage[] sections, int x, int y, int z) {
ExtendedBlockStorage section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 15;
}
return section.getExtSkylightValue(x, y & 15, z);
}
@Override
public int getEmmittedLight(ExtendedBlockStorage[] sections, int x, int y, int z) {
ExtendedBlockStorage section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 0;
}
return section.getExtBlocklightValue(x, y & 15, z);
}
@Override
public void relight(int x, int y, int z) {
pos.set(x, y, z);
nmsWorld.checkLight(pos);
}
private WorldServer nmsWorld;
@Override
public World getImpWorld() {
WorldServer[] worlds = MinecraftServer.getServer().worldServers;
for (WorldServer ws : worlds) {
if (ws.provider.getDimensionName().equals(getWorldName())) {
return nmsWorld = ws;
}
}
return null;
}
}

86
forge194/build.gradle Normal file
View File

@ -0,0 +1,86 @@
buildscript {
repositories {
jcenter()
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
}
maven {url = "https://oss.sonatype.org/content/repositories/snapshots/"}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.2-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
apply plugin: 'com.github.johnrengelman.shadow'
dependencies {
compile project(':core')
compile 'org.spongepowered:spongeapi:4.+'
compile 'org.mcstats.sponge:metrics:R8-SNAPSHOT'
compile 'com.sk89q.worldedit:worldedit-forge-mc1.8.9:6.1.1'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
maven {
name = 'forge'
url = 'http://files.minecraftforge.net/maven'
}
maven {
name = "Sponge"
url = "https://repo.spongepowered.org/maven"
}
maven {
name = "Sponge Metrics"
url = "http://repo.mcstats.org/content/repositories/releases/"
}
}
minecraft {
version = "1965"
mappings = "stable_26"
runDir = 'run'
}
project.archivesBaseName = "${project.archivesBaseName}-mc${minecraft.version}"
processResources {
from(sourceSets.main.resources.srcDirs) {
expand 'version': project.version,
'mcVersion': project.minecraft.version
exclude 'mcmod.info'
}
}
shadowJar {
relocate 'org.yaml.snakeyaml', 'com.boydti.fawe.yaml'
dependencies {
include(dependency(':core'))
include(dependency('org.yaml:snakeyaml:1.16'))
}
archiveName = "${parent.name}-${project.name}-${parent.version}.jar"
destinationDir = file '../target'
}
shadowJar.doLast {
task ->
ant.checksum file: task.archivePath
}
reobf {
shadowJar {
mappingType = 'SEARGE'
}
}
task deobfJar(type: Jar) {
from sourceSets.main.output
classifier = 'dev'
}
artifacts {
archives deobfJar
}

View File

@ -0,0 +1,161 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.IFawe;
import com.boydti.fawe.forge.v0.ForgeQueue_All;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.regions.FaweMaskManager;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.TaskManager;
import com.boydti.fawe.wrappers.WorldWrapper;
import com.mojang.authlib.GameProfile;
import com.sk89q.worldedit.forge.ForgeWorld;
import com.sk89q.worldedit.world.World;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.UUID;
import javax.management.InstanceAlreadyExistsException;
import net.minecraft.command.ServerCommandManager;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.fml.common.FMLCommonHandler;
import org.apache.logging.log4j.Logger;
public class FaweForge implements IFawe {
private final ForgeMain parent;
private final File directory;
private final Logger logger;
public FaweForge(ForgeMain plugin, Logger logger, File directory) {
this.parent = plugin;
this.logger = logger;
this.directory = directory;
try {
Fawe.set(this);
} catch (InstanceAlreadyExistsException e) {
MainUtil.handleError(e);
}
}
@Override
public void debug(String s) {
logger.debug(s);
}
@Override
public File getDirectory() {
return directory;
}
@Override
public void setupCommand(String label, FaweCommand cmd) {
if (TaskManager.IMP != null) {
TaskManager.IMP.task(new Runnable() {
@Override
public void run() {
ServerCommandManager scm = (ServerCommandManager) FMLCommonHandler.instance().getMinecraftServerInstance().getCommandManager();
scm.registerCommand(new ForgeCommand(label, cmd));
}
});
}
}
@Override
public FawePlayer wrap(Object obj) {
EntityPlayerMP player = null;
if (obj instanceof String) {
MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
player = server.getPlayerList().getPlayerByUsername((String) obj);
} else if (obj instanceof UUID) {
MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
player = server.getPlayerList().getPlayerByUUID((UUID) obj);
} else if (obj instanceof EntityPlayerMP) {
player = (EntityPlayerMP) obj;
}
if (player == null) {
return null;
}
FawePlayer existing = Fawe.get().getCachedPlayer(player.getName());
return existing != null ? existing : new ForgePlayer(player);
}
@Override
public void setupVault() {
// Do nothing
}
@Override
public TaskManager getTaskManager() {
return new com.boydti.fawe.forge.ForgeTaskMan(512);
}
@Override
public int[] getVersion() {
String[] version = FMLCommonHandler.instance().getMinecraftServerInstance().getMinecraftVersion().split("\\.");
return new int[] {Integer.parseInt(version[0]), Integer.parseInt(version[1]), Integer.parseInt(version[2])};
}
@Override
public String getWorldName(World world) {
if (world instanceof WorldWrapper) {
world = ((WorldWrapper) world).getParent();
}
return ((ForgeWorld) world).getWorld().getWorldInfo().getWorldName();
}
@Override
public FaweQueue getNewQueue(String world, boolean dontCareIfFast) {
return new ForgeQueue_All(world);
}
@Override
public Collection<FaweMaskManager> getMaskManagers() {
return new ArrayList<>();
}
@Override
public void startMetrics() {
try {
com.boydti.fawe.forge.ForgeMetrics metrics = new com.boydti.fawe.forge.ForgeMetrics("FastAsyncWorldEdit", "3.5.1");
metrics.start();
debug("[FAWE] &6Metrics enabled.");
} catch (Throwable e) {
debug("[FAWE] &cFailed to load up metrics.");
}
}
@Override
public String getPlatform() {
return "forge";
}
@Override
public UUID getUUID(String name) {
try {
GameProfile profile = FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerProfileCache().getGameProfileForUsername(name);
return profile.getId();
} catch (Throwable e) {
return null;
}
}
@Override
public String getName(UUID uuid) {
try {
GameProfile profile = FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerProfileCache().getProfileByUUID(uuid);
return profile.getName();
} catch (Throwable e) {
return null;
}
}
@Override
public Object getBlocksHubApi() {
return null;
}
}

View File

@ -0,0 +1,42 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.object.FaweCommand;
import com.boydti.fawe.object.FawePlayer;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
public class ForgeCommand extends CommandBase {
private final String name;
private final FaweCommand cmd;
public ForgeCommand(String name, FaweCommand cmd) {
this.name = name;
this.cmd = cmd;
}
@Override
public String getCommandName() {
return name;
}
@Override
public String getCommandUsage(ICommandSender iCommandSender) {
return "/" + name;
}
@Override
public void execute(MinecraftServer minecraftServer, ICommandSender sender, String[] args) throws CommandException {
if ((sender instanceof EntityPlayerMP)) {
EntityPlayerMP player = (EntityPlayerMP) sender;
if (player.worldObj.isRemote) {
return;
}
FawePlayer<Object> fp = FawePlayer.wrap(player);
cmd.executeSafe(fp, args);
}
}
}

View File

@ -0,0 +1,75 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FawePlayer;
import java.io.File;
import java.util.List;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStoppingEvent;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent;
import org.apache.logging.log4j.Logger;
@Mod(modid = "com.boydti.fawe", name = "FastAsyncWorldEdit", version = "3.5.1", acceptableRemoteVersions = "*")
public class ForgeMain {
private static com.boydti.fawe.forge.FaweForge IMP;
private Logger logger;
@Mod.EventHandler
public void preInit(FMLPreInitializationEvent event) {
this.logger = event.getModLog();
File directory = new File(event.getModConfigurationDirectory() + File.separator + "FastAsyncWorldEdit");
MinecraftForge.EVENT_BUS.register(this);
FMLCommonHandler.instance().bus().register(this);
this.IMP = new com.boydti.fawe.forge.FaweForge(this, event.getModLog(), directory);
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onPlayerQuit(PlayerEvent.PlayerLoggedOutEvent event) {
if (event.player.worldObj.isRemote) {
return;
}
handleQuit((EntityPlayerMP) event.player);
}
@Mod.EventHandler
public void serverStopping(FMLServerStoppingEvent event) {
for (EntityPlayerMP player : (List<EntityPlayerMP>)FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayerList()) {
handleQuit(player);
}
}
public void handleQuit(EntityPlayerMP player) {
FawePlayer fp = FawePlayer.wrap(player);
fp.unregister();
Fawe.get().unregister(player.getName());
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onPlayerChangedWorld(EntityJoinWorldEvent event) {
Entity entity = event.getEntity();
if (!(entity instanceof EntityPlayerMP)) {
return;
}
EntityPlayerMP player = (EntityPlayerMP) entity;
if (player.worldObj.isRemote) {
return;
}
FawePlayer fp = FawePlayer.wrap(player);
if (fp.getMeta("lastWorld") != event.getWorld()) {
fp.setMeta("lastWorld", event.getWorld());
if (Settings.HISTORY.USE_DISK) {
fp.getSession().clearHistory();
fp.loadSessionsFromDisk(fp.getWorld());
}
}
}
}

View File

@ -0,0 +1,481 @@
/*
* Copyright 2011-2013 Tyler Blair. All rights reserved.
* Ported to Minecraft Forge by Mike Primm
* 1.7.x update by Dries007
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and contributors and should not be interpreted as representing official policies,
* either expressed or implied, of anybody else.
*/
package com.boydti.fawe.forge;
import com.boydti.fawe.util.MainUtil;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.UUID;
import java.util.zip.GZIPOutputStream;
import net.minecraft.server.MinecraftServer;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
public class ForgeMetrics {
/**
* The current revision number
*/
private final static int REVISION = 7;
/**
* The base url of the metrics domain
*/
private static final String BASE_URL = "http://report.mcstats.org";
/**
* The url used to report a server's status
*/
private static final String REPORT_URL = "/plugin/%s";
/**
* Interval of time to ping (in minutes)
*/
private static final int PING_INTERVAL = 15;
/**
* The mod this metrics submits for
*/
private final String modName;
private final String modVersion;
/**
* The metrics configuration file
*/
private final Configuration configuration;
/**
* The metrics configuration file
*/
private final File configurationFile;
/**
* Unique server id
*/
private final String guid;
/**
* Debug mode
*/
private final boolean debug;
private Thread thread = null;
private boolean firstPost = true;
int tickCount;
public ForgeMetrics(final String modName, final String modVersion) throws IOException {
if (modName == null || modVersion == null) {
throw new IllegalArgumentException("modName and modVersion cannot be null");
}
this.modName = modName;
this.modVersion = modVersion;
// load the config
configurationFile = getConfigFile();
configuration = new Configuration(configurationFile);
// Get values, and add some defaults, if needed
configuration.get(Configuration.CATEGORY_GENERAL, "opt-out", false, "Set to true to disable all reporting");
guid = configuration.get(Configuration.CATEGORY_GENERAL, "guid", UUID.randomUUID().toString(), "Server unique ID").getString();
debug = configuration.get(Configuration.CATEGORY_GENERAL, "debug", false, "Set to true for verbose debug").getBoolean(false);
configuration.save();
}
/**
* Start measuring statistics. This will immediately create an async
* repeating task as the plugin and send the initial data to the metrics
* backend, and then after that it will post in increments of PING_INTERVAL
* * 1200 ticks.
*
* @return True if statistics measuring is running, otherwise false.
*/
public boolean start() {
// Did we opt out?
if (isOptOut()) {
return false;
}
FMLCommonHandler.instance().bus().register(this);
return true;
}
@SubscribeEvent
public void tick(TickEvent.ServerTickEvent tick) {
if (tick.phase != TickEvent.Phase.END) return;
if (tickCount++ % (PING_INTERVAL * 1200) != 0) return;
if (thread == null) {
thread = new Thread(new Runnable() {
public void run() {
try {
// Disable Task, if it is running and the server owner decided
// to opt-out
if (isOptOut()) {
FMLCommonHandler.instance().bus().unregister(ForgeMetrics.this);
return;
}
// We use the inverse of firstPost because if it
// is the first time we are posting,
// it is not a interval ping, so it evaluates to
// FALSE
// Each time thereafter it will evaluate to
// TRUE, i.e PING!
postPlugin(!firstPost);
// After the first post we set firstPost to
// false
// Each post thereafter will be a ping
firstPost = false;
} catch (IOException e) {
if (debug) {
FMLLog.info("[Metrics] Exception - %s", e.getMessage());
}
} finally {
thread = null;
}
}
});
thread.start();
}
}
/**
* Stop processing
*/
public void stop() {
}
/**
* Has the server owner denied plugin metrics?
*
* @return true if metrics should be opted out of it
*/
public boolean isOptOut() {
// Reload the metrics file
configuration.load();
return configuration.get(Configuration.CATEGORY_GENERAL, "opt-out", false).getBoolean(false);
}
/**
* Enables metrics for the server by setting "opt-out" to false in the
* config file and starting the metrics task.
*
* @throws java.io.IOException
*/
public void enable() throws IOException {
// Check if the server owner has already set opt-out, if not, set it.
if (isOptOut()) {
configuration.getCategory(Configuration.CATEGORY_GENERAL).get("opt-out").set("false");
configuration.save();
}
// Enable Task, if it is not running
FMLCommonHandler.instance().bus().register(this);
}
/**
* Disables metrics for the server by setting "opt-out" to true in the
* config file and canceling the metrics task.
*
* @throws java.io.IOException
*/
public void disable() throws IOException {
// Check if the server owner has already set opt-out, if not, set it.
if (!isOptOut()) {
configuration.getCategory(Configuration.CATEGORY_GENERAL).get("opt-out").set("true");
configuration.save();
}
FMLCommonHandler.instance().bus().unregister(this);
}
/**
* Gets the File object of the config file that should be used to store data
* such as the GUID and opt-out status
*
* @return the File object for the config file
*/
public File getConfigFile() {
return new File(Loader.instance().getConfigDir(), "PluginMetrics.cfg");
}
/**
* Generic method that posts a plugin to the metrics website
*/
private void postPlugin(final boolean isPing) throws IOException {
// Server software specific section
String pluginName = modName;
MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
boolean onlineMode = server.isServerInOnlineMode();
String pluginVersion = modVersion;
String serverVersion;
if (server.isDedicatedServer()) {
serverVersion = "MinecraftForge (MC: " + server.getMinecraftVersion() + ")";
} else {
serverVersion = "MinecraftForgeSSP (MC: " + server.getMinecraftVersion() + ")";
}
int playersOnline = server.getCurrentPlayerCount();
// END server software specific section -- all code below does not use any code outside of this class / Java
// Construct the post data
StringBuilder json = new StringBuilder(1024);
json.append('{');
// The plugin's description file containg all of the plugin data such as name, version, author, etc
appendJSONPair(json, "guid", guid);
appendJSONPair(json, "plugin_version", pluginVersion);
appendJSONPair(json, "server_version", serverVersion);
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
// New data as of R6
String osname = System.getProperty("os.name");
String osarch = System.getProperty("os.arch");
String osversion = System.getProperty("os.version");
String java_version = System.getProperty("java.version");
int coreCount = Runtime.getRuntime().availableProcessors();
// normalize os arch .. amd64 -> x86_64
if (osarch.equals("amd64")) {
osarch = "x86_64";
}
appendJSONPair(json, "osname", osname);
appendJSONPair(json, "osarch", osarch);
appendJSONPair(json, "osversion", osversion);
appendJSONPair(json, "cores", Integer.toString(coreCount));
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
appendJSONPair(json, "java_version", java_version);
// If we're pinging, append it
if (isPing) {
appendJSONPair(json, "ping", "1");
}
// close json
json.append('}');
// Create the url
URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
// Connect to the website
URLConnection connection;
// Mineshafter creates a socks proxy, so we can safely bypass it
// It does not reroute POST requests so we need to go around it
if (isMineshafterPresent()) {
connection = url.openConnection(Proxy.NO_PROXY);
} else {
connection = url.openConnection();
}
byte[] uncompressed = json.toString().getBytes();
byte[] compressed = gzip(json.toString());
// Headers
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Content-Encoding", "gzip");
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
connection.addRequestProperty("Accept", "application/json");
connection.addRequestProperty("Connection", "close");
connection.setDoOutput(true);
// Write the data
OutputStream os = connection.getOutputStream();
os.write(compressed);
os.flush();
// Now read the response
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String response = reader.readLine();
// close resources
os.close();
reader.close();
if (response == null || response.startsWith("ERR") || response.startsWith("7")) {
if (response == null) {
response = "null";
} else if (response.startsWith("7")) {
response = response.substring(response.startsWith("7,") ? 2 : 1);
}
throw new IOException(response);
}
}
/**
* GZip compress a string of bytes
*
* @param input
* @return
*/
public static byte[] gzip(String input) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzos = null;
try {
gzos = new GZIPOutputStream(baos);
gzos.write(input.getBytes("UTF-8"));
} catch (IOException e) {
MainUtil.handleError(e);
} finally {
if (gzos != null) try {
gzos.close();
} catch (IOException ignore) {
}
}
return baos.toByteArray();
}
/**
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
*
* @return true if mineshafter is installed on the server
*/
private boolean isMineshafterPresent() {
try {
Class.forName("mineshafter.MineServer");
return true;
} catch (Exception e) {
return false;
}
}
/**
* Appends a json encoded key/value pair to the given string builder.
*
* @param json
* @param key
* @param value
* @throws java.io.UnsupportedEncodingException
*/
private static void appendJSONPair(StringBuilder json, String key, String value) throws UnsupportedEncodingException {
boolean isValueNumeric = false;
try {
if (value.equals("0") || !value.endsWith("0")) {
Double.parseDouble(value);
isValueNumeric = true;
}
} catch (NumberFormatException e) {
isValueNumeric = false;
}
if (json.charAt(json.length() - 1) != '{') {
json.append(',');
}
json.append(escapeJSON(key));
json.append(':');
if (isValueNumeric) {
json.append(value);
} else {
json.append(escapeJSON(value));
}
}
/**
* Escape a string to create a valid JSON string
*
* @param text
* @return
*/
private static String escapeJSON(String text) {
StringBuilder builder = new StringBuilder();
builder.append('"');
for (int index = 0; index < text.length(); index++) {
char chr = text.charAt(index);
switch (chr) {
case '"':
case '\\':
builder.append('\\');
builder.append(chr);
break;
case '\b':
builder.append("\\b");
break;
case '\t':
builder.append("\\t");
break;
case '\n':
builder.append("\\n");
break;
case '\r':
builder.append("\\r");
break;
default:
if (chr < ' ') {
String t = "000" + Integer.toHexString(chr);
builder.append("\\u" + t.substring(t.length() - 4));
} else {
builder.append(chr);
}
break;
}
}
builder.append('"');
return builder.toString();
}
/**
* Encode text as UTF-8
*
* @param text the text to encode
* @return the encoded text, as UTF-8
*/
private static String urlEncode(final String text) throws UnsupportedEncodingException {
return URLEncoder.encode(text, "UTF-8");
}
}

View File

@ -0,0 +1,78 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.config.Settings;
import com.boydti.fawe.object.FaweLocation;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.wrappers.PlayerWrapper;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.forge.ForgeWorldEdit;
import java.util.UUID;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentBase;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
public class ForgePlayer extends FawePlayer<EntityPlayerMP> {
public ForgePlayer(EntityPlayerMP parent) {
super(parent);
}
@Override
public void sendTitle(String head, String sub) { // Not supported
Settings.QUEUE.PROGRESS.DISPLAY = false;
}
@Override
public void resetTitle() { // Not supported
Settings.QUEUE.PROGRESS.DISPLAY = false;
}
@Override
public String getName() {
return parent.getName();
}
@Override
public UUID getUUID() {
return parent.getUniqueID();
}
@Override
public boolean hasPermission(String perm) {
Object meta = getMeta(perm);
return meta instanceof Boolean ? (boolean) meta : ForgeWorldEdit.inst.getPermissionsProvider().hasPermission(parent, perm);
}
@Override
public void setPermission(String perm, boolean flag) {
setMeta(perm, flag);
}
@Override
public void sendMessage(String msg) {
for (String part : msg.split("\n")) {
part = BBC.color(part);
TextComponentBase text = new TextComponentString(part);
this.parent.addChatMessage(text);
}
}
@Override
public void executeCommand(String substring) {
throw new UnsupportedOperationException("NOT IMPLEMENTED");
}
@Override
public FaweLocation getLocation() {
World world = parent.worldObj;
BlockPos pos = parent.getPosition();
return new FaweLocation(world.getWorldInfo().getWorldName(), pos.getX(), pos.getY(), pos.getZ());
}
@Override
public Player getPlayer() {
return PlayerWrapper.wrap(ForgeWorldEdit.inst.wrap(this.parent));
}
}

View File

@ -0,0 +1,168 @@
package com.boydti.fawe.forge;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.TaskManager;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.EventPriority;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
public class ForgeTaskMan extends TaskManager {
private final ConcurrentLinkedDeque<Runnable> syncTasks = new ConcurrentLinkedDeque<>();
private final ConcurrentLinkedDeque<Runnable> asyncTasks = new ConcurrentLinkedDeque<>();
private final ConcurrentHashMap<Integer, Runnable> taskIdMap = new ConcurrentHashMap<>();
private final AtomicInteger taskId = new AtomicInteger();
private final ExecutorService executor;
public ForgeTaskMan(int size) {
this.executor = Executors.newFixedThreadPool(size);
FMLCommonHandler.instance().bus().register(this);
}
@Override
public int repeat(final Runnable r, final int interval) {
if (r == null) {
return -1;
}
int id = taskId.incrementAndGet();
taskIdMap.put(id, r);
task(new Runnable() {
@Override
public void run() {
if (!taskIdMap.containsKey(id)) {
return;
}
try {
r.run();
} catch (Throwable e) {
MainUtil.handleError(e);
}
later(this, interval);
}
});
return id;
}
@SubscribeEvent(priority = EventPriority.HIGHEST)
public void onServerTick(TickEvent.ServerTickEvent event) {
Fawe.get().setMainThread();
int asyncSize = asyncTasks.size();
for (int i = 0; i < asyncSize; i++) {
Runnable item = asyncTasks.poll();
if (item != null) {
async(item);
}
}
int syncSize = syncTasks.size();
for (int i = 0; i < syncSize; i++) {
Runnable item = syncTasks.poll();
if (item != null) {
try {
item.run();
} catch (Throwable e) {
MainUtil.handleError(e);
}
}
}
}
@Override
public int repeatAsync(Runnable r, int interval) {
if (r == null) {
return -1;
}
int id = taskId.incrementAndGet();
taskIdMap.put(id, r);
async(new Runnable() {
@Override
public void run() {
if (!taskIdMap.containsKey(id)) {
return;
}
try {
r.run();
} catch (Throwable e) {
MainUtil.handleError(e);
}
laterAsync(this, interval);
}
});
return id;
}
@Override
public void async(Runnable r) {
if (r == null) {
return;
}
executor.execute(r);
}
@Override
public void task(Runnable r) {
if (r == null) {
return;
}
syncTasks.add(r);
}
@Override
public void later(Runnable r, int delay) {
if (r == null) {
return;
}
AtomicInteger remaining = new AtomicInteger(delay);
task(new Runnable() {
@Override
public void run() {
if (remaining.decrementAndGet() <= 0) {
try {
r.run();
} catch (Throwable e) {
MainUtil.handleError(e);
}
return;
}
task(this);
}
});
}
@Override
public void laterAsync(Runnable r, int delay) {
if (r == null) {
return;
}
AtomicInteger remaining = new AtomicInteger(delay);
task(new Runnable() {
@Override
public void run() {
if (remaining.decrementAndGet() <= 0) {
try {
async(r);
} catch (Throwable e) {
MainUtil.handleError(e);
}
return;
}
task(this);
}
});
}
@Override
public void cancel(int task) {
taskIdMap.remove(task);
}
}

View File

@ -0,0 +1,114 @@
package com.boydti.fawe.forge.v0;
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.Field;
import net.minecraft.block.Block;
import net.minecraft.util.BitArray;
import net.minecraft.world.World;
import net.minecraft.world.chunk.BlockStateContainer;
import net.minecraft.world.chunk.BlockStatePaletteRegistry;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IBlockStatePalette;
public class ForgeChunk_All extends CharFaweChunk<Chunk> {
public BlockStateContainer[] sectionPalettes;
/**
* A FaweSections object represents a chunk and the blocks that you wish to change in it.
*
* @param parent
* @param x
* @param z
*/
public ForgeChunk_All(FaweQueue parent, int x, int z) {
super(parent, x, z);
}
@Override
public Chunk getNewChunk() {
World world = ((ForgeQueue_All) getParent()).getWorld();
return world.getChunkProvider().provideChunk(getX(), getZ());
}
@Override
public CharFaweChunk<Chunk> copy(boolean shallow) {
ForgeChunk_All value = (ForgeChunk_All) super.copy(shallow);
if (sectionPalettes != null) {
value.sectionPalettes = new BlockStateContainer[16];
try {
Field fieldBits = BlockStateContainer.class.getDeclaredField("storage");
fieldBits.setAccessible(true);
Field fieldPalette = BlockStateContainer.class.getDeclaredField("palette");
fieldPalette.setAccessible(true);
Field fieldSize = BlockStateContainer.class.getDeclaredField("bits");
fieldSize.setAccessible(true);
for (int i = 0; i < sectionPalettes.length; i++) {
BlockStateContainer current = sectionPalettes[i];
if (current == null) {
continue;
}
// Clone palette
IBlockStatePalette currentPalette = (IBlockStatePalette) fieldPalette.get(current);
if (!(currentPalette instanceof BlockStatePaletteRegistry)) {
current.onResize(128, null);
}
BlockStateContainer paletteBlock = new BlockStateContainer();
currentPalette = (IBlockStatePalette) fieldPalette.get(current);
if (!(currentPalette instanceof BlockStatePaletteRegistry)) {
throw new RuntimeException("Palette must be global!");
}
fieldPalette.set(paletteBlock, currentPalette);
// Clone size
fieldSize.set(paletteBlock, fieldSize.get(current));
// Clone palette
BitArray currentBits = (BitArray) fieldBits.get(current);
BitArray newBits = new BitArray(1, 0);
for (Field field : BitArray.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 void optimize() {
if (sectionPalettes != null) {
return;
}
char[][] arrays = getCombinedIdArrays();
char lastChar = Character.MAX_VALUE;
for (int layer = 0; layer < 16; layer++) {
if (getCount(layer) > 0) {
if (sectionPalettes == null) {
sectionPalettes = new BlockStateContainer[16];
}
BlockStateContainer palette = new BlockStateContainer();
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.set(x, y, z, Block.getBlockById(combinedId >> 4).getStateFromMeta(combinedId & 0xF));
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,702 @@
package com.boydti.fawe.forge.v0;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.example.CharFaweChunk;
import com.boydti.fawe.example.NMSMappedFaweQueue;
import com.boydti.fawe.object.BytePair;
import com.boydti.fawe.object.FaweChunk;
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 java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
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.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityTracker;
import net.minecraft.entity.EntityTrackerEntry;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.play.server.SPacketChunkData;
import net.minecraft.network.play.server.SPacketDestroyEntities;
import net.minecraft.server.management.PlayerChunkMap;
import net.minecraft.server.management.PlayerChunkMapEntry;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BitArray;
import net.minecraft.util.ClassInheritanceMultiMap;
import net.minecraft.util.IntHashMap;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.BlockStateContainer;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IBlockStatePalette;
import net.minecraft.world.chunk.IChunkGenerator;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.chunk.NibbleArray;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraft.world.gen.ChunkProviderServer;
import net.minecraftforge.fml.common.FMLCommonHandler;
public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlockStorage[], BlockStateContainer> {
private Method methodFromNative;
private Method methodToNative;
public ForgeQueue_All(String world) {
super(world);
try {
Class<?> converter = Class.forName("com.sk89q.worldedit.forge.NBTConverter");
this.methodFromNative = converter.getDeclaredMethod("toNative", Tag.class);
this.methodToNative = converter.getDeclaredMethod("fromNative", NBTBase.class);
methodFromNative.setAccessible(true);
methodToNative.setAccessible(true);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
private BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(0, 0, 0);
@Override
public CompoundTag getTileEntity(Chunk chunk, int x, int y, int z) {
Map<BlockPos, TileEntity> tiles = chunk.getTileEntityMap();
pos.setPos(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.readFromNBT(tag); // readTagIntoEntity
return (CompoundTag) methodToNative.invoke(null, tag);
} catch (Exception e) {
MainUtil.handleError(e);
return null;
}
}
@Override
public Chunk getChunk(World world, int x, int z) {
Chunk chunk = world.getChunkProvider().provideChunk(x, z);
if (chunk != null && !chunk.isLoaded()) {
chunk.onChunkLoad();
}
return chunk;
}
@Override
public boolean isChunkLoaded(int x, int z) {
return getWorld().getChunkProvider().getLoadedChunk(x, z) != null;
}
@Override
public boolean regenerateChunk(World world, int x, int z) {
IChunkProvider provider = world.getChunkProvider();
if (!(provider instanceof ChunkProviderServer)) {
return false;
}
try {
ChunkProviderServer chunkServer = (ChunkProviderServer) provider;
IChunkGenerator gen = chunkServer.chunkGenerator;
long pos = ChunkPos.chunkXZ2Int(x, z);
Chunk mcChunk;
if (chunkServer.chunkExists(x, z)) {
mcChunk = chunkServer.loadChunk(x, z);
mcChunk.onChunkUnload();
}
PlayerChunkMap playerManager = ((WorldServer) getWorld()).getPlayerChunkMap();
List<EntityPlayerMP> oldWatchers = null;
if (chunkServer.chunkExists(x, z)) {
mcChunk = chunkServer.loadChunk(x, z);
PlayerChunkMapEntry entry = playerManager.getEntry(x, z);
if (entry != null) {
Field fieldPlayers = PlayerChunkMap.class.getDeclaredField("players");
fieldPlayers.setAccessible(true);
oldWatchers = (List<EntityPlayerMP>) fieldPlayers.get(entry);
playerManager.removeEntry(entry);
}
mcChunk.onChunkUnload();
}
try {
Field droppedChunksSetField = chunkServer.getClass().getDeclaredField("field_73248_b");
droppedChunksSetField.setAccessible(true);
Set droppedChunksSet = (Set) droppedChunksSetField.get(chunkServer);
droppedChunksSet.remove(pos);
} catch (Throwable e) {
MainUtil.handleError(e);
}
chunkServer.id2ChunkMap.remove(pos);
mcChunk = gen.provideChunk(x, z);
chunkServer.id2ChunkMap.put(pos, mcChunk);
if (mcChunk != null) {
mcChunk.onChunkLoad();
mcChunk.populateChunk(chunkServer, chunkServer.chunkGenerator);
}
if (oldWatchers != null) {
for (EntityPlayerMP player : oldWatchers) {
playerManager.addPlayer(player);
}
}
return true;
} catch (Throwable t) {
MainUtil.handleError(t);
return false;
}
}
@Override
public boolean loadChunk(World world, int x, int z, boolean generate) {
return getCachedSections(world, x, z) != null;
}
@Override
public ExtendedBlockStorage[] getCachedSections(World world, int x, int z) {
Chunk chunk = world.getChunkProvider().provideChunk(x, z);
if (chunk != null && !chunk.isLoaded()) {
chunk.onChunkLoad();
}
return chunk == null ? null : chunk.getBlockStorageArray();
}
@Override
public BlockStateContainer getCachedSection(ExtendedBlockStorage[] chunk, int cy) {
ExtendedBlockStorage value = chunk[cy];
return value == null ? null : value.getData();
}
@Override
public int getCombinedId4Data(BlockStateContainer ls, int x, int y, int z) {
IBlockState ibd = lastSection.get(x & 15, y & 15, z & 15);
Block block = ibd.getBlock();
int id = Block.getIdFromBlock(block);
if (FaweCache.hasData(id)) {
return (id << 4) + block.getMetaFromState(ibd);
} else {
return id << 4;
}
}
@Override
public boolean isChunkLoaded(World world, int x, int z) {
return world.getChunkProvider().getLoadedChunk(x, z) != null;
}
public void setCount(int tickingBlockCount, int nonEmptyBlockCount, ExtendedBlockStorage section) throws NoSuchFieldException, IllegalAccessException {
Class<? extends ExtendedBlockStorage> clazz = section.getClass();
Field fieldTickingBlockCount = clazz.getDeclaredField("field_76683_c");
Field fieldNonEmptyBlockCount = clazz.getDeclaredField("field_76682_b");
fieldTickingBlockCount.setAccessible(true);
fieldNonEmptyBlockCount.setAccessible(true);
fieldTickingBlockCount.set(section, tickingBlockCount);
fieldNonEmptyBlockCount.set(section, nonEmptyBlockCount);
}
@Override
public CharFaweChunk getPrevious(CharFaweChunk fs, ExtendedBlockStorage[] sections, Map<?, ?> tilesGeneric, Collection<?>[] entitiesGeneric, Set<UUID> createdEntities, boolean all) throws Exception {
Map<BlockPos, TileEntity> tiles = (Map<BlockPos, TileEntity>) tilesGeneric;
ClassInheritanceMultiMap<Entity>[] entities = (ClassInheritanceMultiMap<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) {
ExtendedBlockStorage section = sections[layer];
if (section != null) {
short solid = 0;
char[] previousLayer = idPrevious[layer] = new char[4096];
BlockStateContainer blocks = section.getData();
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];
IBlockState ibd = blocks.get(x, y, z);
Block block = ibd.getBlock();
int combined = Block.getIdFromBlock(block);
if (FaweCache.hasData(combined)) {
combined = (combined << 4) + block.getMetaFromState(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;
if (tiles != null) {
for (Map.Entry<BlockPos, TileEntity> entry : tiles.entrySet()) {
TileEntity tile = entry.getValue();
NBTTagCompound tag = new NBTTagCompound();
tile.readFromNBT(tag); // readTileEntityIntoTag
BlockPos pos = entry.getKey();
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(null, tag);
previous.setTile(pos.getX(), pos.getY(), pos.getZ(), 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.posX) & 15);
int z = ((int) Math.round(ent.posZ) & 15);
int y = (int) Math.round(ent.posY);
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 = EntityList.getEntityString(ent);
if (id != null) {
NBTTagCompound tag = ent.getEntityData(); // readEntityIntoTag
CompoundTag nativeTag = (CompoundTag) methodToNative.invoke(null, tag);
Map<String, Tag> map = ReflectionUtils.getMap(nativeTag.getValue());
map.put("Id", new StringTag(id));
previous.setEntity(nativeTag);
}
}
}
}
}
return previous;
}
private final IBlockState air = Blocks.AIR.getDefaultState();
@Override
public boolean setComponents(FaweChunk fc, RunnableVal<FaweChunk> changeTask) {
ForgeChunk_All fs = (ForgeChunk_All) fc;
net.minecraft.world.chunk.Chunk nmsChunk = fs.getChunk();
nmsChunk.setModified(true);
net.minecraft.world.World nmsWorld = nmsChunk.getWorld();
try {
boolean flag = !nmsWorld.provider.getHasNoSky();
// Sections
ExtendedBlockStorage[] sections = nmsChunk.getBlockStorageArray();
Map<BlockPos, TileEntity> tiles = nmsChunk.getTileEntityMap();
ClassInheritanceMultiMap<Entity>[] entities = nmsChunk.getEntityLists();
// Remove entities
for (int i = 0; i < 16; i++) {
int count = fs.getCount(i);
if (count == 0) {
continue;
} else if (count >= 4096) {
entities[i] = new ClassInheritanceMultiMap<>(Entity.class);
} 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.posX) & 15);
int z = ((int) Math.round(entity.posZ) & 15);
int y = (int) Math.round(entity.posY);
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();
NBTTagCompound tag = (NBTTagCompound)methodFromNative.invoke(null, nativeTag);
Entity entity = EntityList.createEntityFromNBT(tag, nmsWorld);
if (entity != null) {
entity.setPositionAndRotation(x, y, z, yaw, pitch);
nmsWorld.spawnEntityInWorld(entity);
}
}
// 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<BlockPos, TileEntity>> entryset = tiles.entrySet();
Iterator<Map.Entry<BlockPos, TileEntity>> iterator = entryset.iterator();
while (iterator.hasNext()) {
Map.Entry<BlockPos, TileEntity> tile = iterator.next();
BlockPos 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().invalidate();;
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);
}
}
}
}
// Efficiently merge sections
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;
}
ExtendedBlockStorage section = sections[j];
if (section == null) {
if (fs.sectionPalettes != null && fs.sectionPalettes[j] != null) {
section = sections[j] = new ExtendedBlockStorage(j << 4, flag);
setPalette(section, fs.sectionPalettes[j]);
setCount(0, count - fs.getAir(j), section);
} else {
sections[j] = new ExtendedBlockStorage(j << 4, flag);
}
} 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] = new ExtendedBlockStorage(j << 4, flag);
}
}
BlockStateContainer nibble = section.getData();
Field fieldBits = BlockStateContainer.class.getDeclaredField("storage");
fieldBits.setAccessible(true);
BitArray bits = (BitArray) fieldBits.get(nibble);
Field fieldPalette = BlockStateContainer.class.getDeclaredField("palette");
fieldPalette.setAccessible(true);
IBlockStatePalette palette = (IBlockStatePalette) 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:
IBlockState existing = nibble.get(x, y, z);
if (existing != air) {
nonEmptyBlockCount++;
}
continue;
case 1:
nibble.set(x, y, z, air);
continue;
default:
nonEmptyBlockCount++;
nibble.set(x, y, z, Block.getBlockById(combinedId >> 4).getStateFromMeta(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.getBiomeArray()[((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();
BlockPos pos = new BlockPos(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(null, nativeTag);
tileEntity.readFromNBT(tag); // ReadTagIntoTile
}
}
} catch (Throwable e) {
MainUtil.handleError(e);
}
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.getBiomeArray()[((z & 0xF) << 4 | x & 0xF)] = (byte) biome;
}
}
}
sendChunk(fs, null);
return true;
}
public void setPalette(ExtendedBlockStorage section, BlockStateContainer palette) throws NoSuchFieldException, IllegalAccessException {
Field fieldSection = ExtendedBlockStorage.class.getDeclaredField("data");
fieldSection.setAccessible(true);
fieldSection.set(section, palette);
}
@Override
public void refreshChunk(World world, net.minecraft.world.chunk.Chunk nmsChunk) {
if (!nmsChunk.isLoaded()) {
return;
}
try {
ChunkPos pos = nmsChunk.getChunkCoordIntPair();
WorldServer w = (WorldServer) nmsChunk.getWorld();
PlayerChunkMap chunkMap = w.getPlayerChunkMap();
int x = pos.chunkXPos;
int z = pos.chunkZPos;
if (!chunkMap.contains(x, z)) {
return;
}
EntityTracker tracker = w.getEntityTracker();
HashSet<EntityPlayerMP> players = new HashSet<>();
for (EntityPlayer player : w.playerEntities) {
if (player instanceof EntityPlayerMP) {
if (chunkMap.isPlayerWatchingChunk((EntityPlayerMP) player, x, z)) {
players.add((EntityPlayerMP) player);
}
}
}
if (players.size() == 0) {
return;
}
HashSet<EntityTrackerEntry> entities = new HashSet<>();
ClassInheritanceMultiMap<Entity>[] entitieSlices = nmsChunk.getEntityLists();
IntHashMap<EntityTrackerEntry> entries = null;
for (Field field : tracker.getClass().getDeclaredFields()) {
if (field.getType() == IntHashMap.class) {
field.setAccessible(true);
entries = (IntHashMap<EntityTrackerEntry>) field.get(tracker);
}
}
for (ClassInheritanceMultiMap<Entity> slice : entitieSlices) {
if (slice == null) {
continue;
}
for (Entity ent : slice) {
EntityTrackerEntry entry = entries != null ? entries.lookup(ent.getEntityId()) : null;
if (entry == null) {
continue;
}
entities.add(entry);
SPacketDestroyEntities packet = new SPacketDestroyEntities(ent.getEntityId());
for (EntityPlayerMP player : players) {
player.connection.sendPacket(packet);
}
}
}
// Send chunks
SPacketChunkData packet = new SPacketChunkData(nmsChunk, 65535);
for (EntityPlayerMP player : players) {
player.connection.sendPacket(packet);
}
// send ents
for (EntityTrackerEntry entry : entities) {
try {
TaskManager.IMP.later(new Runnable() {
@Override
public void run() {
for (EntityPlayerMP player : players) {
boolean result = entry.trackingPlayers.remove(player);
if (result && entry.getTrackedEntity() != player) {
entry.updatePlayerEntity(player);
}
}
}
}, 2);
} catch (Throwable e) {
MainUtil.handleError(e);
}
}
} catch (Throwable e) {
MainUtil.handleError(e);
}
}
@Override
public FaweChunk<Chunk> getFaweChunk(int x, int z) {
return new ForgeChunk_All(this, x, z);
}
@Override
public boolean removeLighting(ExtendedBlockStorage[] sections, RelightMode mode, boolean sky) {
if (mode == RelightMode.ALL) {
for (int i = 0; i < sections.length; i++) {
ExtendedBlockStorage section = sections[i];
if (section != null) {
section.setBlocklightArray(new NibbleArray());
if (sky) {
section.setSkylightArray(new NibbleArray());
}
}
}
}
return true;
}
@Override
public boolean hasSky() {
return nmsWorld.provider.getHasNoSky();
}
@Override
public boolean initLighting(Chunk nmsChunk, ExtendedBlockStorage[] sections, RelightMode mode) {
if (mode == RelightMode.ALL) {
nmsChunk.generateSkylightMap();
} else {
int i = nmsChunk.getTopFilledSegment();
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 = nmsChunk.getBlockLightOpacity(new BlockPos(x, y, z));
if (opacity == 0 && l != 15) {
opacity = 1;
}
l -= opacity;
if (l > 0) {
ExtendedBlockStorage section = sections[y >> 4];
if (section != null) {
section.setExtSkylightValue(x, y & 15, z, l);
}
}
--y;
} while (y > 0 && l > 0);
}
}
}
return true;
}
@Override
public void setFullbright(ExtendedBlockStorage[] sections) {
for (int i = 0; i < sections.length; i++) {
ExtendedBlockStorage section = sections[i];
if (section != null) {
byte[] bytes = section.getSkylightArray().getData();
Arrays.fill(bytes, (byte) 255);
}
}
}
@Override
public int getSkyLight(ExtendedBlockStorage[] sections, int x, int y, int z) {
ExtendedBlockStorage section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 15;
}
return section.getExtSkylightValue(x, y & 15, z);
}
@Override
public int getEmmittedLight(ExtendedBlockStorage[] sections, int x, int y, int z) {
ExtendedBlockStorage section = sections[FaweCache.CACHE_I[y][x][z]];
if (section == null) {
return 0;
}
return section.getExtBlocklightValue(x, y & 15, z);
}
@Override
public void relight(int x, int y, int z) {
pos.setPos(x, y, z);
nmsWorld.checkLight(pos);
}
private WorldServer nmsWorld;
@Override
public World getImpWorld() {
WorldServer[] worlds = FMLCommonHandler.instance().getMinecraftServerInstance().worldServers;
for (WorldServer ws : worlds) {
if (ws.getWorldInfo().getWorldName().equals(getWorldName())) {
return nmsWorld = ws;
}
}
return null;
}
}

View File

View File

@ -1,3 +1,3 @@
rootProject.name = 'FastAsyncWorldEdit'
include 'core', 'bukkit0', 'bukkit19', 'bukkit110', 'bukkit18', 'forge189', 'forge1710', 'sponge'
include 'core', 'bukkit0', 'bukkit1710', 'bukkit18', 'bukkit19', 'bukkit110', 'forge1710', 'forge189', 'forge194', 'forge110'