mirror of
https://github.com/boy0001/FastAsyncWorldedit.git
synced 2024-11-28 13:45:36 +01:00
Relight improvements + ports
6 lighting modes (0-5), see config forge194 forge110 bukkit1710 (untested)
This commit is contained in:
parent
bdff04cff4
commit
c52c1bee27
@ -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"}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,46 +269,38 @@ 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();
|
||||
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 (flag) {
|
||||
section.b(new NibbleArray());
|
||||
section.a(new NibbleArray()); // Emitted
|
||||
if (sky) {
|
||||
section.b(new NibbleArray()); // Skylight
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@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 {
|
||||
int i = c.g();
|
||||
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) {
|
||||
int l = 15;
|
||||
int y = i + 16 - 1;
|
||||
y = i2;
|
||||
l = 15;
|
||||
do {
|
||||
int opacity = c.a(x, y, z).c();
|
||||
opacity = c.a(x, y, z).c();
|
||||
if (opacity == 0 && l != 15) {
|
||||
opacity = 1;
|
||||
}
|
||||
@ -324,121 +316,51 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], DataP
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (((bc.getTotalRelight() == 0) && mode == RelightMode.MINIMAL)) {
|
||||
return true;
|
||||
}
|
||||
if (mode == RelightMode.ALL) {
|
||||
bc = getPrevious(bc, c.getSections(), null, null, null, true);
|
||||
|
||||
@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);
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(ChunkSection[] sections, int x, int y, int z) {
|
||||
ChunkSection section = sections[FaweCache.CACHE_I[y][x][z]];
|
||||
if (section == null) {
|
||||
continue;
|
||||
return 15;
|
||||
}
|
||||
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 section.b(x, y & 15, z);
|
||||
}
|
||||
|
||||
public boolean isSurrounded(final char[][] sections, final int x, final int y, final int z) {
|
||||
return this.isSolid(this.getId(sections, x, y + 1, z))
|
||||
&& this.isSolid(this.getId(sections, x + 1, y - 1, z))
|
||||
&& this.isSolid(this.getId(sections, x - 1, y, z))
|
||||
&& this.isSolid(this.getId(sections, x, y, z + 1))
|
||||
&& this.isSolid(this.getId(sections, x, y, z - 1));
|
||||
}
|
||||
|
||||
public boolean isSolid(final int i) {
|
||||
if (i != 0) {
|
||||
final Material material = Material.getMaterial(i);
|
||||
return (material != null) && Material.getMaterial(i).isOccluding();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getId(final char[][] sections, final int x, final int y, final int z) {
|
||||
if ((x < 0) || (x > 15) || (z < 0) || (z > 15)) {
|
||||
return 1;
|
||||
}
|
||||
if ((y < 0) || (y > 255)) {
|
||||
return 1;
|
||||
}
|
||||
final int i = FaweCache.CACHE_I[y][x][z];
|
||||
final char[] section = sections[i];
|
||||
@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
32
bukkit1710/build.gradle
Normal 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);
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
122
bukkit1710/src/main/resources/plugin.yml
Normal file
122
bukkit1710/src/main/resources/plugin.yml
Normal 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
|
@ -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,41 +504,100 @@ 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;
|
||||
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 (flag) {
|
||||
if (sky) {
|
||||
section.b(new NibbleArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
if (mode == RelightMode.ALL) {
|
||||
nmsChunk.initLighting();
|
||||
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);
|
||||
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 {
|
||||
int i = nmsChunk.g();
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@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 = nmsChunk.getTypeAbs(x, y, z).p();
|
||||
int opacity = c.getTypeAbs(x, y, z).p();
|
||||
if (opacity == 0 && l != 15) {
|
||||
opacity = 1;
|
||||
}
|
||||
@ -528,117 +613,41 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], char[]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
@Override
|
||||
public int getSkyLight(ChunkSection[] sections, int x, int y, int z) {
|
||||
ChunkSection section = sections[FaweCache.CACHE_I[y][x][z]];
|
||||
if (section == null) {
|
||||
continue;
|
||||
return 15;
|
||||
}
|
||||
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 section.d(x, y & 15, z);
|
||||
}
|
||||
|
||||
public boolean isSurrounded(ChunkSection[] sections, int x, int y, int z) {
|
||||
return isSolid(getId(sections, x, y + 1, z))
|
||||
&& isSolid(getId(sections, x + 1, y - 1, z))
|
||||
&& isSolid(getId(sections, x - 1, y, z))
|
||||
&& isSolid(getId(sections, x, y, z + 1))
|
||||
&& isSolid(getId(sections, x, y, z - 1));
|
||||
}
|
||||
|
||||
public boolean isSolid(int i) {
|
||||
return Material.getMaterial(i).isOccluding();
|
||||
}
|
||||
|
||||
public int getId(ChunkSection[] sections, int x, int y, int z) {
|
||||
if (x < 0 || x > 15 || z < 0 || z > 15) {
|
||||
return 1;
|
||||
}
|
||||
if (y < 0 || y > 255) {
|
||||
return 1;
|
||||
}
|
||||
int i = FaweCache.CACHE_I[y][x][z];
|
||||
ChunkSection section = sections[i];
|
||||
@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
|
||||
|
@ -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,34 +202,101 @@ 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;
|
||||
if (folder.exists() && !folder.isDirectory()) {
|
||||
throw new IllegalArgumentException("File exists with the name '" + name + "' and isn't a folder");
|
||||
}
|
||||
chunk.load(false);
|
||||
if (generator == null) {
|
||||
generator = server.getGenerator(name);
|
||||
}
|
||||
net.minecraft.server.v1_9_R2.Chunk c = ((CraftChunk) chunk).getHandle();
|
||||
final boolean flag = chunk.getWorld().getEnvironment() == Environment.NORMAL;
|
||||
ChunkSection[] sections = c.getSections();
|
||||
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;
|
||||
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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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 (flag) {
|
||||
if (sky) {
|
||||
section.b(new NibbleArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
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 {
|
||||
@ -240,89 +322,41 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Dat
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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];
|
||||
|
||||
|
||||
@Override
|
||||
public int getSkyLight(ChunkSection[] sections, int x, int y, int z) {
|
||||
ChunkSection section = sections[FaweCache.CACHE_I[y][x][z]];
|
||||
if (section == null) {
|
||||
continue;
|
||||
return 15;
|
||||
}
|
||||
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;
|
||||
return section.b(x, y & 15, z);
|
||||
}
|
||||
final char[] array = bc.getIdArray(j);
|
||||
if (array == null) {
|
||||
continue;
|
||||
|
||||
@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;
|
||||
}
|
||||
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;
|
||||
return section.c(x, y & 15, z);
|
||||
}
|
||||
pos.c(X + x, y, Z + z);
|
||||
w.w(pos);
|
||||
|
||||
@Override
|
||||
public void relight(int x, int y, int z) {
|
||||
pos.c(x, y, z);
|
||||
nmsWorld.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;
|
||||
|
||||
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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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 ======");
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
88
forge110/build.gradle
Normal 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)
|
161
forge110/src/main/java/com/boydti/fawe/forge/FaweForge.java
Normal file
161
forge110/src/main/java/com/boydti/fawe/forge/FaweForge.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
75
forge110/src/main/java/com/boydti/fawe/forge/ForgeMain.java
Normal file
75
forge110/src/main/java/com/boydti/fawe/forge/ForgeMain.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
481
forge110/src/main/java/com/boydti/fawe/forge/ForgeMetrics.java
Normal file
481
forge110/src/main/java/com/boydti/fawe/forge/ForgeMetrics.java
Normal 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");
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
168
forge110/src/main/java/com/boydti/fawe/forge/ForgeTaskMan.java
Normal file
168
forge110/src/main/java/com/boydti/fawe/forge/ForgeTaskMan.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
0
forge110/src/main/resources/config.yml
Normal file
0
forge110/src/main/resources/config.yml
Normal 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,31 +588,28 @@ 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();
|
||||
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 (flag) {
|
||||
if (sky) {
|
||||
section.setSkylightArray(new NibbleArray(4096, 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSky() {
|
||||
return nmsWorld.provider.hasNoSky;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean initLighting(Chunk nmsChunk, ExtendedBlockStorage[] sections, RelightMode mode) {
|
||||
if (mode == RelightMode.ALL) {
|
||||
nmsChunk.generateSkylightMap();
|
||||
} else {
|
||||
@ -648,108 +635,53 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (y < 0 || y > 255) {
|
||||
return 1;
|
||||
}
|
||||
int i = FaweCache.CACHE_I[y][x][z];
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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
86
forge194/build.gradle
Normal 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
|
||||
}
|
161
forge194/src/main/java/com/boydti/fawe/forge/FaweForge.java
Normal file
161
forge194/src/main/java/com/boydti/fawe/forge/FaweForge.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
75
forge194/src/main/java/com/boydti/fawe/forge/ForgeMain.java
Normal file
75
forge194/src/main/java/com/boydti/fawe/forge/ForgeMain.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
481
forge194/src/main/java/com/boydti/fawe/forge/ForgeMetrics.java
Normal file
481
forge194/src/main/java/com/boydti/fawe/forge/ForgeMetrics.java
Normal 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");
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
168
forge194/src/main/java/com/boydti/fawe/forge/ForgeTaskMan.java
Normal file
168
forge194/src/main/java/com/boydti/fawe/forge/ForgeTaskMan.java
Normal 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);
|
||||
}
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
0
forge194/src/main/resources/config.yml
Normal file
0
forge194/src/main/resources/config.yml
Normal 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'
|
||||
|
Loading…
Reference in New Issue
Block a user