Compare commits

...
Author SHA1 Message Date
Jim C K Flaten c0bb3be9f2 Continued. 2026-01-05 21:09:00 +01:00
Jim C K Flaten fa9c24ede8 WIP 2026-01-03 23:32:01 +01:00
18 changed files with 103 additions and 110 deletions

No files matched your search

+7 -4
View File
@@ -8,16 +8,17 @@ version = '0.13.0-SNAPSHOT'
description = 'Distant Horizons Support'
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
toolchain.languageVersion.set(JavaLanguageVersion.of(8))
}
def paperVersions = [
'1.16.5',
'1.8.8',
]
repositories {
mavenCentral()
maven { url = 'https://repo.papermc.io/repository/maven-public/' }
maven { url = 'https://hub.spigotmc.org/nexus/content/groups/public/' }
//maven { url = 'https://repo.papermc.io/repository/maven-public/' }
maven { url = 'https://jitpack.io/' }
}
@@ -33,6 +34,7 @@ dependencies {
implementation 'com.google.guava:guava:33.3.1-jre'
shade 'org.xerial:sqlite-jdbc:3.45.3.0'
shade 'org.bstats:bstats-bukkit:3.1.0'
shade 'org.json:json:20240303'
shade 'org.tukaani:xz:1.10'
@@ -71,7 +73,8 @@ paperVersions.each { mcVersion ->
}
dependencies {
compileOnly "com.destroystokyo.paper:paper-api:${mcVersion}-R0.1-SNAPSHOT"
compileOnly 'org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT'
//compileOnly "com.destroystokyo.paper:paper-api:${mcVersion}-R0.1-SNAPSHOT"
//compileOnly "io.papermc.paper:paper-api:${mcVersion}-R0.1-SNAPSHOT"
}
@@ -71,7 +71,7 @@ public class BukkitScheduler implements Scheduler
@Override
public boolean canReadWorldAsync()
{
return !this.foliaLib.isFolia();
return !this.foliaLib.isSpigot() && !this.foliaLib.isFolia();
}
@Override
@@ -78,7 +78,7 @@ public class BukkitWorldInterface implements WorldInterface
this.config = config;
this.worldConfig = new WorldConfiguration(this, config);
this.lightOffset = this.getConfig().getInt(DhsConfig.LIGHT_OFFSET_HACK, this.plugin.getDhSupport().getGameVersion().equals("1.20.1") ? this.world.getMinHeight() : 0);
this.lightOffset = this.getConfig().getInt(DhsConfig.LIGHT_OFFSET_HACK, this.plugin.getDhSupport().getGameVersion().equals("1.20.1") ? this.getMinY() : 0);
}
public void setLogger(Logger logger)
@@ -289,8 +289,10 @@ public class BukkitWorldInterface implements WorldInterface
int borderRadius = (int) (this.world.getWorldBorder().getSize() / 2.0);
if (this.worldConfig.getString(DhsConfig.VANILLA_WORLD_BORDER_EXPANSION, "auto").equals("auto")) {
borderRadius += Coordinates.chunkToBlock(this.world.getViewDistance());
borderRadius += Coordinates.chunkToBlock(this.plugin.getServer().getViewDistance());
} else {
borderRadius += Coordinates.chunkToBlock(this.worldConfig.getInt(DhsConfig.VANILLA_WORLD_BORDER_EXPANSION, 0));
}
@@ -459,7 +461,7 @@ public class BukkitWorldInterface implements WorldInterface
@Override
public int getMinY()
{
return this.world.getMinHeight();
return 0;
}
@Override
@@ -499,7 +501,8 @@ public class BukkitWorldInterface implements WorldInterface
return Collections.max(this.getDummyColumn().keySet());
}
return this.getChunk(x, z).getHighestBlockYAt(Coordinates.blockToChunkRelative(x), Coordinates.blockToChunkRelative(z));
// Clamp between min and max Y. Corrupted chunks might return bogus data here.
return Math.max(this.getMinY(), Math.min(this.getChunk(x, z).getHighestBlockYAt(Coordinates.blockToChunkRelative(x), Coordinates.blockToChunkRelative(z)), this.getMaxY()));
}
@Override
@@ -509,18 +512,7 @@ public class BukkitWorldInterface implements WorldInterface
return "minecraft:plains";
}
NamespacedKey key = this.getChunk(x, z).getBiome(Coordinates.blockToChunkRelative(x), y, Coordinates.blockToChunkRelative(z)).getKey();
// If the server just reports "custom" and we have access to getBiomeKey, try to get the correct biome name.
if (key.toString().equals("minecraft:custom") && this.getBiomeKey != null) {
try {
key = (NamespacedKey) this.getBiomeKey.invoke(this.unsafeValues, this.world, x, y, z);
} catch (IllegalAccessException | InvocationTargetException exception) {
throw new RuntimeException(exception);
}
}
return key.toString();
return "minecraft:" + this.getChunk(x, z).getBiome(Coordinates.blockToChunkRelative(x), Coordinates.blockToChunkRelative(z)).toString().toLowerCase();
}
@Override
@@ -536,7 +528,7 @@ public class BukkitWorldInterface implements WorldInterface
return this.getDummyMaterialAt(y);
}
String material = this.getChunk(x, z).getBlockType(Coordinates.blockToChunkRelative(x), y, Coordinates.blockToChunkRelative(z)).getKey().toString();
String material = "minecraft:" + Material.getMaterial(this.getChunk(x, z).getBlockTypeId(Coordinates.blockToChunkRelative(x), y, Coordinates.blockToChunkRelative(z))).toString().toLowerCase();
return Utils.namespaceKey(this.config.getString(DhsConfig.MATERIAL_MAP + "." + Utils.unNamespaceKey(material), material));
}
@@ -544,11 +536,7 @@ public class BukkitWorldInterface implements WorldInterface
@Override
public String getBlockStateAsStringAt(int x, int y, int z)
{
if (this.isDummyMode()) {
return "";
}
return this.getChunk(x, z).getBlockData(Coordinates.blockToChunkRelative(x), y, Coordinates.blockToChunkRelative(z)).getAsString();
return "";
}
@Override
@@ -582,7 +570,9 @@ public class BukkitWorldInterface implements WorldInterface
return 0;
}
return (byte) this.getChunk(x, z).getBlockEmittedLight(Coordinates.blockToChunkRelative(x), Math.clamp(y + this.lightOffset, this.getMinY(), this.getMaxY() - 1), Coordinates.blockToChunkRelative(z));
int offsetY = y + this.lightOffset;
return (byte) this.getChunk(x, z).getBlockEmittedLight(Coordinates.blockToChunkRelative(x), Math.max(this.getMinY(), Math.min(offsetY, this.getMaxY() - 1)), Coordinates.blockToChunkRelative(z));
}
@Override
@@ -592,7 +582,9 @@ public class BukkitWorldInterface implements WorldInterface
return (byte) (this.getDummyMaterialAt(y + 1).equals("minecraft:air") ? 15 : 0);
}
return (byte) this.getChunk(x, z).getBlockSkyLight(Coordinates.blockToChunkRelative(x), Math.clamp(y + this.lightOffset, this.getMinY(), this.getMaxY() - 1), Coordinates.blockToChunkRelative(z));
int offsetY = y + this.lightOffset;
return (byte) this.getChunk(x, z).getBlockSkyLight(Coordinates.blockToChunkRelative(x), Math.max(this.getMinY(), Math.min(offsetY, this.getMaxY() - 1)), Coordinates.blockToChunkRelative(z));
}
@Override
@@ -612,11 +604,7 @@ public class BukkitWorldInterface implements WorldInterface
return false;
}
return this.plugin.getDhSupport().getScheduler()
.runOnRegionThread(this.world.getUID(), x, z, () ->
((Beacon) this.world.getBlockAt(x, y, z).getState()).getTier() > 0
)
.join();
return true;
}
@Override
@@ -67,7 +67,7 @@ public class DhSupportBukkitPlugin extends JavaPlugin
this.getLogger().info("I am DHS " + pluginVersion + ".");
this.dhSupport = new DhSupport(pluginVersion, this.getServer().getMinecraftVersion());
this.dhSupport = new DhSupport(pluginVersion, this.getServer().getVersion());
this.dhSupport.setLogger(this.getLogger());
this.dhSupport.setDataDirectory(this.getDataFolder().getAbsolutePath());
@@ -338,7 +338,7 @@ public class DhsCommand implements CommandExecutor
Duration elapsedTime = generator.getElapsedTime();
float momentaryLodsPerSecond = (float) this.plugin.getDhSupport().getGenerationTracker().getPingsPerSecond();
float totalLodsPerSecond = (float) generator.getCompletedRequests() / elapsedTime.toSeconds();
float totalLodsPerSecond = (float) generator.getCompletedRequests() / (elapsedTime.getSeconds() + (elapsedTime.getNano() / 1_000_000_000f));
sender.sendMessage(ChatColor.GREEN + "Generation progress: " + ChatColor.YELLOW + String.format("%.2f", generator.getProgress() * 100f) + "%");
sender.sendMessage(ChatColor.GREEN + "Processed LODs: " + ChatColor.YELLOW + generator.getCompletedRequests() + ChatColor.GREEN + " / " + ChatColor.YELLOW + generator.getTargetRequests() + ChatColor.GREEN + " (" + ChatColor.YELLOW + String.format("%.2f", totalLodsPerSecond * 16) + ChatColor.GREEN + " CPS)");
@@ -35,9 +35,7 @@ import org.bukkit.event.world.WorldUnloadEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class WorldHandler implements Listener
{
@@ -138,23 +136,31 @@ public class WorldHandler implements Listener
try {
Object result = method.invoke(event);
if (result instanceof Location location) {
list = List.of(location.getBlock());
} else if (result instanceof Chunk chunk) {
list = List.of(chunk.getBlock(0, 0, 0));
if (result instanceof Location) {
Location location = (Location) result;
list = Collections.singletonList(location.getBlock());
} else if (result instanceof Chunk) {
Chunk chunk = (Chunk) result;
list = Collections.singletonList(chunk.getBlock(0, 0, 0));
} else if (result instanceof List) {
list = (List<?>) result;
} else {
list = List.of(result);
list = Collections.singletonList(result);
}
} catch (IllegalAccessException | InvocationTargetException exception) {
throw new RuntimeException(exception);
}
for (Object entry : list) {
if (entry instanceof Block block) {
if (entry instanceof Block) {
Block block = (Block) entry;
this.touchLod(block.getLocation(), eventClassName);
} else if (entry instanceof BlockState state) {
} else if (entry instanceof BlockState) {
BlockState state = (BlockState) entry;
this.touchLod(state.getLocation(), eventClassName);
} else {
this.plugin.getDhSupport().warning("Unknown block " + entry + " from event: " + eventClassName);
@@ -329,7 +329,7 @@ public class DhSupport implements Configurable
LodBuilder builder;
try {
Class<? extends LodBuilder> builderClass = Class.forName(LodBuilder.class.getPackageName() + "." + builderType).asSubclass(LodBuilder.class);
Class<? extends LodBuilder> builderClass = Class.forName(LodBuilder.class.getPackage().getName() + "." + builderType).asSubclass(LodBuilder.class);
Constructor<?> constructor = builderClass.getConstructor(WorldInterface.class, SectionPosition.class);
@@ -727,7 +727,7 @@ public class DhSupport implements Configurable
chains.add(chain);
}
return CompletableFuture.allOf(chains.toArray(CompletableFuture[]::new))
return CompletableFuture.allOf(chains.stream().toArray(CompletableFuture[]::new))
.thenApply((bar) -> {
double elapsed = (System.currentTimeMillis() - ts) / 1000d;
+23 -28
View File
@@ -66,49 +66,44 @@ public class Utils
public static String humanReadableDuration(final Duration duration)
{
if (duration.toDays() >= 365) {
long totalSeconds = duration.getSeconds();
if (totalSeconds >= 365L * 24 * 60 * 60) {
return "infinite";
}
final StringBuilder builder = new StringBuilder();
long days = totalSeconds / 86_400;
totalSeconds %= 86_400;
if (duration.toDays() > 0) {
builder.append(duration.toDaysPart()).append(" day");
long hours = totalSeconds / 3_600;
totalSeconds %= 3_600;
if (duration.toDaysPart() != 1) {
builder.append("s");
}
long minutes = totalSeconds / 60;
long seconds = totalSeconds % 60;
StringBuilder builder = new StringBuilder();
if (days > 0) {
builder.append(days).append(" day");
if (days != 1) builder.append("s");
builder.append(", ");
}
if (duration.toHours() > 0) {
builder.append(duration.toHoursPart()).append(" hour");
if (duration.toHoursPart() != 1) {
builder.append("s");
}
if (hours > 0) {
builder.append(hours).append(" hour");
if (hours != 1) builder.append("s");
builder.append(", ");
}
if (duration.toMinutes() > 0) {
builder.append(duration.toMinutesPart()).append(" minute");
if (duration.toMinutesPart() != 1) {
builder.append("s");
}
if (minutes > 0) {
builder.append(minutes).append(" minute");
if (minutes != 1) builder.append("s");
builder.append(", ");
}
if (duration.toSeconds() > 0 || builder.isEmpty()) {
builder.append(duration.toSecondsPart()).append(" second");
if (duration.toSecondsPart() != 1) {
builder.append("s");
}
if (seconds > 0 || builder.length() == 0) {
builder.append(seconds).append(" second");
if (seconds != 1) builder.append("s");
builder.append(", ");
}
@@ -37,7 +37,9 @@ public class Configuration
public void set(String key, @Nullable Object value)
{
if (value instanceof String stringValue) {
if (value instanceof String) {
String stringValue = (String) value;
if ("false".equalsIgnoreCase(stringValue)) {
value = false;
} else if ("true".equalsIgnoreCase(stringValue)) {
@@ -25,7 +25,7 @@ import javax.annotation.Nullable;
public class WorldConfiguration extends Configuration
{
protected static String WORLD_PREFIX = "worlds.%s.";
protected static String WORLD_PREFIX = "worlds.";
protected WorldInterface world;
@@ -40,19 +40,19 @@ public class WorldConfiguration extends Configuration
@Override
public void set(String key, @Nullable Object value)
{
this.config.set(WORLD_PREFIX.formatted(this.world.getName()) + key, value);
this.config.set(WORLD_PREFIX + this.world.getName() + "." + key, value);
}
@Override
public void unset(String key)
{
this.config.unset(WORLD_PREFIX.formatted(this.world.getName()) + key);
this.config.unset(WORLD_PREFIX + this.world.getName() + "." + key);
}
@Override
public @PolyNull Object get(String key, @PolyNull Object defaultValue)
{
Object specific = this.config.get(WORLD_PREFIX.formatted(this.world.getName()) + key);
Object specific = this.config.get(WORLD_PREFIX + this.world.getName() + "." + key);
return specific == null ? this.config.get(key, defaultValue) : specific;
}
@@ -41,6 +41,12 @@ public class Database
public Connection getConnection() throws SQLException
{
try {
Class.forName("org.sqlite.JDBC");
} catch (ClassNotFoundException e) {
throw new RuntimeException("SQLite JDBC driver missing from plugin jar", e);
}
if (this.connection == null || this.connection.isClosed()) {
this.connection = DriverManager.getConnection("jdbc:sqlite:" + this.path);
}
@@ -90,12 +96,7 @@ public class Database
protected void createMigrationsTable() throws SQLException
{
String sql = """
CREATE TABLE IF NOT EXISTS migrations (
name STRING PRIMARY KEY,
timestamp INTEGER
);
""";
String sql = "CREATE TABLE IF NOT EXISTS migrations ( name STRING PRIMARY KEY, timestamp INTEGER);";
try (Statement statement = this.getConnection().createStatement()) {
statement.execute(sql);
@@ -33,9 +33,7 @@ public class AddLodVersionColumn extends Migration
public void up() throws Exception
{
try (Statement statement = this.database.getConnection().createStatement()) {
statement.execute("""
ALTER TABLE lods ADD version INT NULL;
""");
statement.execute("ALTER TABLE lods ADD version INT NULL;");
}
}
}
@@ -33,17 +33,7 @@ public class CreateLodsTable extends Migration
public void up() throws Exception
{
try (Statement statement = this.database.getConnection().createStatement()) {
statement.execute("""
CREATE TABLE IF NOT EXISTS lods (
worldId STRING NOT NULL,
x INTEGER NOT NULL,
z INTEGER NOT NULL,
data BLOB NOT NULL,
beacons BLOB NOT NULL,
timestamp INTEGER NOT NULL,
PRIMARY KEY (worldId, x, z)
);
""");
statement.execute("CREATE TABLE IF NOT EXISTS lods ( worldId STRING NOT NULL, x INTEGER NOT NULL, z INTEGER NOT NULL, data BLOB NOT NULL, beacons BLOB NOT NULL, timestamp INTEGER NOT NULL, PRIMARY KEY (worldId, x, z));");
}
}
}
@@ -33,9 +33,7 @@ public class DeleteLodsWithoutVersion extends Migration
public void up() throws Exception
{
try (Statement statement = this.database.getConnection().createStatement()) {
statement.execute("""
DELETE FROM lods WHERE version IS NULL;
""");
statement.execute("DELETE FROM lods WHERE version IS NULL;");
}
}
}
@@ -102,6 +102,10 @@ public class LodRepository
statement.setInt(3, sectionZ);
try (ResultSet result = statement.executeQuery()) {
if (!result.next()) {
return null;
}
byte[] data = result.getBytes("data");
if (data == null) {
@@ -135,6 +139,8 @@ public class LodRepository
statement.setInt(3, sectionZ);
try (ResultSet result = statement.executeQuery()) {
result.next();
return result.getInt(1) == 1;
}
} catch (SQLException exception) {
@@ -74,7 +74,7 @@ public class IdMapping extends DataObject
}
}
String serialized = this.biome + IdMapping.separator1 + this.block + (propStringBuilder.isEmpty() ? "" : IdMapping.separator2 + propStringBuilder);
String serialized = this.biome + IdMapping.separator1 + this.block + (propStringBuilder.length() > 0 ? "" : IdMapping.separator2 + propStringBuilder);
encoder.writeShortString(serialized);
}
@@ -29,7 +29,7 @@ import org.bukkit.entity.Player;
public class PlayerConfigHandler
{
public final static String USAGE_PERMISSION = "distant_horizons.worlds.%s";
public final static String USAGE_PERMISSION = "distant_horizons.worlds.";
protected DhSupport dhSupport;
@@ -49,7 +49,7 @@ public class PlayerConfigHandler
WorldInterface world = this.dhSupport.getWorldInterface(player.getWorld().getUID());
String permission = USAGE_PERMISSION.formatted(world.getName());
String permission = USAGE_PERMISSION + world.getName();
boolean dhUseIsAllowed = !player.isPermissionSet(permission) || player.hasPermission(permission);
Configuration dhsConfig = world.getConfig();
@@ -95,11 +95,17 @@ public class PlayerConfigHandler
}
if (keepValue == null) {
if (dhsValue instanceof Boolean dhsBool && clientValue instanceof Boolean clientBool) {
if (dhsValue instanceof Boolean && clientValue instanceof Boolean) {
boolean dhsBool = (boolean) dhsValue;
boolean clientBool = (boolean) clientValue;
keepValue = dhsBool && clientBool;
//this.dhSupport.getLogger().info(" Server " + (dhsBool ? "Y" : "N") + " or client " + (clientBool ? "Y" : "N") + " = " + ((boolean) keepValue ? "Y" : "N"));
} else if (dhsValue instanceof Integer dhsInt && clientValue instanceof Integer clientInt) {
} else if (dhsValue instanceof Integer && clientValue instanceof Integer) {
int dhsInt = (int) dhsValue;
int clientInt = (int) clientValue;
keepValue = dhsInt < clientInt ? dhsInt : clientInt;
//this.dhSupport.getLogger().info(" Server " + dhsInt + " or client " + clientInt + " = " + keepValue);
@@ -36,7 +36,7 @@ public class PluginMessageHandler
private MessageTypeRegistry messageTypeRegistry;
public final String pluginChannel = "distant_horizons:message";
public final String pluginChannel = "distant_horizons:msg";
public final short protocolVersion = 13;