implement world api changes

This commit is contained in:
dfsek
2021-11-28 12:19:10 -07:00
parent 01f6df4a19
commit 1e9e1dce75
49 changed files with 111 additions and 1428 deletions

View File

@@ -25,6 +25,7 @@ import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.LimitedRegion;
import org.bukkit.generator.WorldInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,6 +33,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import com.dfsek.terra.api.config.WorldConfig;
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
@@ -66,7 +68,12 @@ public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGener
@Override
public @NotNull List<BlockPopulator> getDefaultPopulators(@NotNull World world) {
return Collections.singletonList(new BukkitPopulatorWrapper(delegate));
return delegate.getGenerationStages().stream().map(generationStage -> new BlockPopulator() {
@Override
public void populate(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull LimitedRegion limitedRegion) {
generationStage.populate(new BukkitProtoWorld(limitedRegion));
}
}).collect(Collectors.toList());
}
@Override

View File

@@ -1,54 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.bukkit.generator;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.LimitedRegion;
import org.bukkit.generator.WorldInfo;
import org.jetbrains.annotations.NotNull;
import java.util.Random;
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
import com.dfsek.terra.api.world.chunk.generation.stage.Chunkified;
import com.dfsek.terra.bukkit.world.BukkitAdapter;
public class BukkitPopulatorWrapper extends BlockPopulator {
private final ChunkGenerator delegate;
public BukkitPopulatorWrapper(ChunkGenerator delegate) {
this.delegate = delegate;
}
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk source) {
delegate.getGenerationStages().forEach(populator -> {
if(populator instanceof Chunkified) {
populator.populate(BukkitAdapter.adapt(world), BukkitAdapter.adapt(source));
}
});
}
@Override
public void populate(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull LimitedRegion limitedRegion) {
super.populate(worldInfo, random, x, z, limitedRegion);
}
}

View File

@@ -1,68 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.bukkit.population;
import java.io.Serializable;
import java.util.UUID;
import com.dfsek.terra.api.world.chunk.Chunk;
import com.dfsek.terra.bukkit.world.BukkitWorld;
public class ChunkCoordinate implements Serializable {
public static final long serialVersionUID = 7102462856296750285L;
private final int x;
private final int z;
private final UUID worldID;
public ChunkCoordinate(int x, int z, UUID worldID) {
this.x = x;
this.z = z;
this.worldID = worldID;
}
public ChunkCoordinate(Chunk c) {
this.x = c.getX();
this.z = c.getZ();
this.worldID = ((BukkitWorld) c.getWorld()).getUID();
}
public UUID getWorldID() {
return worldID;
}
public int getX() {
return x;
}
public int getZ() {
return z;
}
@Override
public int hashCode() {
return x * 31 + z;
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof ChunkCoordinate other)) return false;
return other.getX() == x && other.getZ() == z;
}
}

View File

