mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-01 07:26:09 +00:00
Merge remote-tracking branch 'everbuild-org/feat/platform/minestom' into ver/6.6.0
This commit is contained in:
commit
a61c6b8a97
@ -44,6 +44,7 @@ afterEvaluate {
|
||||
configureDistribution()
|
||||
}
|
||||
project(":platforms:bukkit:common").configureDistribution()
|
||||
project(":platforms:minestom:example").configureDistribution()
|
||||
forSubProjects(":common:addons") {
|
||||
apply(plugin = "com.gradleup.shadow")
|
||||
|
||||
|
@ -4,9 +4,11 @@ import java.io.File
|
||||
import java.io.FileWriter
|
||||
import java.net.URL
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Path
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.BasePluginExtension
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.gradle.kotlin.dsl.extra
|
||||
@ -19,6 +21,25 @@ import kotlin.io.path.createDirectories
|
||||
import kotlin.io.path.createFile
|
||||
import kotlin.io.path.exists
|
||||
|
||||
private fun Project.installAddonsInto(dest: Path) {
|
||||
FileSystems.newFileSystem(dest, mapOf("create" to "false"), null).use { fs ->
|
||||
forSubProjects(":common:addons") {
|
||||
val jar = getJarTask()
|
||||
|
||||
logger.info("Packaging addon ${jar.archiveFileName.get()} to $dest. size: ${jar.archiveFile.get().asFile.length() / 1024}KB")
|
||||
|
||||
val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else ""
|
||||
val addonPath = fs.getPath("/addons/$boot${jar.archiveFileName.get()}")
|
||||
|
||||
if (!addonPath.exists()) {
|
||||
addonPath.parent.createDirectories()
|
||||
addonPath.createFile()
|
||||
jar.archiveFile.get().asFile.toPath().copyTo(addonPath, overwrite = true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.configureDistribution() {
|
||||
apply(plugin = "com.gradleup.shadow")
|
||||
@ -48,25 +69,17 @@ fun Project.configureDistribution() {
|
||||
doLast {
|
||||
// https://github.com/johnrengelman/shadow/issues/111
|
||||
val dest = tasks.named<ShadowJar>("shadowJar").get().archiveFile.get().path
|
||||
|
||||
|
||||
FileSystems.newFileSystem(dest, mapOf("create" to "false"), null).use { fs ->
|
||||
forSubProjects(":common:addons") {
|
||||
val jar = getJarTask()
|
||||
|
||||
logger.info("Packaging addon ${jar.archiveFileName.get()} to $dest. size: ${jar.archiveFile.get().asFile.length() / 1024}KB")
|
||||
|
||||
val boot = if (extra.has("bootstrap") && extra.get("bootstrap") as Boolean) "bootstrap/" else ""
|
||||
val addonPath = fs.getPath("/addons/$boot${jar.archiveFileName.get()}")
|
||||
|
||||
if (!addonPath.exists()) {
|
||||
addonPath.parent.createDirectories()
|
||||
addonPath.createFile()
|
||||
jar.archiveFile.get().asFile.toPath().copyTo(addonPath, overwrite = true)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
installAddonsInto(dest)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.create("installAddonsIntoDefaultJar") {
|
||||
group = "terra"
|
||||
dependsOn(compileAddons)
|
||||
|
||||
doLast {
|
||||
val dest = tasks.named<Jar>("jar").get().archiveFile.get().path
|
||||
installAddonsInto(dest)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,4 +81,8 @@ object Versions {
|
||||
object Allay {
|
||||
const val api = "0.1.3"
|
||||
}
|
||||
|
||||
object Minestom {
|
||||
const val minestom = "187931e50b"
|
||||
}
|
||||
}
|
||||
|
11
platforms/minestom/build.gradle.kts
Normal file
11
platforms/minestom/build.gradle.kts
Normal file
@ -0,0 +1,11 @@
|
||||
dependencies {
|
||||
shadedApi(project(":common:implementation:base"))
|
||||
shadedApi("com.github.ben-manes.caffeine", "caffeine", Versions.Libraries.caffeine)
|
||||
shadedImplementation("com.google.guava", "guava", Versions.Libraries.Internal.guava)
|
||||
|
||||
compileOnly("net.minestom", "minestom-snapshots", Versions.Minestom.minestom)
|
||||
}
|
||||
|
||||
tasks.named("jar") {
|
||||
finalizedBy("installAddonsIntoDefaultJar")
|
||||
}
|
28
platforms/minestom/example/build.gradle.kts
Normal file
28
platforms/minestom/example/build.gradle.kts
Normal file
@ -0,0 +1,28 @@
|
||||
plugins {
|
||||
application
|
||||
}
|
||||
|
||||
val javaMainClass = "com.dfsek.terra.minestom.TerraMinestomExample"
|
||||
|
||||
dependencies {
|
||||
shadedApi(project(":platforms:minestom"))
|
||||
|
||||
implementation("net.minestom", "minestom-snapshots", Versions.Minestom.minestom)
|
||||
implementation("org.slf4j", "slf4j-simple", Versions.Libraries.slf4j)
|
||||
}
|
||||
|
||||
tasks.withType<Jar> {
|
||||
entryCompression = ZipEntryCompression.STORED
|
||||
manifest {
|
||||
attributes(
|
||||
"Main-Class" to javaMainClass,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass.set(javaMainClass)
|
||||
}
|
||||
|
||||
tasks.getByName("run").setProperty("workingDir", file("./run"))
|
||||
addonDir(project.file("./run/terra/addons"), tasks.named("run").get())
|
@ -0,0 +1,132 @@
|
||||
package com.dfsek.terra.minestom;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.entity.GameMode;
|
||||
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
|
||||
import net.minestom.server.event.player.PlayerSpawnEvent;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.LightingChunk;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import com.dfsek.terra.minestom.world.TerraMinestomWorld;
|
||||
import com.dfsek.terra.minestom.world.TerraMinestomWorldBuilder;
|
||||
|
||||
|
||||
public class TerraMinestomExample {
|
||||
private static final Logger logger = LoggerFactory.getLogger(TerraMinestomExample.class);
|
||||
private final MinecraftServer server = MinecraftServer.init();
|
||||
private Instance instance;
|
||||
private TerraMinestomWorld world;
|
||||
|
||||
public void createNewInstance() {
|
||||
instance = MinecraftServer.getInstanceManager().createInstanceContainer();
|
||||
instance.setChunkSupplier(LightingChunk::new);
|
||||
}
|
||||
|
||||
public void attachTerra() {
|
||||
world = TerraMinestomWorldBuilder.from(instance)
|
||||
.defaultPack()
|
||||
.attach();
|
||||
}
|
||||
|
||||
private void sendProgressBar(int current, int max) {
|
||||
String left = "#".repeat((int) ((((float) current) / max) * 20));
|
||||
String right = ".".repeat(20 - left.length());
|
||||
int percent = (int) (((float) current) / max * 100);
|
||||
String percentString = percent + "%";
|
||||
percentString = " ".repeat(4 - percentString.length()) + percentString;
|
||||
String message = percentString + " |" + left + right + "| " + current + "/" + max;
|
||||
logger.info(message);
|
||||
}
|
||||
|
||||
public void preloadWorldAndMeasure() {
|
||||
int radius = 12;
|
||||
int chunksLoading = (radius * 2 + 1) * (radius * 2 + 1);
|
||||
AtomicInteger chunksLeft = new AtomicInteger(chunksLoading);
|
||||
|
||||
long start = System.nanoTime();
|
||||
for(int x = -radius; x <= radius; x++) {
|
||||
for(int z = -radius; z <= radius; z++) {
|
||||
instance.loadChunk(x, z).thenAccept(chunk -> {
|
||||
int left = chunksLeft.decrementAndGet();
|
||||
if(left == 0) {
|
||||
long end = System.nanoTime();
|
||||
sendProgressBar(chunksLoading - left, chunksLoading);
|
||||
double chunksPerSecond = chunksLoading / ((end - start) / 1000000000.0);
|
||||
logger.info(
|
||||
"Preloaded {} chunks in world in {}ms. That's {} Chunks/s",
|
||||
chunksLoading,
|
||||
(end - start) / 1000000.0,
|
||||
chunksPerSecond
|
||||
);
|
||||
|
||||
world.displayStats();
|
||||
} else if(left % 60 == 0) {
|
||||
sendProgressBar(chunksLoading - left, chunksLoading);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addListeners() {
|
||||
MinecraftServer.getGlobalEventHandler().addListener(AsyncPlayerConfigurationEvent.class, event -> {
|
||||
event.setSpawningInstance(instance);
|
||||
event.getPlayer().setRespawnPoint(new Pos(0.0, 100.0, 0.0));
|
||||
});
|
||||
|
||||
MinecraftServer.getGlobalEventHandler().addListener(PlayerSpawnEvent.class, event -> {
|
||||
event.getPlayer().setGameMode(GameMode.SPECTATOR);
|
||||
});
|
||||
}
|
||||
|
||||
public void addScheduler() {
|
||||
MinecraftServer.getSchedulerManager().buildTask(() -> world.displayStats())
|
||||
.repeat(Duration.ofSeconds(10))
|
||||
.schedule();
|
||||
}
|
||||
|
||||
public void addCommands() {
|
||||
MinecraftServer.getCommandManager().register(new RegenerateCommand());
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
logger.info("Starting server on port 25565");
|
||||
server.start("localhost", 25565);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
TerraMinestomExample example = new TerraMinestomExample();
|
||||
example.createNewInstance();
|
||||
example.attachTerra();
|
||||
example.preloadWorldAndMeasure();
|
||||
example.addScheduler();
|
||||
example.addListeners();
|
||||
example.addCommands();
|
||||
example.bind();
|
||||
}
|
||||
|
||||
public class RegenerateCommand extends Command {
|
||||
public RegenerateCommand() {
|
||||
super("regenerate");
|
||||
setDefaultExecutor((sender, context) -> regenerate());
|
||||
}
|
||||
|
||||
private void regenerate() {
|
||||
instance.sendMessage(Component.text("Regenerating world"));
|
||||
createNewInstance();
|
||||
attachTerra();
|
||||
preloadWorldAndMeasure();
|
||||
MinecraftServer.getConnectionManager().getOnlinePlayers().forEach(player ->
|
||||
player.setInstance(instance, new Pos(0, 100, 0))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.dfsek.terra.minestom;
|
||||
|
||||
import com.dfsek.terra.api.util.vector.Vector3;
|
||||
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
|
||||
|
||||
public class MinestomAdapter {
|
||||
public static Vector3 adapt(Point point) {
|
||||
return Vector3.of(point.x(), point.y(), point.z());
|
||||
}
|
||||
|
||||
public static Pos adapt(Vector3 vector) {
|
||||
return new Pos(vector.getX(), vector.getY(), vector.getZ());
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package com.dfsek.terra.minestom;
|
||||
|
||||
import com.dfsek.tectonic.api.TypeRegistry;
|
||||
import com.dfsek.tectonic.api.loader.type.TypeLoader;
|
||||
import com.dfsek.terra.AbstractPlatform;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.entity.EntityType;
|
||||
import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent;
|
||||
import com.dfsek.terra.api.handle.ItemHandle;
|
||||
import com.dfsek.terra.api.handle.WorldHandle;
|
||||
import com.dfsek.terra.api.world.biome.PlatformBiome;
|
||||
import com.dfsek.terra.minestom.biome.MinestomBiomeLoader;
|
||||
import com.dfsek.terra.minestom.entity.MinestomEntityType;
|
||||
import com.dfsek.terra.minestom.item.MinestomItemHandle;
|
||||
import com.dfsek.terra.minestom.world.MinestomChunkGeneratorWrapper;
|
||||
import com.dfsek.terra.minestom.world.MinestomWorldHandle;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
||||
public final class MinestomPlatform extends AbstractPlatform {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MinestomPlatform.class);
|
||||
private static MinestomPlatform INSTANCE = null;
|
||||
private final MinestomWorldHandle worldHandle = new MinestomWorldHandle();
|
||||
private final MinestomItemHandle itemHandle = new MinestomItemHandle();
|
||||
|
||||
private MinestomPlatform() {
|
||||
load();
|
||||
getEventManager().callEvent(new PlatformInitializationEvent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(TypeRegistry registry) {
|
||||
super.register(registry);
|
||||
registry
|
||||
.registerLoader(PlatformBiome.class, new MinestomBiomeLoader())
|
||||
.registerLoader(EntityType.class, (TypeLoader<EntityType>) (annotatedType, o, configLoader, depthTracker) -> new MinestomEntityType((String) o))
|
||||
.registerLoader(BlockState.class, (TypeLoader<BlockState>) (annotatedType, o, configLoader, depthTracker) -> worldHandle.createBlockState((String) o));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reload() {
|
||||
getTerraConfig().load(this);
|
||||
getRawConfigRegistry().clear();
|
||||
boolean succeed = getRawConfigRegistry().loadAll(this);
|
||||
|
||||
MinecraftServer.getInstanceManager().getInstances().forEach(world -> {
|
||||
if(world.generator() instanceof MinestomChunkGeneratorWrapper wrapper) {
|
||||
getConfigRegistry().get(wrapper.getPack().getRegistryKey()).ifPresent(pack -> {
|
||||
wrapper.setPack(pack);
|
||||
LOGGER.info("Replaced pack in chunk generator for instance {}", world.getUniqueId());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return succeed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull WorldHandle getWorldHandle() {
|
||||
return worldHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemHandle getItemHandle() {
|
||||
return itemHandle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String platformName() {
|
||||
return "Minestom";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull File getDataFolder() {
|
||||
String pathName = System.getProperty("terra.datafolder");
|
||||
if (pathName == null) pathName = "./terra/";
|
||||
File file = new File(pathName);
|
||||
if(!file.exists()) file.mkdirs();
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
public static MinestomPlatform getInstance() {
|
||||
if(INSTANCE == null) {
|
||||
INSTANCE = new MinestomPlatform();
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.dfsek.terra.minestom.api;
|
||||
|
||||
import com.dfsek.terra.api.block.entity.BlockEntity;
|
||||
|
||||
import net.minestom.server.coordinate.BlockVec;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a factory interface for creating instances of BlockEntity
|
||||
* at a specified BlockVec position. This is not implemented directly because
|
||||
* Minestom does not define a way to build block entities out of the box.
|
||||
*/
|
||||
public interface BlockEntityFactory {
|
||||
@Nullable BlockEntity createBlockEntity(BlockVec position);
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.dfsek.terra.minestom.api;
|
||||
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
|
||||
|
||||
/**
|
||||
* Allows adding AI to generated entities using custom entity types
|
||||
*/
|
||||
public interface EntityFactory {
|
||||
Entity createEntity(EntityType type);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.dfsek.terra.minestom.biome;
|
||||
|
||||
import com.dfsek.terra.api.world.biome.PlatformBiome;
|
||||
|
||||
import net.minestom.server.world.biome.Biome;
|
||||
|
||||
|
||||
public class MinestomBiome implements PlatformBiome {
|
||||
private final Biome biome;
|
||||
|
||||
public MinestomBiome(Biome biome) { this.biome = biome; }
|
||||
|
||||
@Override
|
||||
public Biome getHandle() {
|
||||
return biome;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.dfsek.terra.minestom.biome;
|
||||
|
||||
import com.dfsek.tectonic.api.depth.DepthTracker;
|
||||
import com.dfsek.tectonic.api.exception.LoadException;
|
||||
import com.dfsek.tectonic.api.loader.ConfigLoader;
|
||||
import com.dfsek.tectonic.api.loader.type.TypeLoader;
|
||||
|
||||
import com.dfsek.terra.api.world.biome.PlatformBiome;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.registry.DynamicRegistry;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import net.minestom.server.world.biome.Biome;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
|
||||
|
||||
public class MinestomBiomeLoader implements TypeLoader<PlatformBiome> {
|
||||
private final DynamicRegistry<Biome> biomeRegistry = MinecraftServer.getBiomeRegistry();
|
||||
|
||||
@Override
|
||||
public PlatformBiome load(@NotNull AnnotatedType annotatedType, @NotNull Object o, @NotNull ConfigLoader configLoader,
|
||||
DepthTracker depthTracker) throws LoadException {
|
||||
String id = (String) o;
|
||||
NamespaceID biomeID = NamespaceID.from(id);
|
||||
Biome biome = biomeRegistry.get(biomeID);
|
||||
if(biome == null) throw new LoadException("Biome %s does not exist in registry".formatted(id), depthTracker);
|
||||
return new MinestomBiome(biome);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.minestom.block;
|
||||
|
||||
import com.dfsek.terra.api.block.entity.BlockEntity;
|
||||
import com.dfsek.terra.minestom.api.BlockEntityFactory;
|
||||
|
||||
import net.minestom.server.coordinate.BlockVec;
|
||||
|
||||
|
||||
public class DefaultBlockEntityFactory implements BlockEntityFactory {
|
||||
@Override
|
||||
public BlockEntity createBlockEntity(BlockVec position) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package com.dfsek.terra.minestom.block;
|
||||
|
||||
import com.dfsek.terra.api.block.BlockType;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.block.state.properties.Property;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class MinestomBlockState implements BlockState {
|
||||
private final Block block;
|
||||
|
||||
public MinestomBlockState(Block block) {
|
||||
if(block == null) {
|
||||
this.block = Block.AIR;
|
||||
} else {
|
||||
this.block = block;
|
||||
}
|
||||
}
|
||||
|
||||
public MinestomBlockState(String data) {
|
||||
if(!data.contains("[")) {
|
||||
block = Block.fromNamespaceId(data);
|
||||
return;
|
||||
}
|
||||
|
||||
String[] split = data.split("\\[");
|
||||
String namespaceId = split[0];
|
||||
String properties = split[1].substring(0, split[1].length() - 1);
|
||||
Block block = Block.fromNamespaceId(namespaceId);
|
||||
HashMap<String, String> propertiesMap = new HashMap<>();
|
||||
|
||||
for(String property : properties.split(",")) {
|
||||
String[] kv = property.split("=");
|
||||
propertiesMap.put(kv[0].strip(), kv[1].strip());
|
||||
}
|
||||
|
||||
assert block != null;
|
||||
this.block = block.withProperties(propertiesMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(BlockState other) {
|
||||
return ((MinestomBlockState) other).block.compare(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Comparable<T>> boolean has(Property<T> property) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Comparable<T>> T get(Property<T> property) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Comparable<T>> BlockState set(Property<T> property, T value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockType getBlockType() {
|
||||
return new MinestomBlockType(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsString(boolean properties) {
|
||||
String name = block.namespace().asString();
|
||||
if(!properties || block.properties().isEmpty()) {
|
||||
return name;
|
||||
}
|
||||
|
||||
name += "[" + block.properties().entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).collect(
|
||||
Collectors.joining(",")) + "]";
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAir() {
|
||||
return block.isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(block.id());
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.dfsek.terra.minestom.block;
|
||||
|
||||
import com.dfsek.terra.api.block.BlockType;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
|
||||
|
||||
public class MinestomBlockType implements BlockType {
|
||||
private final Block block;
|
||||
|
||||
public MinestomBlockType(Block block) {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getDefaultState() {
|
||||
return new MinestomBlockState(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSolid() {
|
||||
return block.isSolid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWater() {
|
||||
return block.isLiquid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return block.id();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if(obj instanceof MinestomBlockType other) {
|
||||
return block.id() == other.block.id();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.dfsek.terra.minestom.chunk;
|
||||
|
||||
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
|
||||
import com.dfsek.terra.api.world.chunk.generation.ProtoChunk;
|
||||
import com.dfsek.terra.minestom.block.MinestomBlockState;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.generator.UnitModifier;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class CachedChunk implements ProtoChunk {
|
||||
private final int minHeight;
|
||||
private final int maxHeight;
|
||||
private final Block[][][] blocks;
|
||||
|
||||
public CachedChunk(int minHeight, int maxHeight) {
|
||||
this.minHeight = minHeight;
|
||||
this.maxHeight = maxHeight;
|
||||
this.blocks = new Block[16][maxHeight - minHeight + 1][16];
|
||||
|
||||
for(int x = 0; x < 16; x++) {
|
||||
for(int z = 0; z < 16; z++) {
|
||||
for(int y = 0; y < maxHeight - minHeight + 1; y++) {
|
||||
blocks[x][y][z] = Block.AIR;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void writeRelative(UnitModifier modifier) {
|
||||
modifier.setAllRelative((x, y, z) -> blocks[x][y][z]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, @NotNull BlockState blockState) {
|
||||
Block block = (Block) blockState.getHandle();
|
||||
if(block == null) return;
|
||||
blocks[x][y - minHeight][z] = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull BlockState getBlock(int x, int y, int z) {
|
||||
return new MinestomBlockState(blocks[x][y - minHeight][z]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return blocks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHeight() {
|
||||
return maxHeight;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.dfsek.terra.minestom.chunk;
|
||||
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
import com.dfsek.terra.api.world.ServerWorld;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.github.benmanes.caffeine.cache.stats.CacheStats;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class GeneratedChunkCache {
|
||||
private static final Logger log = LoggerFactory.getLogger(GeneratedChunkCache.class);
|
||||
private final LoadingCache<Pair<Integer, Integer>, CachedChunk> cache;
|
||||
private final DimensionType dimensionType;
|
||||
private final ChunkGenerator generator;
|
||||
private final ServerWorld world;
|
||||
private final BiomeProvider biomeProvider;
|
||||
|
||||
public GeneratedChunkCache(DimensionType dimensionType, ChunkGenerator generator, ServerWorld world) {
|
||||
this.dimensionType = dimensionType;
|
||||
this.generator = generator;
|
||||
this.world = world;
|
||||
this.biomeProvider = world.getBiomeProvider();
|
||||
this.cache = Caffeine.newBuilder().maximumSize(128).recordStats().build(
|
||||
(Pair<Integer, Integer> key) -> generateChunk(key.getLeft(), key.getRight()));
|
||||
}
|
||||
|
||||
private CachedChunk generateChunk(int x, int z) {
|
||||
CachedChunk chunk = new CachedChunk(dimensionType.minY(), dimensionType.maxY());
|
||||
generator.generateChunkData(chunk, world, biomeProvider, x, z);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
public void displayStats() {
|
||||
CacheStats stats = cache.stats();
|
||||
log.info("Avg load time: {}ms | Hit rate: {}% | Load Count: {}", stats.averageLoadPenalty(), stats.hitRate() * 100,
|
||||
stats.loadCount());
|
||||
}
|
||||
|
||||
public CachedChunk at(int x, int z) {
|
||||
return cache.get(Pair.of(x, z));
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.dfsek.terra.minestom.chunk;
|
||||
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.world.ServerWorld;
|
||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
||||
|
||||
import com.dfsek.terra.minestom.block.MinestomBlockState;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class TerraMinestomChunk implements Chunk {
|
||||
private net.minestom.server.instance.Chunk delegate;
|
||||
private final ServerWorld world;
|
||||
|
||||
public TerraMinestomChunk(net.minestom.server.instance.Chunk delegate, ServerWorld world) {
|
||||
this.delegate = delegate;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlock(int x, int y, int z, BlockState data, boolean physics) {
|
||||
delegate.setBlock(x, y, z, (Block) data.getHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull BlockState getBlock(int x, int y, int z) {
|
||||
return new MinestomBlockState(delegate.getBlock(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getX() {
|
||||
return delegate.getChunkX();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getZ() {
|
||||
return delegate.getChunkZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerWorld getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.dfsek.terra.minestom.entity;
|
||||
|
||||
import com.dfsek.terra.minestom.api.EntityFactory;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
|
||||
|
||||
public class DefaultEntityFactory implements EntityFactory {
|
||||
@Override
|
||||
public Entity createEntity(EntityType type) {
|
||||
return new Entity(type);
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package com.dfsek.terra.minestom.entity;
|
||||
|
||||
import com.dfsek.terra.api.entity.Entity;
|
||||
import com.dfsek.terra.api.entity.EntityType;
|
||||
import com.dfsek.terra.api.util.vector.Vector3;
|
||||
import com.dfsek.terra.api.world.ServerWorld;
|
||||
import com.dfsek.terra.minestom.world.TerraMinestomWorld;
|
||||
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
|
||||
|
||||
public class DeferredMinestomEntity implements Entity {
|
||||
private final EntityType type;
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
private TerraMinestomWorld world;
|
||||
|
||||
public DeferredMinestomEntity(double x, double y, double z, EntityType type, TerraMinestomWorld world) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.type = type;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3 position() {
|
||||
return Vector3.of(x, y, z);
|
||||
}
|
||||
|
||||
public Pos pos() {
|
||||
return new Pos(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void position(Vector3 position) {
|
||||
x = position.getX();
|
||||
y = position.getY();
|
||||
z = position.getZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void world(ServerWorld world) {
|
||||
this.world = (TerraMinestomWorld) world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerWorld world() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public void spawn() {
|
||||
int chunkX = (int) x >> 4;
|
||||
int chunkZ = (int) z >> 4;
|
||||
|
||||
if(!world.getHandle().isChunkLoaded(chunkX, chunkZ)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MinestomEntity.spawn(x, y, z, type, world);
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.dfsek.terra.minestom.entity;
|
||||
|
||||
import com.dfsek.terra.api.entity.EntityType;
|
||||
import com.dfsek.terra.api.util.vector.Vector3;
|
||||
import com.dfsek.terra.api.world.ServerWorld;
|
||||
|
||||
import com.dfsek.terra.minestom.MinestomAdapter;
|
||||
import com.dfsek.terra.minestom.world.TerraMinestomWorld;
|
||||
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.instance.Instance;
|
||||
|
||||
|
||||
public class MinestomEntity implements com.dfsek.terra.api.entity.Entity {
|
||||
private final Entity delegate;
|
||||
private final TerraMinestomWorld world;
|
||||
|
||||
public MinestomEntity(Entity delegate, TerraMinestomWorld world) {
|
||||
this.delegate = delegate;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3 position() {
|
||||
return MinestomAdapter.adapt(delegate.getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void position(Vector3 position) {
|
||||
delegate.teleport(MinestomAdapter.adapt(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void world(ServerWorld world) {
|
||||
delegate.setInstance(((TerraMinestomWorld) world).getHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerWorld world() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
public static MinestomEntity spawn(double x, double y, double z, EntityType type, TerraMinestomWorld world) {
|
||||
Instance instance = world.getHandle();
|
||||
Entity entity = world.getEntityFactory().createEntity(((MinestomEntityType) type).getHandle());
|
||||
entity.setInstance(instance, new Pos(x, y, z));
|
||||
return new MinestomEntity(entity, world);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.dfsek.terra.minestom.entity;
|
||||
|
||||
|
||||
import net.minestom.server.entity.EntityType;
|
||||
|
||||
|
||||
public class MinestomEntityType implements com.dfsek.terra.api.entity.EntityType {
|
||||
private final EntityType delegate;
|
||||
|
||||
public MinestomEntityType(String id) {
|
||||
delegate = EntityType.fromNamespaceId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getHandle() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package com.dfsek.terra.minestom.item;
|
||||
|
||||
import com.dfsek.terra.api.inventory.ItemStack;
|
||||
import com.dfsek.terra.api.inventory.item.Enchantment;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
public class MinestomEnchantment implements Enchantment {
|
||||
private final net.minestom.server.item.enchant.Enchantment delegate;
|
||||
private final String id;
|
||||
|
||||
public MinestomEnchantment(net.minestom.server.item.enchant.Enchantment delegate) {
|
||||
this.delegate = delegate;
|
||||
id = Objects.requireNonNull(delegate.registry()).raw();
|
||||
}
|
||||
|
||||
public MinestomEnchantment(String id) {
|
||||
this.delegate = MinecraftServer.getEnchantmentRegistry().get(NamespaceID.from(id));
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEnchantItem(ItemStack itemStack) {
|
||||
return delegate.supportedItems().contains((Material) itemStack.getType().getHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean conflictsWith(Enchantment other) {
|
||||
return delegate.exclusiveSet().contains(NamespaceID.from(((MinestomEnchantment) other).id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxLevel() {
|
||||
return delegate.maxLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public net.minestom.server.item.enchant.Enchantment getHandle() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.dfsek.terra.minestom.item;
|
||||
|
||||
import com.dfsek.terra.api.handle.ItemHandle;
|
||||
import com.dfsek.terra.api.inventory.Item;
|
||||
import com.dfsek.terra.api.inventory.item.Enchantment;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class MinestomItemHandle implements ItemHandle {
|
||||
@Override
|
||||
public Item createItem(String data) {
|
||||
return new MinestomMaterial(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enchantment getEnchantment(String id) {
|
||||
return new MinestomEnchantment(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Enchantment> getEnchantments() {
|
||||
return MinecraftServer.getEnchantmentRegistry().values().stream().map(MinestomEnchantment::new).collect(Collectors.toSet());
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.dfsek.terra.minestom.item;
|
||||
|
||||
import com.dfsek.terra.api.inventory.item.Enchantment;
|
||||
import com.dfsek.terra.api.inventory.item.ItemMeta;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class MinestomItemMeta implements ItemMeta {
|
||||
private final HashMap<Enchantment, Integer> enchantments;
|
||||
|
||||
public MinestomItemMeta(HashMap<Enchantment, Integer> enchantments) {
|
||||
this.enchantments = enchantments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEnchantment(Enchantment enchantment, int level) {
|
||||
enchantments.put(enchantment, level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Enchantment, Integer> getEnchantments() {
|
||||
return enchantments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return enchantments;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package com.dfsek.terra.minestom.item;
|
||||
|
||||
import com.dfsek.terra.api.inventory.Item;
|
||||
|
||||
import com.dfsek.terra.api.inventory.item.Enchantment;
|
||||
import com.dfsek.terra.api.inventory.item.ItemMeta;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.item.ItemComponent;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.component.EnchantmentList;
|
||||
import net.minestom.server.registry.DynamicRegistry;
|
||||
import net.minestom.server.registry.DynamicRegistry.Key;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
public class MinestomItemStack implements com.dfsek.terra.api.inventory.ItemStack {
|
||||
private ItemStack base;
|
||||
|
||||
public MinestomItemStack(net.minestom.server.item.@NotNull ItemStack base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAmount() {
|
||||
return base.amount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAmount(int i) {
|
||||
base = base.withAmount(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item getType() {
|
||||
return new MinestomMaterial(base.material());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemMeta getItemMeta() {
|
||||
HashMap<Enchantment, Integer> enchantments = new HashMap<>();
|
||||
EnchantmentList enchantmentList = base.get(ItemComponent.ENCHANTMENTS);
|
||||
if(enchantmentList != null) {
|
||||
enchantmentList.enchantments().forEach((enchantmentKey, integer) -> {
|
||||
enchantments.put(
|
||||
new MinestomEnchantment(Objects.requireNonNull(MinecraftServer.getEnchantmentRegistry().get(enchantmentKey))), integer);
|
||||
});
|
||||
}
|
||||
return new MinestomItemMeta(enchantments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItemMeta(ItemMeta meta) {
|
||||
HashMap<Key<net.minestom.server.item.enchant.Enchantment>, Integer> enchantments = new HashMap<>();
|
||||
DynamicRegistry<net.minestom.server.item.enchant.Enchantment> registry = MinecraftServer.getEnchantmentRegistry();
|
||||
meta.getEnchantments().forEach((key, value) -> {
|
||||
MinestomEnchantment enchantment = (MinestomEnchantment) key;
|
||||
enchantments.put(registry.getKey(enchantment.getHandle()), value);
|
||||
});
|
||||
|
||||
EnchantmentList list = new EnchantmentList(enchantments);
|
||||
base = base.with(ItemComponent.ENCHANTMENTS, list);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.dfsek.terra.minestom.item;
|
||||
|
||||
import com.dfsek.terra.api.inventory.Item;
|
||||
import com.dfsek.terra.api.inventory.ItemStack;
|
||||
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
|
||||
public class MinestomMaterial implements Item {
|
||||
private final Material delegate;
|
||||
|
||||
public MinestomMaterial(Material delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public MinestomMaterial(String id) {
|
||||
this.delegate = Material.fromNamespaceId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack newItemStack(int amount) {
|
||||
return new MinestomItemStack(net.minestom.server.item.ItemStack.builder(delegate).amount(amount).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMaxDurability() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Material getHandle() {
|
||||
return delegate;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package com.dfsek.terra.minestom.world;
|
||||
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||
|
||||
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
|
||||
import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper;
|
||||
import com.dfsek.terra.minestom.chunk.CachedChunk;
|
||||
import com.dfsek.terra.minestom.chunk.GeneratedChunkCache;
|
||||
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.instance.generator.GenerationUnit;
|
||||
import net.minestom.server.instance.generator.Generator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class MinestomChunkGeneratorWrapper implements Generator, GeneratorWrapper {
|
||||
private final GeneratedChunkCache cache;
|
||||
private ChunkGenerator generator;
|
||||
private final TerraMinestomWorld world;
|
||||
private ConfigPack pack;
|
||||
|
||||
public MinestomChunkGeneratorWrapper(ChunkGenerator generator, TerraMinestomWorld world, ConfigPack pack) {
|
||||
this.generator = generator;
|
||||
this.world = world;
|
||||
this.pack = pack;
|
||||
this.cache = new GeneratedChunkCache(world.getDimensionType(), generator, world);
|
||||
}
|
||||
|
||||
public ChunkGenerator getGenerator() {
|
||||
return generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(@NotNull GenerationUnit unit) {
|
||||
Point start = unit.absoluteStart();
|
||||
int x = start.chunkX();
|
||||
int z = start.chunkZ();
|
||||
CachedChunk chunk = cache.at(x, z);
|
||||
chunk.writeRelative(unit.modifier());
|
||||
|
||||
unit.fork(setter -> {
|
||||
MinestomProtoWorld protoWorld = new MinestomProtoWorld(cache, x, z, world, setter);
|
||||
|
||||
for(GenerationStage stage : world.getPack().getStages()) {
|
||||
stage.populate(protoWorld);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ConfigPack getPack() {
|
||||
return pack;
|
||||
}
|
||||
|
||||
public void setPack(ConfigPack pack) {
|
||||
this.pack = pack;
|
||||
this.generator = pack.getGeneratorProvider().newInstance(pack);
|
||||
}
|
||||
|
||||
public void displayStats() {
|
||||
cache.displayStats();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkGenerator getHandle() {
|
||||
return generator;
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package com.dfsek.terra.minestom.world;
|
||||
|
||||
import com.dfsek.terra.api.block.entity.BlockEntity;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.entity.Entity;
|
||||
import com.dfsek.terra.api.entity.EntityType;
|
||||
import com.dfsek.terra.api.world.ServerWorld;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||
import com.dfsek.terra.api.world.chunk.generation.ProtoWorld;
|
||||
import com.dfsek.terra.minestom.chunk.CachedChunk;
|
||||
import com.dfsek.terra.minestom.chunk.GeneratedChunkCache;
|
||||
|
||||
import com.dfsek.terra.minestom.entity.DeferredMinestomEntity;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.block.Block.Setter;
|
||||
|
||||
|
||||
public class MinestomProtoWorld implements ProtoWorld {
|
||||
private final GeneratedChunkCache cache;
|
||||
private final int x;
|
||||
private final int z;
|
||||
private final TerraMinestomWorld world;
|
||||
private final Setter modifier;
|
||||
|
||||
public MinestomProtoWorld(GeneratedChunkCache cache, int x, int z, TerraMinestomWorld world, Setter modifier) {
|
||||
this.cache = cache;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
this.world = world;
|
||||
this.modifier = modifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int centerChunkX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int centerChunkZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerWorld getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockState(int x, int y, int z, BlockState data, boolean physics) {
|
||||
modifier.setBlock(x, y, z, (Block) data.getHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity spawnEntity(double x, double y, double z, EntityType entityType) {
|
||||
TerraMinestomWorld world = this.world;
|
||||
DeferredMinestomEntity entity = new DeferredMinestomEntity(x, y, z, entityType, world);
|
||||
world.enqueue(entity.pos(), (chunk) -> entity.spawn());
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(int x, int y, int z) {
|
||||
int chunkX = x >> 4;
|
||||
int chunkZ = z >> 4;
|
||||
CachedChunk chunk = cache.at(chunkX, chunkZ);
|
||||
return chunk.getBlock(x & 15, y, z & 15);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(int x, int y, int z) {
|
||||
return world.getBlockEntity(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkGenerator getGenerator() {
|
||||
return world.getGenerator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeProvider getBiomeProvider() {
|
||||
return world.getBiomeProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigPack getPack() {
|
||||
return world.getPack();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSeed() {
|
||||
return world.getSeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHeight() {
|
||||
return world.getMaxHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinHeight() {
|
||||
return world.getMinHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return world;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.dfsek.terra.minestom.world;
|
||||
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.entity.EntityType;
|
||||
import com.dfsek.terra.api.handle.WorldHandle;
|
||||
|
||||
import com.dfsek.terra.minestom.block.MinestomBlockState;
|
||||
import com.dfsek.terra.minestom.entity.MinestomEntityType;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class MinestomWorldHandle implements WorldHandle {
|
||||
private static final MinestomBlockState AIR = new MinestomBlockState(Block.AIR);
|
||||
|
||||
@Override
|
||||
public @NotNull BlockState createBlockState(@NotNull String data) {
|
||||
return new MinestomBlockState(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull BlockState air() {
|
||||
return AIR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull EntityType getEntity(@NotNull String id) {
|
||||
return new MinestomEntityType(id);
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package com.dfsek.terra.minestom.world;
|
||||
|
||||
import com.dfsek.terra.api.block.entity.BlockEntity;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.entity.Entity;
|
||||
import com.dfsek.terra.api.entity.EntityType;
|
||||
import com.dfsek.terra.api.world.ServerWorld;
|
||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
||||
|
||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||
|
||||
import com.dfsek.terra.api.world.info.WorldProperties;
|
||||
|
||||
import com.dfsek.terra.minestom.api.BlockEntityFactory;
|
||||
import com.dfsek.terra.minestom.api.EntityFactory;
|
||||
import com.dfsek.terra.minestom.block.MinestomBlockState;
|
||||
import com.dfsek.terra.minestom.entity.MinestomEntity;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.coordinate.BlockVec;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
||||
public final class TerraMinestomWorld implements ServerWorld, WorldProperties {
|
||||
private final Instance instance;
|
||||
private final ConfigPack pack;
|
||||
private final long seed;
|
||||
private final DimensionType dimensionType;
|
||||
private final MinestomChunkGeneratorWrapper wrapper;
|
||||
private final EntityFactory entityFactory;
|
||||
private final BlockEntityFactory blockEntityFactory;
|
||||
|
||||
public TerraMinestomWorld(Instance instance, ConfigPack pack, long seed, EntityFactory entityFactory,
|
||||
BlockEntityFactory blockEntityFactory) {
|
||||
this.instance = instance;
|
||||
this.pack = pack;
|
||||
this.seed = seed;
|
||||
|
||||
this.dimensionType = MinecraftServer.getDimensionTypeRegistry().get(instance.getDimensionType());
|
||||
this.blockEntityFactory = blockEntityFactory;
|
||||
|
||||
this.wrapper = new MinestomChunkGeneratorWrapper(pack.getGeneratorProvider().newInstance(pack), this, pack);
|
||||
this.entityFactory = entityFactory;
|
||||
|
||||
instance.setGenerator(this.wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Chunk getChunkAt(int x, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlockState(int x, int y, int z, BlockState data, boolean physics) {
|
||||
instance.setBlock(x, y, z, (Block) data.getHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity spawnEntity(double x, double y, double z, EntityType entityType) {
|
||||
return MinestomEntity.spawn(x, y, z, entityType, this);
|
||||
}
|
||||
|
||||
public void displayStats() {
|
||||
wrapper.displayStats();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(int x, int y, int z) {
|
||||
return new MinestomBlockState(instance.getBlock(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(int x, int y, int z) {
|
||||
return blockEntityFactory.createBlockEntity(new BlockVec(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChunkGenerator getGenerator() {
|
||||
return wrapper.getGenerator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeProvider getBiomeProvider() {
|
||||
return pack.getBiomeProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigPack getPack() {
|
||||
return pack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSeed() {
|
||||
return seed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxHeight() {
|
||||
return dimensionType.maxY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinHeight() {
|
||||
return dimensionType.minY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Instance getHandle() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public DimensionType getDimensionType() {
|
||||
return dimensionType;
|
||||
}
|
||||
|
||||
public EntityFactory getEntityFactory() {
|
||||
return entityFactory;
|
||||
}
|
||||
|
||||
public void enqueue(Point position, Consumer<net.minestom.server.instance.Chunk> action) {
|
||||
instance.loadChunk(position.chunkX(), position.chunkZ()).thenAccept(action);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package com.dfsek.terra.minestom.world;
|
||||
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
|
||||
import com.dfsek.terra.api.registry.CheckedRegistry;
|
||||
|
||||
import com.dfsek.terra.minestom.MinestomPlatform;
|
||||
import com.dfsek.terra.minestom.api.BlockEntityFactory;
|
||||
import com.dfsek.terra.minestom.api.EntityFactory;
|
||||
import com.dfsek.terra.minestom.block.DefaultBlockEntityFactory;
|
||||
import com.dfsek.terra.minestom.entity.DefaultEntityFactory;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.instance.Instance;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.function.Function;
|
||||
|
||||
|
||||
public class TerraMinestomWorldBuilder {
|
||||
private final Instance instance;
|
||||
private ConfigPack pack;
|
||||
private long seed = new Random().nextLong();
|
||||
private EntityFactory entityFactory = new DefaultEntityFactory();
|
||||
private BlockEntityFactory blockEntityFactory = new DefaultBlockEntityFactory();
|
||||
|
||||
private TerraMinestomWorldBuilder(Instance instance) { this.instance = instance; }
|
||||
|
||||
public static TerraMinestomWorldBuilder from(Instance instance) {
|
||||
return new TerraMinestomWorldBuilder(instance);
|
||||
}
|
||||
|
||||
public static TerraMinestomWorldBuilder builder() {
|
||||
return new TerraMinestomWorldBuilder(MinecraftServer.getInstanceManager().createInstanceContainer());
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder pack(ConfigPack pack) {
|
||||
this.pack = pack;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder packById(String id) {
|
||||
this.pack = MinestomPlatform.getInstance().getConfigRegistry().getByID(id).orElseThrow();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder findPack(Function<CheckedRegistry<ConfigPack>, ConfigPack> fn) {
|
||||
this.pack = fn.apply(MinestomPlatform.getInstance().getConfigRegistry());
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder defaultPack() {
|
||||
return this.packById("OVERWORLD");
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder seed(long seed) {
|
||||
this.seed = seed;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder entityFactory(EntityFactory factory) {
|
||||
this.entityFactory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerraMinestomWorldBuilder blockEntityFactory(BlockEntityFactory factory) {
|
||||
this.blockEntityFactory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TerraMinestomWorld attach() {
|
||||
return new TerraMinestomWorld(instance, pack, seed, entityFactory, blockEntityFactory);
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ includeImmediateChildren(file("platforms"), "platform")
|
||||
includeImmediateChildren(file("platforms/bukkit/nms"), "Bukkit NMS")
|
||||
|
||||
include(":platforms:bukkit:common")
|
||||
include(":platforms:minestom:example")
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
|
Loading…
x
Reference in New Issue
Block a user