Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/gradle-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ jobs:

steps:
- uses: actions/checkout@v4.2.2
- name: Set up JDK 21
- name: Set up JDK 25
uses: actions/setup-java@v4.7.1
with:
java-version: '21'
java-version: '25'
distribution: 'temurin'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ dependencies {
//TODO Allow pulling from Versions.kt
implementation("com.gradleup.shadow", "shadow-gradle-plugin", "8.3.9")

implementation("io.papermc.paperweight.userdev", "io.papermc.paperweight.userdev.gradle.plugin", "2.0.0-beta.18")
implementation("io.papermc.paperweight.userdev", "io.papermc.paperweight.userdev.gradle.plugin", "2.0.0-beta.21")
implementation("org.ow2.asm", "asm", "9.9")
implementation("org.ow2.asm", "asm-tree", "9.9")
implementation("com.dfsek.tectonic", "common", "4.3.1")
Expand Down
11 changes: 3 additions & 8 deletions buildSrc/src/main/kotlin/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,14 @@ var isPrerelease = false


fun Project.getGitHash(): String {
val stdout = ByteArrayOutputStream()
exec {
return providers.exec {
commandLine = mutableListOf("git", "rev-parse", "--short", "HEAD")
standardOutput = stdout
}
return stdout.toString().trim()
}.standardOutput.asText.get().trim()
}

fun Project.gitClone(name: String) {
val stdout = ByteArrayOutputStream()
exec {
providers.exec {
commandLine = mutableListOf("git", "clone", name)
standardOutput = stdout
}
}

Expand Down
13 changes: 7 additions & 6 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ object Versions {
const val strata = "1.3.2"
const val seismic = "2.5.7"

const val cloud = "2.0.0"
const val cloud = "2.1.0"

const val caffeine = "3.2.2"

Expand Down Expand Up @@ -60,16 +60,17 @@ object Versions {
// }

object Bukkit {
const val minecraft = "1.21.10"
const val minecraft = "26.1.2"
const val nms = "$minecraft-R0.1"
const val paperBuild = "$nms-20251012.013929-7"
const val paperBuild = "26.1.2.build.60-stable"
const val paper = paperBuild
const val paperLib = "1.0.8"
const val reflectionRemapper = "0.1.3"
const val paperDevBundle = paperBuild
const val runPaper = "2.3.1"
const val paperWeight = "2.0.0-beta.19"
const val cloud = "2.0.0-beta.12"
const val paperDevBundle26_3 = "26.3.build.156-beta"
const val runPaper = "3.0.2"
const val paperWeight = "2.0.0-beta.21"
const val cloud = "2.0.1"
const val multiverse = "5.3.0"
}

Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=845952a9d6afa783db70bb3b0effaae45ae5542ca2bb7929619e8af49cb634cf
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
distributionSha256Sum=553c78f50dafcd54d65b9a444649057857469edf836431389695608536d6b746
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
8 changes: 7 additions & 1 deletion platforms/bukkit/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@ dependencies {
paperweight.paperDevBundle(Versions.Bukkit.paperDevBundle)

shaded(project(":platforms:bukkit:common"))
shaded(project(":platforms:bukkit:nms"))
shaded(project(path = ":platforms:bukkit:nms:common", configuration = "runtimeElements"))
shaded(project(path = ":platforms:bukkit:nms:26.1", configuration = "runtimeElements"))
shaded(project(path = ":platforms:bukkit:nms:26.3", configuration = "runtimeElements"))
shaded("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
}

tasks.withType<JavaCompile>().configureEach {
options.release = 25
}

tasks {
shadowJar {
relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib")
Expand Down
3 changes: 3 additions & 0 deletions platforms/bukkit/common/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
repositories {

}
tasks.withType<JavaCompile>().configureEach {
options.release = 25
}

dependencies {
shadedApi(project(":common:implementation:base"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
import java.util.List;

import com.dfsek.terra.bukkit.util.VersionUtil;
import com.dfsek.terra.bukkit.util.BukkitNMSAccess;
import com.dfsek.terra.bukkit.util.BukkitUtils;


public interface NMSInitializer {
List<String> SUPPORTED_VERSIONS = List.of("v1.21.9", "v1.21.10");
List<String> SUPPORTED_VERSIONS = List.of("v26.1.2", "v26.2", "v26.3");
String MINECRAFT_VERSION = VersionUtil.getMinecraftVersionInfo().toString();
String TERRA_PACKAGE = NMSInitializer.class.getPackageName();

Expand Down Expand Up @@ -44,10 +46,19 @@ static PlatformImpl init(TerraBukkitPlugin plugin) {

private static PlatformImpl constructPlatform(TerraBukkitPlugin plugin) {
try {
Class<?> platformClass = Class.forName(TERRA_PACKAGE + ".nms.NMSPlatform");
return (PlatformImpl) platformClass
String bindingsVersion = switch(MINECRAFT_VERSION) {
case "v26.3" -> "v26_3";
case "v26.1.2", "v26.2" -> "v26_1";
default -> "v26_1";
};
Class<?> platformClass = Class.forName(TERRA_PACKAGE + ".nms." + bindingsVersion + ".NMSPlatform");
PlatformImpl platform = (PlatformImpl) platformClass
.getConstructor(TerraBukkitPlugin.class)
.newInstance(plugin);
if(platform instanceof BukkitNMSAccess nmsAccess) {
BukkitUtils.setNMSAccess(nmsAccess);
}
return platform;
} catch(ReflectiveOperationException e) {
throw new RuntimeException("Error initializing NMS bindings. Report this to Terra.", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -29,6 +30,9 @@
import com.dfsek.terra.bukkit.util.BukkitUtils;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


public class BukkitWorldHandle implements WorldHandle {
private static final Logger logger = LoggerFactory.getLogger(BukkitWorldHandle.class);
Expand All @@ -40,9 +44,19 @@ public BukkitWorldHandle() {

@Override
public synchronized @NotNull BlockState createBlockState(@NotNull String data) {
org.bukkit.block.data.BlockData bukkitData = Bukkit.createBlockData(
data); // somehow bukkit managed to make this not thread safe! :)
return BukkitBlockState.newInstance(bukkitData);
try {
org.bukkit.block.data.BlockData bukkitData = Bukkit.createBlockData(data); // somehow bukkit managed to make this not thread safe! :)
return BukkitBlockState.newInstance(bukkitData);
} catch (Exception ignored) {
try {
Class<?> hacks = Class.forName("com.dfsek.terra.bukkit.nms.AwfulBukkitHacks");
Method method = hacks.getMethod("createBlockState", String.class);
Object result = method.invoke(null, data);
return BukkitBlockState.newInstance((BlockData) result);
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new IllegalArgumentException("Invalid block state data: " + data);
}
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.dfsek.terra.bukkit.util;

import org.bukkit.Location;
import org.bukkit.block.CreatureSpawner;

import com.dfsek.terra.api.entity.EntityType;
import com.dfsek.terra.api.entity.EntityTypeExtended;


public interface BukkitNMSAccess {
EntityType getEntityType(String data);

org.bukkit.entity.Entity spawnEntity(Object target, Location location, EntityType type);

void setSpawnerEntity(CreatureSpawner spawner, EntityTypeExtended type);
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,62 @@
package com.dfsek.terra.bukkit.util;

import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.block.CreatureSpawner;
import org.bukkit.block.data.BlockData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Locale;

import com.dfsek.terra.api.entity.EntityType;
import com.dfsek.terra.api.entity.EntityTypeExtended;
import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;


public class BukkitUtils {
private static final Logger logger = LoggerFactory.getLogger(BukkitUtils.class);
private static volatile BukkitNMSAccess nmsAccess;

public static boolean isLiquid(BlockData blockState) {
Material material = blockState.getMaterial();
return material == Material.WATER || material == Material.LAVA;
}

public static void setNMSAccess(BukkitNMSAccess access) {
nmsAccess = access;
}

public static EntityType getEntityType(String id) {
if(!id.startsWith("minecraft:")) throw new IllegalArgumentException("Invalid entity identifier " + id);
String entityID = id.toUpperCase(Locale.ROOT).substring(10);

return new BukkitEntityType(switch(entityID) {
case "END_CRYSTAL" -> org.bukkit.entity.EntityType.END_CRYSTAL;
case "ENDER_CRYSTAL" -> throw new IllegalArgumentException(
"Invalid entity identifier " + id); // make sure this issue can't happen the other way around.
default -> org.bukkit.entity.EntityType.valueOf(entityID);
});
BukkitNMSAccess access = nmsAccess;
return access == null ? getBukkitEntityType(id) : access.getEntityType(id);
}

public static org.bukkit.entity.Entity spawnEntity(Object region, org.bukkit.Location location, EntityType entityType) {
if(entityType instanceof EntityTypeExtended) {
BukkitNMSAccess access = nmsAccess;
if(access == null) throw new IllegalStateException("Entity NBT loading requires Terra's NMS bindings");
return access.spawnEntity(region, location, entityType);
}

org.bukkit.entity.EntityType bukkitType = ((BukkitEntityType) entityType).getHandle();
if(region instanceof org.bukkit.generator.LimitedRegion limitedRegion) {
return limitedRegion.spawnEntity(location, bukkitType);
}
return ((org.bukkit.World) region).spawnEntity(location, bukkitType);
}

public static void setSpawnerEntity(CreatureSpawner spawner, EntityTypeExtended type) {
BukkitNMSAccess access = nmsAccess;
if(access == null) throw new IllegalStateException("Entity NBT loading requires Terra's NMS bindings");
access.setSpawnerEntity(spawner, type);
}

private static EntityType getBukkitEntityType(String data) {
int nbtStart = data.indexOf('{');
if(nbtStart >= 0) {
throw new IllegalArgumentException("Entity NBT loading requires Terra's NMS bindings: " + data);
}

NamespacedKey key = NamespacedKey.fromString(data);
org.bukkit.entity.EntityType type = key == null ? null : Registry.ENTITY_TYPE.get(key);
if(type == null) throw new IllegalArgumentException("Invalid entity identifier " + data);
return new BukkitEntityType(type);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import com.dfsek.terra.bukkit.util.BukkitUtils;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
import com.dfsek.terra.bukkit.world.block.state.BukkitBlockEntity;
import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;


public class BukkitProtoWorld implements ProtoWorld {
Expand Down Expand Up @@ -89,7 +88,7 @@ public int getMinHeight() {
@Override
public Entity spawnEntity(double x, double y, double z, EntityType entityType) {
return access((int) x, (int) y, (int) z, () -> new BukkitEntity(
delegate.spawnEntity(new Location(delegate.getWorld(), x, y, z), ((BukkitEntityType) entityType).getHandle()))).orElse(
BukkitUtils.spawnEntity(delegate, new Location(delegate.getWorld(), x, y, z), entityType))).orElse(
null);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
import com.dfsek.terra.bukkit.BukkitEntity;
import com.dfsek.terra.bukkit.generator.BukkitChunkGeneratorWrapper;
import com.dfsek.terra.bukkit.util.BukkitUtils;
import com.dfsek.terra.bukkit.world.block.state.BukkitBlockEntity;
import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;


public class BukkitServerWorld implements ServerWorld {
Expand All @@ -43,8 +43,7 @@ public BukkitServerWorld(org.bukkit.World delegate) {

@Override
public Entity spawnEntity(double x, double y, double z, EntityType entityType) {
return new BukkitEntity(
delegate.spawnEntity(new Location(delegate, x, y, z), ((BukkitEntityType) entityType).getHandle()));
return new BukkitEntity(BukkitUtils.spawnEntity(delegate, new Location(delegate, x, y, z), entityType));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.dfsek.terra.api.block.entity.MobSpawner;
import com.dfsek.terra.api.block.entity.SerialState;
import com.dfsek.terra.api.entity.EntityType;
import com.dfsek.terra.api.entity.EntityTypeExtended;
import com.dfsek.terra.bukkit.util.BukkitUtils;
import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;

Expand All @@ -39,7 +40,12 @@ public EntityType getSpawnedType() {

@Override
public void setSpawnedType(@NotNull EntityType creatureType) {
((CreatureSpawner) getHandle()).setSpawnedType(((BukkitEntityType) creatureType).getHandle());
CreatureSpawner spawner = (CreatureSpawner) getHandle();
if(creatureType instanceof EntityTypeExtended extended) {
BukkitUtils.setSpawnerEntity(spawner, extended);
} else {
spawner.setSpawnedType(((BukkitEntityType) creatureType).getHandle());
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.dfsek.terra.bukkit.world.entity;

import com.dfsek.terra.api.data.ExtendedData;


public record BukkitEntityData(String snbt) implements ExtendedData {
@Override
public Object getHandle() {
return snbt;
}

@Override
public String toString() {
return snbt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.dfsek.terra.bukkit.world.entity;

import com.dfsek.terra.api.data.ExtendedData;
import com.dfsek.terra.api.entity.EntityType;
import com.dfsek.terra.api.entity.EntityTypeExtended;


public final class BukkitEntityTypeExtended extends BukkitEntityType implements EntityTypeExtended {
private final BukkitEntityData data;

public BukkitEntityTypeExtended(org.bukkit.entity.EntityType delegate, String snbt) {
super(delegate);
this.data = new BukkitEntityData(snbt);
}

@Override
public ExtendedData getData() {
return data;
}

@Override
public EntityTypeExtended setData(ExtendedData data) {
Object handle = data.getHandle();
if(!(handle instanceof String snbt)) {
throw new IllegalArgumentException("Bukkit entity data must contain SNBT text");
}
return new BukkitEntityTypeExtended(getHandle(), snbt);
}

@Override
public EntityType getType() {
return new BukkitEntityType(getHandle());
}
}
Loading