@@ -1,113 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.bukkit.population;
import com.dfsek.terra.api.world.chunk.Chunk;
import org.bukkit.generator.BlockPopulator;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Random;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.profiler.ProfileFrame;
import com.dfsek.terra.api.world.access.World;
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
import com.dfsek.terra.api.world.chunk.generation.stage.Chunkified;
import com.dfsek.terra.bukkit.PlatformImpl;
import com.dfsek.terra.bukkit.world.BukkitAdapter;
import com.dfsek.terra.bukkit.world.BukkitWorld;
import com.dfsek.terra.util.FastRandom;
/**
* Cursed management class for the horrors of Bukkit population
*/
public class PopulationManager extends BlockPopulator {
private final ChunkGenerator generator;
private final HashSet<ChunkCoordinate> needsPop = new HashSet<>();
private final Platform platform;
public PopulationManager(ChunkGenerator generator, Platform platform) {
this.generator = generator;
this.platform = platform;
}
public static File getDataFolder(World w) {
File f = new File(((BukkitWorld) w).getWorldFolder(), "gaea");
f.mkdirs();
return f;
}
@SuppressWarnings("unchecked")
public synchronized void saveBlocks(World w) throws IOException {
File f = new File(getDataFolder(w), "chunks.bin");
f.createNewFile();
SerializationUtil.toFile((HashSet<ChunkCoordinate>) needsPop.clone(), f);
}
@SuppressWarnings("unchecked")
public synchronized void loadBlocks(World w) throws IOException, ClassNotFoundException {
File f = new File(getDataFolder(w), "chunks.bin");
needsPop.addAll((HashSet<ChunkCoordinate>) SerializationUtil.fromFile(f));
}
// Synchronize to prevent chunks from being queued for population multiple times.
public synchronized void checkNeighbors(int x, int z, World world) {
BukkitWorld w = (BukkitWorld) world;
ChunkCoordinate c = new ChunkCoordinate(x, z, (w).getUID());
if(w.isChunkGenerated(x + 1, z)
&& w.isChunkGenerated(x - 1, z)
&& w.isChunkGenerated(x, z + 1)
&& w.isChunkGenerated(x, z - 1) && needsPop.contains(c)) {
Random random = new FastRandom(w.getSeed());
long xRand = (random.nextLong() / 2L << 1L) + 1L;
long zRand = (random.nextLong() / 2L << 1L) + 1L;
random.setSeed((long) x * xRand + (long) z * zRand ^ w.getSeed());
Chunk currentChunk = w.getChunkAt(x, z);
generator.getGenerationStages().forEach(populator -> {
if(!(populator instanceof Chunkified)) {
populator.populate(w, currentChunk);
}
});
needsPop.remove(c);
}
}
@Override
@SuppressWarnings("try")
public void populate(org.bukkit.@NotNull World world, @NotNull Random random, org.bukkit.@NotNull Chunk source) {
try(ProfileFrame ignore = platform.getProfiler().profile("popman")) {
Chunk chunk = BukkitAdapter.adapt(source);
needsPop.add(new ChunkCoordinate(chunk));
int x = chunk.getX();
int z = chunk.getZ();
if(((PlatformImpl) platform).getPlugin().isEnabled()) {
for(int xi = -1; xi <= 1; xi++) {
for(int zi = -1; zi <= 1; zi++) {
if(xi == 0 && zi == 0) continue;
if(world.isChunkGenerated(xi + x, zi + z)) checkNeighbors(xi + x, zi + z, BukkitAdapter.adapt(world));
}
}
}
}
}
}

View File

@@ -1,89 +0,0 @@
/*
* This file is part of Terra.
*
* Terra is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Terra is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Terra. If not, see <https://www.gnu.org/licenses/>.
*/
package com.dfsek.terra.bukkit.population;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import java.lang.reflect.Field;
public final class SerializationUtil {
public static Object fromFile(File f) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new MovedObjectInputStream(new FileInputStream(f), "com.dfsek.terra.api.world.generation.population",
"com.dfsek.terra.bukkit.population"); // Backwards compat with old Gaea location
Object o = ois.readObject();
ois.close();
return o;
}
public static void toFile(Serializable o, File f) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
oos.writeObject(o);
oos.close();
}
public static class MovedObjectInputStream extends ObjectInputStream {
private final String oldNameSpace;
private final String newNameSpace;
public MovedObjectInputStream(InputStream in, String oldNameSpace, String newNameSpace) throws IOException {
super(in);
this.oldNameSpace = oldNameSpace;
this.newNameSpace = newNameSpace;
}
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
if(desc.getName().contains(oldNameSpace)) {
String newClassName = desc.getName().replace(oldNameSpace, newNameSpace);
return Class.forName(newClassName);
}
return super.resolveClass(desc);
}
@Override
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
ObjectStreamClass result = super.readClassDescriptor();
try {
if(result.getName().contains(oldNameSpace)) {
String newClassName = result.getName().replace(oldNameSpace, newNameSpace);
Class<?> localClass = Class.forName(newClassName);
Field nameField = ObjectStreamClass.class.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(result, newClassName);
ObjectStreamClass localClassDescriptor = ObjectStreamClass.lookup(localClass);
Field suidField = ObjectStreamClass.class.getDeclaredField("suid");
suidField.setAccessible(true);
suidField.set(result, localClassDescriptor.getSerialVersionUID());
}
} catch(Exception e) {
throw new IOException("Exception when trying to replace namespace", e);
}
return result;
}
}
}