Add speicifying biome/seed for regen command
//regen //regen forest //regen desert 5336
This commit is contained in:
parent
dcc0c15c03
commit
76e037492b
@ -13,6 +13,7 @@ import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
@ -169,7 +170,7 @@ public abstract class BukkitQueue_0<CHUNK, CHUNKSECTIONS, SECTION> extends NMSMa
|
||||
public void refreshChunk(FaweChunk fs) {}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z) {
|
||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||
return world.regenerateChunk(x, z);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
@ -24,11 +25,38 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
import net.minecraft.server.v1_10_R1.*;
|
||||
import net.minecraft.server.v1_10_R1.Block;
|
||||
import net.minecraft.server.v1_10_R1.BlockPosition;
|
||||
import net.minecraft.server.v1_10_R1.ChunkSection;
|
||||
import net.minecraft.server.v1_10_R1.DataBits;
|
||||
import net.minecraft.server.v1_10_R1.DataPaletteBlock;
|
||||
import net.minecraft.server.v1_10_R1.Entity;
|
||||
import net.minecraft.server.v1_10_R1.EntityPlayer;
|
||||
import net.minecraft.server.v1_10_R1.EntityTracker;
|
||||
import net.minecraft.server.v1_10_R1.EntityTypes;
|
||||
import net.minecraft.server.v1_10_R1.EnumDifficulty;
|
||||
import net.minecraft.server.v1_10_R1.EnumGamemode;
|
||||
import net.minecraft.server.v1_10_R1.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_10_R1.IBlockData;
|
||||
import net.minecraft.server.v1_10_R1.IDataManager;
|
||||
import net.minecraft.server.v1_10_R1.MinecraftServer;
|
||||
import net.minecraft.server.v1_10_R1.NBTTagCompound;
|
||||
import net.minecraft.server.v1_10_R1.NibbleArray;
|
||||
import net.minecraft.server.v1_10_R1.PacketPlayOutMapChunk;
|
||||
import net.minecraft.server.v1_10_R1.PlayerChunk;
|
||||
import net.minecraft.server.v1_10_R1.PlayerChunkMap;
|
||||
import net.minecraft.server.v1_10_R1.ServerNBTManager;
|
||||
import net.minecraft.server.v1_10_R1.TileEntity;
|
||||
import net.minecraft.server.v1_10_R1.WorldData;
|
||||
import net.minecraft.server.v1_10_R1.WorldManager;
|
||||
import net.minecraft.server.v1_10_R1.WorldServer;
|
||||
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.World;
|
||||
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;
|
||||
@ -44,6 +72,14 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
|
||||
protected static Field fieldTickingBlockCount;
|
||||
protected static Field fieldNonEmptyBlockCount;
|
||||
protected static Field fieldSection;
|
||||
protected static Field fieldBiomes;
|
||||
protected static Field fieldChunkGenerator;
|
||||
protected static Field fieldSeed;
|
||||
protected static Field fieldBiomeCache;
|
||||
protected static Field fieldBiomes2;
|
||||
protected static Field fieldGenLayer1;
|
||||
protected static Field fieldGenLayer2;
|
||||
protected static MutableGenLayer genLayer;
|
||||
public static final IBlockData[] IBD_CACHE = new IBlockData[Character.MAX_VALUE];
|
||||
|
||||
static {
|
||||
@ -54,6 +90,22 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
|
||||
fieldSection.setAccessible(true);
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
|
||||
fieldBiomes = net.minecraft.server.v1_10_R1.ChunkProviderGenerate.class.getDeclaredField("C");
|
||||
fieldBiomes.setAccessible(true);
|
||||
fieldChunkGenerator = net.minecraft.server.v1_10_R1.ChunkProviderServer.class.getDeclaredField("chunkGenerator");
|
||||
fieldChunkGenerator.setAccessible(true);
|
||||
fieldSeed = net.minecraft.server.v1_10_R1.WorldData.class.getDeclaredField("e");
|
||||
fieldSeed.setAccessible(true);
|
||||
fieldBiomeCache = net.minecraft.server.v1_10_R1.WorldChunkManager.class.getDeclaredField("c");
|
||||
fieldBiomeCache.setAccessible(true);
|
||||
fieldBiomes2 = net.minecraft.server.v1_10_R1.WorldChunkManager.class.getDeclaredField("d");
|
||||
fieldBiomes2.setAccessible(true);
|
||||
fieldGenLayer1 = net.minecraft.server.v1_10_R1.WorldChunkManager.class.getDeclaredField("a") ;
|
||||
fieldGenLayer2 = net.minecraft.server.v1_10_R1.WorldChunkManager.class.getDeclaredField("b") ;
|
||||
fieldGenLayer1.setAccessible(true);
|
||||
fieldGenLayer2.setAccessible(true);
|
||||
|
||||
Field fieldAir = DataPaletteBlock.class.getDeclaredField("a");
|
||||
fieldAir.setAccessible(true);
|
||||
air = (IBlockData) fieldAir.get(null);
|
||||
@ -86,6 +138,53 @@ public class BukkitQueue_1_10 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
|
||||
getImpWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||
if (biome != null) {
|
||||
try {
|
||||
if (seed == null) {
|
||||
seed = world.getSeed();
|
||||
}
|
||||
nmsWorld.worldData.getSeed();
|
||||
boolean result;
|
||||
net.minecraft.server.v1_10_R1.ChunkProviderGenerate generator = new net.minecraft.server.v1_10_R1.ChunkProviderGenerate(nmsWorld, seed, false, "");
|
||||
Biome bukkitBiome = adapter.getBiome(biome.getId());
|
||||
net.minecraft.server.v1_10_R1.BiomeBase base = net.minecraft.server.v1_10_R1.BiomeBase.getBiome(biome.getId());
|
||||
fieldBiomes.set(generator, new net.minecraft.server.v1_10_R1.BiomeBase[]{base});
|
||||
boolean cold = base.getTemperature() <= 1;
|
||||
net.minecraft.server.v1_10_R1.ChunkGenerator existingGenerator = nmsWorld.getChunkProviderServer().chunkGenerator;
|
||||
long existingSeed = world.getSeed();
|
||||
{
|
||||
if (genLayer == null) genLayer = new MutableGenLayer(seed);
|
||||
genLayer.set(biome.getId());
|
||||
Object existingGenLayer1 = fieldGenLayer1.get(nmsWorld.getWorldChunkManager());
|
||||
Object existingGenLayer2 = fieldGenLayer2.get(nmsWorld.getWorldChunkManager());
|
||||
fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), genLayer);
|
||||
fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), genLayer);
|
||||
|
||||
fieldSeed.set(nmsWorld.worldData, seed);
|
||||
|
||||
ReflectionUtils.setFailsafeFieldValue(fieldBiomeCache, this.nmsWorld.getWorldChunkManager(), new net.minecraft.server.v1_10_R1.BiomeCache(this.nmsWorld.getWorldChunkManager()));
|
||||
|
||||
ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProviderServer(), generator);
|
||||
|
||||
result = getWorld().regenerateChunk(x, z);
|
||||
|
||||
ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProviderServer(), existingGenerator);
|
||||
|
||||
fieldSeed.set(nmsWorld.worldData, existingSeed);
|
||||
|
||||
fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), existingGenLayer1);
|
||||
fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), existingGenLayer2);
|
||||
}
|
||||
return result;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return super.regenerateChunk(world, x, z, biome, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightMap(FaweChunk chunk, byte[] heightMap) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk.getChunk();
|
||||
|
@ -0,0 +1,26 @@
|
||||
package com.boydti.fawe.bukkit.v1_10;
|
||||
|
||||
import java.util.Arrays;
|
||||
import net.minecraft.server.v1_10_R1.GenLayer;
|
||||
import net.minecraft.server.v1_10_R1.IntCache;
|
||||
|
||||
public class MutableGenLayer extends GenLayer {
|
||||
|
||||
private int biome;
|
||||
|
||||
public MutableGenLayer(long seed) {
|
||||
super(seed);
|
||||
}
|
||||
|
||||
public MutableGenLayer set(int biome) {
|
||||
this.biome = biome;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] a(int areaX, int areaY, int areaWidth, int areaHeight) {
|
||||
int[] biomes = IntCache.a(areaWidth * areaHeight);
|
||||
Arrays.fill(biomes, biome);
|
||||
return biomes;
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
@ -29,6 +30,7 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_11_R1.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_11_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_11_R1.CraftWorld;
|
||||
@ -44,6 +46,15 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
|
||||
protected static Field fieldTickingBlockCount;
|
||||
protected static Field fieldNonEmptyBlockCount;
|
||||
protected static Field fieldSection;
|
||||
protected static Field fieldBiomes;
|
||||
protected static Field fieldChunkGenerator;
|
||||
protected static Field fieldSeed;
|
||||
protected static Field fieldBiomeCache;
|
||||
protected static Field fieldBiomes2;
|
||||
protected static Field fieldGenLayer1;
|
||||
protected static Field fieldGenLayer2;
|
||||
protected static MutableGenLayer genLayer;
|
||||
|
||||
|
||||
public static final IBlockData[] IBD_CACHE = new IBlockData[Character.MAX_VALUE];
|
||||
|
||||
@ -56,6 +67,21 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
|
||||
fieldBiomes = ChunkProviderGenerate.class.getDeclaredField("D");
|
||||
fieldBiomes.setAccessible(true);
|
||||
fieldChunkGenerator = ChunkProviderServer.class.getDeclaredField("chunkGenerator");
|
||||
fieldChunkGenerator.setAccessible(true);
|
||||
fieldSeed = WorldData.class.getDeclaredField("e");
|
||||
fieldSeed.setAccessible(true);
|
||||
fieldBiomeCache = WorldChunkManager.class.getDeclaredField("d");
|
||||
fieldBiomeCache.setAccessible(true);
|
||||
fieldBiomes2 = WorldChunkManager.class.getDeclaredField("e");
|
||||
fieldBiomes2.setAccessible(true);
|
||||
fieldGenLayer1 = WorldChunkManager.class.getDeclaredField("b") ;
|
||||
fieldGenLayer2 = WorldChunkManager.class.getDeclaredField("c") ;
|
||||
fieldGenLayer1.setAccessible(true);
|
||||
fieldGenLayer2.setAccessible(true);
|
||||
|
||||
Field fieldAir = DataPaletteBlock.class.getDeclaredField("a");
|
||||
fieldAir.setAccessible(true);
|
||||
air = (IBlockData) fieldAir.get(null);
|
||||
@ -86,6 +112,53 @@ public class BukkitQueue_1_11 extends BukkitQueue_0<Chunk, ChunkSection[], Chunk
|
||||
getImpWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||
if (biome != null) {
|
||||
try {
|
||||
if (seed == null) {
|
||||
seed = world.getSeed();
|
||||
}
|
||||
nmsWorld.worldData.getSeed();
|
||||
boolean result;
|
||||
ChunkProviderGenerate generator = new ChunkProviderGenerate(nmsWorld, seed, false, "");
|
||||
Biome bukkitBiome = adapter.getBiome(biome.getId());
|
||||
BiomeBase base = BiomeBase.getBiome(biome.getId());
|
||||
fieldBiomes.set(generator, new BiomeBase[]{base});
|
||||
boolean cold = base.getTemperature() <= 1;
|
||||
net.minecraft.server.v1_11_R1.ChunkGenerator existingGenerator = nmsWorld.getChunkProviderServer().chunkGenerator;
|
||||
long existingSeed = world.getSeed();
|
||||
{
|
||||
if (genLayer == null) genLayer = new MutableGenLayer(seed);
|
||||
genLayer.set(biome.getId());
|
||||
Object existingGenLayer1 = fieldGenLayer1.get(nmsWorld.getWorldChunkManager());
|
||||
Object existingGenLayer2 = fieldGenLayer2.get(nmsWorld.getWorldChunkManager());
|
||||
fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), genLayer);
|
||||
fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), genLayer);
|
||||
|
||||
fieldSeed.set(nmsWorld.worldData, seed);
|
||||
|
||||
ReflectionUtils.setFailsafeFieldValue(fieldBiomeCache, this.nmsWorld.getWorldChunkManager(), new BiomeCache(this.nmsWorld.getWorldChunkManager()));
|
||||
|
||||
ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProviderServer(), generator);
|
||||
|
||||
result = getWorld().regenerateChunk(x, z);
|
||||
|
||||
ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProviderServer(), existingGenerator);
|
||||
|
||||
fieldSeed.set(nmsWorld.worldData, existingSeed);
|
||||
|
||||
fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), existingGenLayer1);
|
||||
fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), existingGenLayer2);
|
||||
}
|
||||
return result;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return super.regenerateChunk(world, x, z, biome, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightMap(FaweChunk chunk, byte[] heightMap) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk.getChunk();
|
||||
|
@ -0,0 +1,26 @@
|
||||
package com.boydti.fawe.bukkit.v1_11;
|
||||
|
||||
import java.util.Arrays;
|
||||
import net.minecraft.server.v1_11_R1.GenLayer;
|
||||
import net.minecraft.server.v1_11_R1.IntCache;
|
||||
|
||||
public class MutableGenLayer extends GenLayer {
|
||||
|
||||
private int biome;
|
||||
|
||||
public MutableGenLayer(long seed) {
|
||||
super(seed);
|
||||
}
|
||||
|
||||
public MutableGenLayer set(int biome) {
|
||||
this.biome = biome;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] a(int areaX, int areaY, int areaWidth, int areaHeight) {
|
||||
int[] biomes = IntCache.a(areaWidth * areaHeight);
|
||||
Arrays.fill(biomes, biome);
|
||||
return biomes;
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
@ -23,11 +24,34 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.server.v1_7_R4.*;
|
||||
import net.minecraft.server.v1_7_R4.Block;
|
||||
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.EntityTypes;
|
||||
import net.minecraft.server.v1_7_R4.EnumDifficulty;
|
||||
import net.minecraft.server.v1_7_R4.EnumGamemode;
|
||||
import net.minecraft.server.v1_7_R4.EnumSkyBlock;
|
||||
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.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.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_7_R4.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_7_R4.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_7_R4.CraftWorld;
|
||||
@ -41,6 +65,13 @@ public class BukkitQueue17 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkSec
|
||||
protected static Field fieldIds;
|
||||
protected static Field fieldTickingBlockCount;
|
||||
protected static Field fieldNonEmptyBlockCount;
|
||||
protected static Field fieldBiomes;
|
||||
protected static Field fieldSeed;
|
||||
protected static Field fieldBiomeCache;
|
||||
protected static Field fieldBiomes2;
|
||||
protected static Field fieldGenLayer1;
|
||||
protected static Field fieldGenLayer2;
|
||||
protected static com.boydti.fawe.bukkit.v1_7.MutableGenLayer genLayer;
|
||||
|
||||
static {
|
||||
try {
|
||||
@ -52,6 +83,19 @@ public class BukkitQueue17 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkSec
|
||||
fieldNonEmptyBlockCount = ChunkSection.class.getDeclaredField("nonEmptyBlockCount");
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
|
||||
fieldBiomes = net.minecraft.server.v1_7_R4.ChunkProviderGenerate.class.getDeclaredField("z");
|
||||
fieldBiomes.setAccessible(true);
|
||||
fieldSeed = net.minecraft.server.v1_7_R4.WorldData.class.getDeclaredField("seed");
|
||||
fieldSeed.setAccessible(true);
|
||||
fieldBiomeCache = net.minecraft.server.v1_7_R4.WorldChunkManager.class.getDeclaredField("e");
|
||||
fieldBiomeCache.setAccessible(true);
|
||||
fieldBiomes2 = net.minecraft.server.v1_7_R4.WorldChunkManager.class.getDeclaredField("f");
|
||||
fieldBiomes2.setAccessible(true);
|
||||
fieldGenLayer1 = net.minecraft.server.v1_7_R4.WorldChunkManager.class.getDeclaredField("c");
|
||||
fieldGenLayer2 = net.minecraft.server.v1_7_R4.WorldChunkManager.class.getDeclaredField("d");
|
||||
fieldGenLayer1.setAccessible(true);
|
||||
fieldGenLayer2.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -67,6 +111,52 @@ public class BukkitQueue17 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkSec
|
||||
getImpWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||
if (biome != null) {
|
||||
try {
|
||||
if (seed == null) {
|
||||
seed = world.getSeed();
|
||||
}
|
||||
nmsWorld.worldData.getSeed();
|
||||
boolean result;
|
||||
net.minecraft.server.v1_7_R4.ChunkProviderGenerate generator = new net.minecraft.server.v1_7_R4.ChunkProviderGenerate(nmsWorld, seed, false);
|
||||
Biome bukkitBiome = adapter.getBiome(biome.getId());
|
||||
net.minecraft.server.v1_7_R4.BiomeBase base = net.minecraft.server.v1_7_R4.BiomeBase.getBiome(biome.getId());
|
||||
fieldBiomes.set(generator, new net.minecraft.server.v1_7_R4.BiomeBase[]{base});
|
||||
net.minecraft.server.v1_7_R4.IChunkProvider existingGenerator = nmsWorld.chunkProviderServer.chunkProvider;
|
||||
long existingSeed = world.getSeed();
|
||||
{
|
||||
if (genLayer == null) genLayer = new com.boydti.fawe.bukkit.v1_7.MutableGenLayer(seed);
|
||||
genLayer.set(biome.getId());
|
||||
Object existingGenLayer1 = fieldGenLayer1.get(nmsWorld.getWorldChunkManager());
|
||||
Object existingGenLayer2 = fieldGenLayer2.get(nmsWorld.getWorldChunkManager());
|
||||
fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), genLayer);
|
||||
fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), genLayer);
|
||||
|
||||
fieldSeed.set(nmsWorld.worldData, seed);
|
||||
|
||||
ReflectionUtils.setFailsafeFieldValue(fieldBiomeCache, this.nmsWorld.getWorldChunkManager(), new net.minecraft.server.v1_7_R4.BiomeCache(this.nmsWorld.getWorldChunkManager()));
|
||||
|
||||
nmsWorld.chunkProviderServer.chunkProvider = generator;
|
||||
|
||||
result = getWorld().regenerateChunk(x, z);
|
||||
|
||||
nmsWorld.chunkProviderServer.chunkProvider = existingGenerator;
|
||||
|
||||
fieldSeed.set(nmsWorld.worldData, existingSeed);
|
||||
|
||||
fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), existingGenLayer1);
|
||||
fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), existingGenLayer2);
|
||||
}
|
||||
return result;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return super.regenerateChunk(world, x, z, biome, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightMap(FaweChunk chunk, byte[] heightMap) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk.getChunk();
|
||||
@ -91,11 +181,6 @@ public class BukkitQueue17 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkSec
|
||||
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;
|
||||
|
@ -0,0 +1,26 @@
|
||||
package com.boydti.fawe.bukkit.v1_7;
|
||||
|
||||
import java.util.Arrays;
|
||||
import net.minecraft.server.v1_7_R4.GenLayer;
|
||||
import net.minecraft.server.v1_7_R4.IntCache;
|
||||
|
||||
public class MutableGenLayer extends GenLayer {
|
||||
|
||||
private int biome;
|
||||
|
||||
public MutableGenLayer(long seed) {
|
||||
super(seed);
|
||||
}
|
||||
|
||||
public MutableGenLayer set(int biome) {
|
||||
this.biome = biome;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] a(int areaX, int areaY, int areaWidth, int areaHeight) {
|
||||
int[] biomes = IntCache.a(areaWidth * areaHeight);
|
||||
Arrays.fill(biomes, biome);
|
||||
return biomes;
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
@ -21,11 +22,35 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.server.v1_8_R3.*;
|
||||
import net.minecraft.server.v1_8_R3.Block;
|
||||
import net.minecraft.server.v1_8_R3.BlockPosition;
|
||||
import net.minecraft.server.v1_8_R3.ChunkSection;
|
||||
import net.minecraft.server.v1_8_R3.Entity;
|
||||
import net.minecraft.server.v1_8_R3.EntityPlayer;
|
||||
import net.minecraft.server.v1_8_R3.EntityTracker;
|
||||
import net.minecraft.server.v1_8_R3.EntityTypes;
|
||||
import net.minecraft.server.v1_8_R3.EnumDifficulty;
|
||||
import net.minecraft.server.v1_8_R3.EnumSkyBlock;
|
||||
import net.minecraft.server.v1_8_R3.IChunkProvider;
|
||||
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.Packet;
|
||||
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.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.v1_8_R3.CraftChunk;
|
||||
import org.bukkit.craftbukkit.v1_8_R3.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_8_R3.CraftWorld;
|
||||
@ -41,6 +66,13 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkS
|
||||
protected static Field fieldNonEmptyBlockCount;
|
||||
protected static Field fieldSection;
|
||||
protected static Field fieldChunkMap;
|
||||
protected static Field fieldBiomes;
|
||||
protected static Field fieldSeed;
|
||||
protected static Field fieldBiomeCache;
|
||||
protected static Field fieldBiomes2;
|
||||
protected static Field fieldGenLayer1;
|
||||
protected static Field fieldGenLayer2;
|
||||
protected static com.boydti.fawe.bukkit.v1_8.MutableGenLayer genLayer;
|
||||
|
||||
static {
|
||||
try {
|
||||
@ -52,6 +84,19 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkS
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
fieldChunkMap.setAccessible(true);
|
||||
|
||||
fieldBiomes = net.minecraft.server.v1_8_R3.ChunkProviderGenerate.class.getDeclaredField("B");
|
||||
fieldBiomes.setAccessible(true);
|
||||
fieldSeed = net.minecraft.server.v1_8_R3.WorldData.class.getDeclaredField("b");
|
||||
fieldSeed.setAccessible(true);
|
||||
fieldBiomeCache = net.minecraft.server.v1_8_R3.WorldChunkManager.class.getDeclaredField("d");
|
||||
fieldBiomeCache.setAccessible(true);
|
||||
fieldBiomes2 = net.minecraft.server.v1_8_R3.WorldChunkManager.class.getDeclaredField("e");
|
||||
fieldBiomes2.setAccessible(true);
|
||||
fieldGenLayer1 = net.minecraft.server.v1_8_R3.WorldChunkManager.class.getDeclaredField("b") ;
|
||||
fieldGenLayer2 = net.minecraft.server.v1_8_R3.WorldChunkManager.class.getDeclaredField("c") ;
|
||||
fieldGenLayer1.setAccessible(true);
|
||||
fieldGenLayer2.setAccessible(true);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -71,6 +116,52 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkS
|
||||
getImpWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||
if (biome != null) {
|
||||
try {
|
||||
if (seed == null) {
|
||||
seed = world.getSeed();
|
||||
}
|
||||
nmsWorld.worldData.getSeed();
|
||||
boolean result;
|
||||
net.minecraft.server.v1_8_R3.ChunkProviderGenerate generator = new net.minecraft.server.v1_8_R3.ChunkProviderGenerate(nmsWorld, seed, false, "");
|
||||
Biome bukkitBiome = adapter.getBiome(biome.getId());
|
||||
net.minecraft.server.v1_8_R3.BiomeBase base = net.minecraft.server.v1_8_R3.BiomeBase.getBiome(biome.getId());
|
||||
fieldBiomes.set(generator, new net.minecraft.server.v1_8_R3.BiomeBase[]{base});
|
||||
IChunkProvider existingGenerator = nmsWorld.chunkProviderServer.chunkProvider;
|
||||
long existingSeed = world.getSeed();
|
||||
{
|
||||
if (genLayer == null) genLayer = new MutableGenLayer(seed);
|
||||
genLayer.set(biome.getId());
|
||||
Object existingGenLayer1 = fieldGenLayer1.get(nmsWorld.getWorldChunkManager());
|
||||
Object existingGenLayer2 = fieldGenLayer2.get(nmsWorld.getWorldChunkManager());
|
||||
fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), genLayer);
|
||||
fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), genLayer);
|
||||
|
||||
fieldSeed.set(nmsWorld.worldData, seed);
|
||||
|
||||
ReflectionUtils.setFailsafeFieldValue(fieldBiomeCache, this.nmsWorld.getWorldChunkManager(), new net.minecraft.server.v1_8_R3.BiomeCache(this.nmsWorld.getWorldChunkManager()));
|
||||
|
||||
nmsWorld.chunkProviderServer.chunkProvider = generator;
|
||||
|
||||
result = getWorld().regenerateChunk(x, z);
|
||||
|
||||
nmsWorld.chunkProviderServer.chunkProvider = existingGenerator;
|
||||
|
||||
fieldSeed.set(nmsWorld.worldData, existingSeed);
|
||||
|
||||
fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), existingGenLayer1);
|
||||
fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), existingGenLayer2);
|
||||
}
|
||||
return result;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return super.regenerateChunk(world, x, z, biome, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightMap(FaweChunk chunk, byte[] heightMap) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk.getChunk();
|
||||
@ -95,11 +186,6 @@ public class BukkitQueue18R3 extends BukkitQueue_0<Chunk, ChunkSection[], ChunkS
|
||||
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;
|
||||
|
@ -0,0 +1,26 @@
|
||||
package com.boydti.fawe.bukkit.v1_8;
|
||||
|
||||
import java.util.Arrays;
|
||||
import net.minecraft.server.v1_8_R3.GenLayer;
|
||||
import net.minecraft.server.v1_8_R3.IntCache;
|
||||
|
||||
public class MutableGenLayer extends GenLayer {
|
||||
|
||||
private int biome;
|
||||
|
||||
public MutableGenLayer(long seed) {
|
||||
super(seed);
|
||||
}
|
||||
|
||||
public MutableGenLayer set(int biome) {
|
||||
this.biome = biome;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] a(int areaX, int areaY, int areaWidth, int areaHeight) {
|
||||
int[] biomes = IntCache.a(areaWidth * areaHeight);
|
||||
Arrays.fill(biomes, biome);
|
||||
return biomes;
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@ import com.boydti.fawe.util.TaskManager;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
@ -53,6 +54,7 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
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;
|
||||
@ -67,6 +69,14 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Chu
|
||||
protected static Field fieldTickingBlockCount;
|
||||
protected static Field fieldNonEmptyBlockCount;
|
||||
protected static Field fieldSection;
|
||||
protected static Field fieldBiomes;
|
||||
protected static Field fieldChunkGenerator;
|
||||
protected static Field fieldSeed;
|
||||
protected static Field fieldBiomeCache;
|
||||
protected static Field fieldBiomes2;
|
||||
protected static Field fieldGenLayer1;
|
||||
protected static Field fieldGenLayer2;
|
||||
protected static com.boydti.fawe.bukkit.v1_9.MutableGenLayer genLayer;
|
||||
|
||||
static {
|
||||
try {
|
||||
@ -77,6 +87,21 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Chu
|
||||
fieldTickingBlockCount.setAccessible(true);
|
||||
fieldNonEmptyBlockCount.setAccessible(true);
|
||||
|
||||
fieldBiomes = net.minecraft.server.v1_9_R2.ChunkProviderGenerate.class.getDeclaredField("C");
|
||||
fieldBiomes.setAccessible(true);
|
||||
fieldChunkGenerator = net.minecraft.server.v1_9_R2.ChunkProviderServer.class.getDeclaredField("chunkGenerator");
|
||||
fieldChunkGenerator.setAccessible(true);
|
||||
fieldSeed = net.minecraft.server.v1_9_R2.WorldData.class.getDeclaredField("e");
|
||||
fieldSeed.setAccessible(true);
|
||||
fieldBiomeCache = net.minecraft.server.v1_9_R2.WorldChunkManager.class.getDeclaredField("c");
|
||||
fieldBiomeCache.setAccessible(true);
|
||||
fieldBiomes2 = net.minecraft.server.v1_9_R2.WorldChunkManager.class.getDeclaredField("d");
|
||||
fieldBiomes2.setAccessible(true);
|
||||
fieldGenLayer1 = net.minecraft.server.v1_9_R2.WorldChunkManager.class.getDeclaredField("a") ;
|
||||
fieldGenLayer2 = net.minecraft.server.v1_9_R2.WorldChunkManager.class.getDeclaredField("b") ;
|
||||
fieldGenLayer1.setAccessible(true);
|
||||
fieldGenLayer2.setAccessible(true);
|
||||
|
||||
Field fieldAir = DataPaletteBlock.class.getDeclaredField("a");
|
||||
fieldAir.setAccessible(true);
|
||||
air = (IBlockData) fieldAir.get(null);
|
||||
@ -102,6 +127,52 @@ public class BukkitQueue_1_9_R1 extends BukkitQueue_0<Chunk, ChunkSection[], Chu
|
||||
getImpWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||
if (biome != null) {
|
||||
try {
|
||||
if (seed == null) {
|
||||
seed = world.getSeed();
|
||||
}
|
||||
nmsWorld.worldData.getSeed();
|
||||
boolean result;
|
||||
net.minecraft.server.v1_9_R2.ChunkProviderGenerate generator = new net.minecraft.server.v1_9_R2.ChunkProviderGenerate(nmsWorld, seed, false, "");
|
||||
Biome bukkitBiome = adapter.getBiome(biome.getId());
|
||||
net.minecraft.server.v1_9_R2.BiomeBase base = net.minecraft.server.v1_9_R2.BiomeBase.getBiome(biome.getId());
|
||||
fieldBiomes.set(generator, new net.minecraft.server.v1_9_R2.BiomeBase[]{base});
|
||||
net.minecraft.server.v1_9_R2.ChunkGenerator existingGenerator = nmsWorld.getChunkProviderServer().chunkGenerator;
|
||||
long existingSeed = world.getSeed();
|
||||
{
|
||||
if (genLayer == null) genLayer = new MutableGenLayer(seed);
|
||||
genLayer.set(biome.getId());
|
||||
Object existingGenLayer1 = fieldGenLayer1.get(nmsWorld.getWorldChunkManager());
|
||||
Object existingGenLayer2 = fieldGenLayer2.get(nmsWorld.getWorldChunkManager());
|
||||
fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), genLayer);
|
||||
fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), genLayer);
|
||||
|
||||
fieldSeed.set(nmsWorld.worldData, seed);
|
||||
|
||||
ReflectionUtils.setFailsafeFieldValue(fieldBiomeCache, this.nmsWorld.getWorldChunkManager(), new net.minecraft.server.v1_9_R2.BiomeCache(this.nmsWorld.getWorldChunkManager()));
|
||||
|
||||
ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProviderServer(), generator);
|
||||
|
||||
result = getWorld().regenerateChunk(x, z);
|
||||
|
||||
ReflectionUtils.setFailsafeFieldValue(fieldChunkGenerator, this.nmsWorld.getChunkProviderServer(), existingGenerator);
|
||||
|
||||
fieldSeed.set(nmsWorld.worldData, existingSeed);
|
||||
|
||||
fieldGenLayer1.set(nmsWorld.getWorldChunkManager(), existingGenLayer1);
|
||||
fieldGenLayer2.set(nmsWorld.getWorldChunkManager(), existingGenLayer2);
|
||||
}
|
||||
return result;
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return super.regenerateChunk(world, x, z, biome, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeightMap(FaweChunk chunk, byte[] heightMap) {
|
||||
CraftChunk craftChunk = (CraftChunk) chunk.getChunk();
|
||||
|
@ -0,0 +1,26 @@
|
||||
package com.boydti.fawe.bukkit.v1_9;
|
||||
|
||||
import java.util.Arrays;
|
||||
import net.minecraft.server.v1_9_R2.GenLayer;
|
||||
import net.minecraft.server.v1_9_R2.IntCache;
|
||||
|
||||
public class MutableGenLayer extends GenLayer {
|
||||
|
||||
private int biome;
|
||||
|
||||
public MutableGenLayer(long seed) {
|
||||
super(seed);
|
||||
}
|
||||
|
||||
public MutableGenLayer set(int biome) {
|
||||
this.biome = biome;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] a(int areaX, int areaY, int areaWidth, int areaHeight) {
|
||||
int[] biomes = IntCache.a(areaWidth * areaHeight);
|
||||
Arrays.fill(biomes, biome);
|
||||
return biomes;
|
||||
}
|
||||
}
|
46
core/src/main/java/com/boydti/fawe/command/LongBinding.java
Normal file
46
core/src/main/java/com/boydti/fawe/command/LongBinding.java
Normal file
@ -0,0 +1,46 @@
|
||||
package com.boydti.fawe.command;
|
||||
|
||||
import com.sk89q.worldedit.util.command.binding.Range;
|
||||
import com.sk89q.worldedit.util.command.parametric.ArgumentStack;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingBehavior;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingHelper;
|
||||
import com.sk89q.worldedit.util.command.parametric.BindingMatch;
|
||||
import com.sk89q.worldedit.util.command.parametric.ParameterException;
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
public class LongBinding extends BindingHelper {
|
||||
@BindingMatch(type = { Long.class, long.class },
|
||||
behavior = BindingBehavior.CONSUMES,
|
||||
consumedCount = 1,
|
||||
provideModifiers = true)
|
||||
public Long getInteger(ArgumentStack context, Annotation[] modifiers) throws ParameterException {
|
||||
try {
|
||||
Long v = Long.parseLong(context.next());
|
||||
validate(v, modifiers);
|
||||
return v;
|
||||
|
||||
} catch (NumberFormatException ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void validate(long number, Annotation[] modifiers)
|
||||
throws ParameterException {
|
||||
for (Annotation modifier : modifiers) {
|
||||
if (modifier instanceof Range) {
|
||||
Range range = (Range) modifier;
|
||||
if (number < range.min()) {
|
||||
throw new ParameterException(
|
||||
String.format(
|
||||
"A valid value is greater than or equal to %s " +
|
||||
"(you entered %s)", range.min(), number));
|
||||
} else if (number > range.max()) {
|
||||
throw new ParameterException(
|
||||
String.format(
|
||||
"A valid value is less than or equal to %s " +
|
||||
"(you entered %s)", range.max(), number));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -104,7 +104,7 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
|
||||
|
||||
public abstract boolean isChunkLoaded(WORLD world, int x, int z);
|
||||
|
||||
public abstract boolean regenerateChunk(WORLD world, int x, int z);
|
||||
public abstract boolean regenerateChunk(WORLD world, int x, int z, BaseBiome biome, Long seed);
|
||||
|
||||
@Override
|
||||
public abstract FaweChunk getFaweChunk(int x, int z);
|
||||
@ -126,8 +126,8 @@ public abstract class MappedFaweQueue<WORLD, CHUNK, SECTION> extends FaweQueue {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(int x, int z) {
|
||||
return regenerateChunk(getWorld(), x, z);
|
||||
public boolean regenerateChunk(int x, int z, BaseBiome biome, Long seed) {
|
||||
return regenerateChunk(getWorld(), x, z, biome, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -7,6 +7,7 @@ import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.object.FaweQueue;
|
||||
import com.boydti.fawe.object.RunnableVal4;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@ -144,7 +145,7 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(FaweQueue faweQueue, int x, int z) {
|
||||
public boolean regenerateChunk(FaweQueue faweQueue, int x, int z, BaseBiome biome, Long seed) {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class FaweQueue {
|
||||
|
||||
@ -229,7 +230,12 @@ public abstract class FaweQueue {
|
||||
|
||||
public abstract boolean isChunkLoaded(final int x, final int z);
|
||||
|
||||
public abstract boolean regenerateChunk(int x, int z);
|
||||
@Deprecated
|
||||
public boolean regenerateChunk(int x, int z) {
|
||||
return regenerateChunk(x, z, null, null);
|
||||
}
|
||||
|
||||
public abstract boolean regenerateChunk(int x, int z, @Nullable BaseBiome biome, @Nullable Long seed);
|
||||
|
||||
public void startSet(boolean parallel) {}
|
||||
|
||||
|
@ -0,0 +1,96 @@
|
||||
package com.boydti.fawe.regions.general.plot;
|
||||
|
||||
import com.boydti.fawe.FaweAPI;
|
||||
import com.boydti.fawe.object.PseudoRandom;
|
||||
import com.boydti.fawe.util.EditSessionBuilder;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.intellectualcrafters.plot.commands.CommandCategory;
|
||||
import com.intellectualcrafters.plot.commands.MainCommand;
|
||||
import com.intellectualcrafters.plot.commands.RequiredType;
|
||||
import com.intellectualcrafters.plot.config.C;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.RegionWrapper;
|
||||
import com.intellectualcrafters.plot.object.RunnableVal2;
|
||||
import com.intellectualcrafters.plot.object.RunnableVal3;
|
||||
import com.intellectualcrafters.plot.util.MainUtil;
|
||||
import com.intellectualcrafters.plot.util.Permissions;
|
||||
import com.intellectualcrafters.plot.util.StringMan;
|
||||
import com.intellectualcrafters.plot.util.WorldUtil;
|
||||
import com.plotsquared.general.commands.Command;
|
||||
import com.plotsquared.general.commands.CommandDeclaration;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import com.sk89q.worldedit.world.biome.Biomes;
|
||||
import com.sk89q.worldedit.world.registry.BiomeRegistry;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
@CommandDeclaration(
|
||||
command = "generatebiome",
|
||||
permission = "plots.generatebiome",
|
||||
category = CommandCategory.APPEARANCE,
|
||||
requiredType = RequiredType.NONE,
|
||||
description = "Generate a biome in your plot",
|
||||
aliases = {"bg","gb"},
|
||||
usage = "/plots generatebiome <biome>"
|
||||
)
|
||||
public class PlotSetBiome extends Command {
|
||||
public PlotSetBiome() {
|
||||
super(MainCommand.getInstance(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final PlotPlayer player, String[] args, RunnableVal3<Command, Runnable, Runnable> confirm, RunnableVal2<Command, CommandResult> whenDone) throws CommandException {
|
||||
final Plot plot = check(player.getCurrentPlot(), C.NOT_IN_PLOT);
|
||||
checkTrue(plot.isOwner(player.getUUID()) || Permissions.hasPermission(player, "plots.admin.command.generatebiome"), C.NO_PLOT_PERMS);
|
||||
if (plot.getRunning() != 0) {
|
||||
C.WAIT_FOR_TIMER.send(player);
|
||||
return;
|
||||
}
|
||||
checkTrue(args.length == 1, C.COMMAND_SYNTAX, getUsage());
|
||||
final HashSet<RegionWrapper> regions = plot.getRegions();
|
||||
final BiomeRegistry biomeRegistry = FaweAPI.getWorld(plot.getArea().worldname).getWorldData().getBiomeRegistry();
|
||||
List<BaseBiome> knownBiomes = biomeRegistry.getBiomes();
|
||||
final BaseBiome biome = Biomes.findBiomeByName(knownBiomes, args[0], biomeRegistry);
|
||||
if (biome == null) {
|
||||
String biomes = StringMan.join(WorldUtil.IMP.getBiomeList(), C.BLOCK_LIST_SEPARATER.s());
|
||||
C.NEED_BIOME.send(player);
|
||||
MainUtil.sendMessage(player, C.SUBCOMMAND_SET_OPTIONS_HEADER.s() + biomes);
|
||||
return;
|
||||
}
|
||||
confirm.run(this, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (plot.getRunning() != 0) {
|
||||
C.WAIT_FOR_TIMER.send(player);
|
||||
return;
|
||||
}
|
||||
plot.addRunning();
|
||||
TaskManager.IMP.async(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
EditSession session = new EditSessionBuilder(plot.getArea().worldname)
|
||||
.autoQueue(false)
|
||||
.checkMemory(false)
|
||||
.allowedRegionsEverywhere()
|
||||
.changeSetNull()
|
||||
.limitUnlimited()
|
||||
.fastmode(true)
|
||||
.build();
|
||||
long seed = PseudoRandom.random.nextLong();
|
||||
for (RegionWrapper region : regions) {
|
||||
CuboidRegion cuboid = new CuboidRegion(new Vector(region.minX, 0, region.minZ), new Vector(region.maxX, 256, region.maxZ));
|
||||
session.regenerate(cuboid, biome, seed);
|
||||
}
|
||||
session.flushQueue();
|
||||
plot.removeRunning();
|
||||
}
|
||||
});
|
||||
}
|
||||
}, null);
|
||||
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import com.boydti.fawe.object.FawePlayer;
|
||||
import com.boydti.fawe.regions.FaweMask;
|
||||
import com.boydti.fawe.regions.FaweMaskManager;
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.commands.MainCommand;
|
||||
import com.intellectualcrafters.plot.config.Settings;
|
||||
import com.intellectualcrafters.plot.generator.HybridPlotManager;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
@ -30,6 +31,9 @@ public class PlotSquaredFeature extends FaweMaskManager {
|
||||
if (Settings.PLATFORM.equals("Bukkit")) {
|
||||
new FaweTrim();
|
||||
}
|
||||
if (MainCommand.getInstance().getCommand("generatebiome") == null) {
|
||||
new PlotSetBiome();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupBlockQueue() {
|
||||
|
@ -15,6 +15,7 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DelegateFaweQueue extends FaweQueue {
|
||||
private FaweQueue parent;
|
||||
@ -149,8 +150,8 @@ public class DelegateFaweQueue extends FaweQueue {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(int x, int z) {
|
||||
return parent.regenerateChunk(x, z);
|
||||
public boolean regenerateChunk(int x, int z, @Nullable BaseBiome biome, Long seed) {
|
||||
return parent.regenerateChunk(x, z, biome, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3057,38 +3057,71 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
|
||||
@Override
|
||||
public boolean regenerate(final Region region, final EditSession session) {
|
||||
final FaweQueue queue = session.getQueue();
|
||||
return session.regenerate(region, null, null);
|
||||
}
|
||||
|
||||
private void setExistingBlocks(Vector pos1, Vector pos2) {
|
||||
for (int x = (int) pos1.x; x <= (int) pos2.x; x++) {
|
||||
for (int z = (int) pos1.z; z <= (int) pos2.z; z++) {
|
||||
for (int y = (int) pos1.y; y <= (int) pos2.y; y++) {
|
||||
int from = queue.getCombinedId4Data(x, y, z);
|
||||
short id = (short) (from >> 4);
|
||||
byte data = (byte) (from & 0xf);
|
||||
queue.setBlock(x, y, z, id, data);
|
||||
if (FaweCache.hasNBT(id)) {
|
||||
CompoundTag tile = queue.getTileEntity(x, y, z);
|
||||
if (tile != null) {
|
||||
queue.setTile(x, y, z, tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean regenerate(final Region region, final BaseBiome biome, final Long seed) {
|
||||
final FaweQueue queue = this.getQueue();
|
||||
queue.setChangeTask(null);
|
||||
final FaweChangeSet fcs = (FaweChangeSet) session.getChangeSet();
|
||||
final FaweRegionExtent fe = session.getRegionExtent();
|
||||
session.setSize(1);
|
||||
final FaweChangeSet fcs = (FaweChangeSet) this.getChangeSet();
|
||||
final FaweRegionExtent fe = this.getRegionExtent();
|
||||
final boolean cuboid = region instanceof CuboidRegion;
|
||||
Set<Vector2D> chunks = region.getChunks();
|
||||
if (fe != null && cuboid) {
|
||||
Vector max = region.getMaximumPoint();
|
||||
Vector min = region.getMinimumPoint();
|
||||
if (!fe.contains(max.getBlockX(), max.getBlockY(), max.getBlockZ()) && !fe.contains(min.getBlockX(), min.getBlockY(), min.getBlockZ())) {
|
||||
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MAX_FAILS);
|
||||
}
|
||||
}
|
||||
final Set<Vector2D> chunks = region.getChunks();
|
||||
for (Vector2D chunk : chunks) {
|
||||
final int cx = chunk.getBlockX();
|
||||
final int cz = chunk.getBlockZ();
|
||||
final int bx = cx << 4;
|
||||
final int bz = cz << 4;
|
||||
Vector cmin = new Vector(bx, 0, bz);
|
||||
Vector cmax = cmin.add(15, getMaxY(), 15);
|
||||
final Vector cmin = new Vector(bx, 0, bz);
|
||||
final Vector cmax = cmin.add(15, getMaxY(), 15);
|
||||
final boolean containsBot1 = (fe == null || fe.contains(cmin.getBlockX(), cmin.getBlockY(), cmin.getBlockZ()));
|
||||
final boolean containsBot2 = region.contains(cmin);
|
||||
final boolean containsTop1 = (fe == null || fe.contains(cmax.getBlockX(), cmax.getBlockY(), cmax.getBlockZ()));
|
||||
final boolean containsTop2 = region.contains(cmax);
|
||||
if ((containsBot2 && containsTop2 && !containsBot1 && !containsTop1)) {
|
||||
if (((containsBot2 && containsTop2)) && !containsBot1 && !containsTop1) {
|
||||
continue;
|
||||
}
|
||||
RunnableVal<Vector2D> r = new RunnableVal<Vector2D>() {
|
||||
@Override
|
||||
public void run(Vector2D chunk) {
|
||||
if (cuboid && containsBot1 && containsBot2 && containsTop1 && containsTop2) {
|
||||
boolean conNextX = chunks.contains(new Vector2D(cx + 1, cz));
|
||||
boolean conNextZ = chunks.contains(new Vector2D(cx, cz + 1));
|
||||
boolean containsAny = false;
|
||||
if (cuboid && containsBot1 && containsBot2 && containsTop1 && containsTop2 && conNextX && conNextZ) {
|
||||
containsAny = true;
|
||||
if (fcs != null) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
int xx = x + bx;
|
||||
for (int z = 0; z < 16; z++) {
|
||||
int zz = z + bz;
|
||||
for (int y = 0; y < getMaxY() + 1; y++) {
|
||||
int from = queue.getCombinedId4DataDebug(xx, y, zz, 0, session);
|
||||
int from = queue.getCombinedId4DataDebug(xx, y, zz, 0, EditSession.this);
|
||||
if (!FaweCache.hasNBT(from >> 4)) {
|
||||
fcs.add(xx, y, zz, from, 0);
|
||||
} else {
|
||||
@ -3105,11 +3138,22 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int tx = 16;
|
||||
int tz = 16;
|
||||
if (!conNextX) {
|
||||
setExistingBlocks(new Vector(bx + 16, 0, bz), new Vector(bx + 31, getMaxY(), bz + 15));
|
||||
}
|
||||
if (!conNextZ) {
|
||||
setExistingBlocks(new Vector(bx, 0, bz + 16), new Vector(bx + 15, getMaxY(), bz + 31));
|
||||
}
|
||||
if (!chunks.contains(new Vector2D(cx + 1, cz + 1)) && !conNextX && !conNextZ) {
|
||||
setExistingBlocks(new Vector(bx + 16, 0, bz + 16), new Vector(bx + 31, getMaxY(), bz + 31));
|
||||
}
|
||||
Vector mutable = new Vector(0,0,0);
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int x = 0; x < tx; x++) {
|
||||
int xx = x + bx;
|
||||
mutable.x = xx;
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int z = 0; z < tz; z++) {
|
||||
int zz = z + bz;
|
||||
mutable.z = zz;
|
||||
for (int y = 0; y < getMaxY() + 1; y++) {
|
||||
@ -3117,6 +3161,7 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
int from = queue.getCombinedId4Data(xx, y, zz);
|
||||
boolean contains = (fe == null || fe.contains(xx, y, zz)) && region.contains(mutable);
|
||||
if (contains) {
|
||||
containsAny = true;
|
||||
if (fcs != null) {
|
||||
if (!FaweCache.hasNBT(from >> 4)) {
|
||||
fcs.add(xx, y, zz, from, 0);
|
||||
@ -3134,9 +3179,9 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
byte data = (byte) (from & 0xf);
|
||||
queue.setBlock(xx, y, zz, id, data);
|
||||
if (FaweCache.hasNBT(id)) {
|
||||
BaseBlock block = getBlock(new Vector(xx, y, zz));
|
||||
if (block.hasNbtData()) {
|
||||
queue.setTile(xx, y, zz, block.getNbtData());
|
||||
CompoundTag tile = queue.getTileEntity(xx, y, zz);
|
||||
if (tile != null) {
|
||||
queue.setTile(xx, y, zz, tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3144,13 +3189,21 @@ public class EditSession extends AbstractWorld implements HasFaweQueue, Lighting
|
||||
}
|
||||
}
|
||||
}
|
||||
queue.regenerateChunk(cx, cz);
|
||||
if (containsAny) {
|
||||
changes++;
|
||||
queue.regenerateChunk(cx, cz, biome, seed);
|
||||
}
|
||||
}
|
||||
};
|
||||
r.value = chunk;
|
||||
TaskManager.IMP.sync(r);
|
||||
}
|
||||
session.flushQueue();
|
||||
if (changes != 0) {
|
||||
flushQueue();
|
||||
return true;
|
||||
} else {
|
||||
this.queue.clear();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
package com.sk89q.worldedit.util.command.parametric;
|
||||
|
||||
import com.boydti.fawe.command.LongBinding;
|
||||
import com.boydti.fawe.config.Commands;
|
||||
import com.google.common.collect.ImmutableBiMap.Builder;
|
||||
import com.sk89q.minecraft.util.commands.Command;
|
||||
@ -71,6 +72,7 @@ public class ParametricBuilder {
|
||||
*/
|
||||
public ParametricBuilder() {
|
||||
addBinding(new PrimitiveBindings());
|
||||
addBinding(new LongBinding());
|
||||
addBinding(new StandardBindings());
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import java.io.File;
|
||||
@ -168,7 +169,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z) {
|
||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||
IChunkProvider provider = world.getChunkProvider();
|
||||
if (!(provider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
|
@ -12,6 +12,7 @@ import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import java.io.File;
|
||||
@ -168,7 +169,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z) {
|
||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||
IChunkProvider provider = world.getChunkProvider();
|
||||
if (!(provider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
|
@ -14,6 +14,7 @@ import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||
import java.io.File;
|
||||
@ -158,7 +159,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z) {
|
||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||
try {
|
||||
IChunkProvider provider = world.getChunkProvider();
|
||||
if (!(provider instanceof ChunkProviderServer)) {
|
||||
|
@ -12,6 +12,7 @@ import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import java.io.File;
|
||||
@ -132,7 +133,7 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z) {
|
||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||
IChunkProvider provider = world.getChunkProvider();
|
||||
if (!(provider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
|
@ -12,6 +12,7 @@ import com.boydti.fawe.util.ReflectionUtils;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
import com.sk89q.jnbt.Tag;
|
||||
import com.sk89q.worldedit.world.biome.BaseBiome;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import java.io.File;
|
||||
@ -140,13 +141,11 @@ public class ForgeQueue_All extends NMSMappedFaweQueue<World, Chunk, ExtendedBlo
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerateChunk(World world, int x, int z) {
|
||||
public boolean regenerateChunk(World world, int x, int z, BaseBiome biome, Long seed) {
|
||||
IChunkProvider provider = world.getChunkProvider();
|
||||
if (!(provider instanceof ChunkProviderServer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
ChunkProviderServer chunkServer = (ChunkProviderServer) provider;
|
||||
IChunkGenerator gen = chunkServer.chunkGenerator;
|
||||
|
Loading…
Reference in New Issue
Block a user