Make beta implementation use Project Poseidon from Maven, default to 1 tick refresh rate to avoid lag, fix tenkumaLib ConfigurationProvider usage in Main, switch from reflection to hybrid abstraction/reflection.
This commit is contained in:
parent
d624a46703
commit
029b37db7e
9 changed files with 100 additions and 242 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -11,4 +11,5 @@ out/
|
|||
# Ignore Gradle build output directory
|
||||
build
|
||||
|
||||
run/
|
||||
run/
|
||||
runBeta/
|
||||
10
.idea/jarRepositories.xml
generated
10
.idea/jarRepositories.xml
generated
|
|
@ -21,5 +21,15 @@
|
|||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://repo.papermc.io/repository/maven-public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven2" />
|
||||
<option name="name" value="maven2" />
|
||||
<option name="url" value="https://repository.johnymuffin.com/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven2" />
|
||||
<option name="name" value="maven2" />
|
||||
<option name="url" value="https://repository.johnymuffin.com/repository/maven-releases/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -9,6 +9,7 @@ version = System.getenv("TKEEPER_VERSION_NAME") ?: "unknown"
|
|||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
maven("https://repository.johnymuffin.com/repository/maven-releases/")
|
||||
flatDir {
|
||||
dirs("libs")
|
||||
}
|
||||
|
|
@ -66,7 +67,7 @@ mcVersions.forEach { ver ->
|
|||
dependencies {
|
||||
add("compileOnly", "io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
|
||||
add("modernCompileOnly", "io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
|
||||
add("legacyCompileOnly", files("libs/tenkumaLib/libs/craftbukkit-1060.jar"))
|
||||
add("legacyImplementation", "com.legacyminecraft.poseidon:poseidon-craftbukkit:1.1.12-260503-0121-a9af58a")
|
||||
|
||||
compileOnly(project(":tenkumaLib"))
|
||||
|
||||
|
|
@ -76,7 +77,6 @@ dependencies {
|
|||
testImplementation("io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
|
||||
testImplementation("com.github.seeseemelk:MockBukkit-v1.21:3.102.0")
|
||||
|
||||
// Allow tests to see the versioned implementations
|
||||
mcVersions.forEach { ver ->
|
||||
testImplementation(sourceSets[ver].output)
|
||||
}
|
||||
|
|
@ -111,26 +111,26 @@ tasks.register("buildAll") {
|
|||
dependsOn(tasks.withType<Jar>())
|
||||
}
|
||||
|
||||
tasks.register<Jar>("bundleAll") {
|
||||
dependsOn(configurations.runtimeClasspath)
|
||||
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
|
||||
from(sourceSets["main"].output)
|
||||
|
||||
mcVersions.forEach { ver ->
|
||||
from(sourceSets[ver].output)
|
||||
}
|
||||
|
||||
from({
|
||||
configurations.runtimeClasspath.get()
|
||||
.filter { it.name.endsWith("jar") }
|
||||
.map { zipTree(it) }
|
||||
})
|
||||
|
||||
archiveClassifier.set("all-implementations")
|
||||
archiveVersion.set(project.version.toString())
|
||||
}
|
||||
//tasks.register<Jar>("bundleAll") {
|
||||
// dependsOn(configurations.runtimeClasspath)
|
||||
//
|
||||
// duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
//
|
||||
// from(sourceSets["main"].output)
|
||||
//
|
||||
// mcVersions.forEach { ver ->
|
||||
// from(sourceSets[ver].output)
|
||||
// }
|
||||
//
|
||||
// from({
|
||||
// configurations.runtimeClasspath.get()
|
||||
// .filter { it.name.endsWith("jar") }
|
||||
// .map { zipTree(it) }
|
||||
// })
|
||||
//
|
||||
// archiveClassifier.set("all-implementations")
|
||||
// archiveVersion.set(project.version.toString())
|
||||
//}
|
||||
|
||||
/* ----------------------------------------- */
|
||||
/* JAVA SETTINGS */
|
||||
|
|
@ -151,14 +151,34 @@ tasks.withType<JavaCompile> {
|
|||
tasks.runServer {
|
||||
minecraftVersion("1.21")
|
||||
|
||||
val bundleAll = tasks.named<Jar>("bundleAll")
|
||||
val modern = tasks.named<Jar>("jarModern")
|
||||
val tLibBundleAll = project(":tenkumaLib").tasks.named<Jar>("bundleAll")
|
||||
|
||||
dependsOn(bundleAll)
|
||||
dependsOn(modern)
|
||||
dependsOn(tLibBundleAll)
|
||||
|
||||
pluginJars(
|
||||
bundleAll.flatMap { it.archiveFile },
|
||||
modern.flatMap { it.archiveFile },
|
||||
tLibBundleAll.flatMap { it.archiveFile }
|
||||
)
|
||||
}
|
||||
|
||||
tasks.register<Copy>("copyLegacyPlugin") {
|
||||
from(project(":tenkumaLib").tasks.named<Jar>("bundleAll"))
|
||||
from(tasks.named<Jar>("jarLegacy"))
|
||||
into("runBeta/plugins")
|
||||
}
|
||||
|
||||
tasks.register<JavaExec>("runBetaServer") {
|
||||
group = "verification"
|
||||
description = "Runs the beta server with legacy TimeKeeper."
|
||||
|
||||
dependsOn("copyLegacyPlugin")
|
||||
|
||||
jvmArgs = listOf("-Djline.terminal=jline.UnsupportedTerminal", "-Dfile.encoding=UTF-8", "-Djava.awt.headless=true")
|
||||
classpath = files("runBeta/poseidon-craftbukkit.jar")
|
||||
mainClass.set("org.bukkit.craftbukkit.Main")
|
||||
workingDir = file("runBeta")
|
||||
|
||||
standardInput = file("/dev/null").inputStream()
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ import org.bukkit.event.player.PlayerBedEnterEvent;
|
|||
|
||||
public class Events {
|
||||
public static void onBedEnter(PlayerBedEnterEvent event) {
|
||||
boolean isCancelled = Main.getInstance().getConfig().getBoolean("preventSleep", true);
|
||||
boolean isCancelled = Main.getInstance().getConfigProvider().getBoolean("preventSleep", true);
|
||||
event.setCancelled(isCancelled);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
19
src/main/java/org/adrianvictor/realtime/GlimmerFactory.java
Normal file
19
src/main/java/org/adrianvictor/realtime/GlimmerFactory.java
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package org.adrianvictor.realtime;
|
||||
|
||||
import org.adrianvictor.realtime.reflection.Glimmer;
|
||||
|
||||
public class GlimmerFactory {
|
||||
public static Glimmer create() {
|
||||
try {
|
||||
return (Glimmer) Class.forName("org.adrianvictor.realtime.impl.modern.Glimmer")
|
||||
.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
return (Glimmer) Class.forName("org.adrianvictor.realtime.impl.legacy.Glimmer")
|
||||
.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Failed to instantiate Glimmer implementation", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,20 @@
|
|||
package org.adrianvictor.realtime;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.ZoneId;
|
||||
import java.util.List;
|
||||
|
||||
import org.adrianvictor.lib.configuration.exception.InvalidConfigurationException;
|
||||
import org.adrianvictor.lib.configuration.provider.ConfigurationProvider;
|
||||
import org.adrianvictor.lib.file.provider.FileProvider;
|
||||
import org.adrianvictor.realtime.reflection.VersionMatcher;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class Main extends JavaPlugin {
|
||||
ConfigurationProvider config;
|
||||
static JavaPlugin plugin;
|
||||
static Main plugin;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
|
@ -22,19 +23,22 @@ public class Main extends JavaPlugin {
|
|||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
plugin = this;
|
||||
config = ConfigurationProvider.get();
|
||||
|
||||
try {
|
||||
config.load(new File(getDataFolder(), "config.yml"));
|
||||
File configFile = new File(getDataFolder(), "config.yml");
|
||||
String configString = Files.readString(Path.of(configFile.getPath()));
|
||||
config.load(configString);
|
||||
} catch (IOException | InvalidConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
new VersionMatcher().loadGlim().onStart();
|
||||
GlimmerFactory.create().onStart();
|
||||
|
||||
int ticksBetweenUpdate = config.getInt("ticksBetweenUpdate", 20);
|
||||
List<String> worlds = config.getStringList("worlds", null);
|
||||
List<String> worlds = config.getStringList("worlds", List.of("world"));
|
||||
ZoneId zone = ZoneId.of(config.getString("timezone", ZoneId.systemDefault().toString()));
|
||||
|
||||
Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(
|
||||
|
|
@ -45,7 +49,7 @@ public class Main extends JavaPlugin {
|
|||
);
|
||||
}
|
||||
|
||||
public static JavaPlugin getInstance() {
|
||||
public static Main getInstance() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package org.adrianvictor.realtime;
|
||||
|
||||
import org.adrianvictor.lib.logging.provider.LoggerProvider;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
|
||||
|
|
@ -21,18 +22,23 @@ public class Runnable implements java.lang.Runnable {
|
|||
for (String worldName : worlds) {
|
||||
World world = Bukkit.getServer().getWorld(worldName);
|
||||
if (world == null) {
|
||||
// log.severe("World " + worldName + " specified in the config was not found, removing it.");
|
||||
LoggerProvider.get().info("World " + worldName + " specified in the config was not found, removing it.");
|
||||
worlds.remove(worldName);
|
||||
return;
|
||||
}
|
||||
ZonedDateTime time = ZonedDateTime.now(zone);
|
||||
int hour = time.getHour();
|
||||
int minute = time.getMinute();
|
||||
long minecraftTime = (hour * 1000 + minute * 100 / 6 - 6000) % 24000;
|
||||
if (minecraftTime < 0) {
|
||||
minecraftTime = minecraftTime * 2;
|
||||
}
|
||||
world.setTime(minecraftTime);
|
||||
|
||||
// Minecraft time: 0 is 6:00 AM. 18000 is Midnight (0:00).
|
||||
// (hour * 1000) + (minute * 1000 / 60) gives time in ticks from 0:00.
|
||||
// Subtract 6000 to align 6:00 AM with 0 ticks.
|
||||
long ticksSinceMidnight = (hour * 1000L) + (minute * 1000L / 60L);
|
||||
long minecraftTime = (ticksSinceMidnight - 6000L + 24000L) % 24000L;
|
||||
|
||||
long currentFullTime = world.getFullTime();
|
||||
long day = currentFullTime / 24000L;
|
||||
world.setFullTime(day * 24000L + minecraftTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,202 +0,0 @@
|
|||
package org.adrianvictor.realtime.reflection;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class VersionMatcher {
|
||||
|
||||
public VersionMatcher() {}
|
||||
|
||||
private record Entry(String pattern, String classSuffix) {}
|
||||
|
||||
public String getVersion(String type, String serverVersion) {
|
||||
if (type == null || serverVersion == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
Map<String, List<Entry>> map = populateMap();
|
||||
List<Entry> entries = map.get(type.toLowerCase());
|
||||
if (entries == null || entries.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
for (Entry e : entries) {
|
||||
if (safeMatches(e.pattern, serverVersion)) {
|
||||
return e.pattern + "|" + e.classSuffix;
|
||||
}
|
||||
}
|
||||
|
||||
List<Entry> sorted = new ArrayList<>(entries);
|
||||
Collections.sort(sorted, (a, b) -> compareVersions(a.pattern, b.pattern));
|
||||
|
||||
Entry oldest = sorted.get(0);
|
||||
Entry newest = sorted.get(sorted.size() - 1);
|
||||
|
||||
int cmpOldest = compareVersions(serverVersion, oldest.pattern);
|
||||
int cmpNewest = compareVersions(serverVersion, newest.pattern);
|
||||
|
||||
if (cmpOldest < 0) {
|
||||
return oldest.pattern + "|" + oldest.classSuffix;
|
||||
} else if (cmpNewest > 0) {
|
||||
return newest.pattern + "|" + newest.classSuffix;
|
||||
}
|
||||
|
||||
// should not happen because we already tried all patterns
|
||||
return newest.pattern + "|" + newest.classSuffix;
|
||||
}
|
||||
|
||||
private Map<String, List<Entry>> populateMap() {
|
||||
Map<String, List<Entry>> map = new HashMap<>();
|
||||
|
||||
// RELEASE patterns, newest first (order does not matter for matching)
|
||||
map.put("release", List.of(
|
||||
new Entry("^1\\.21\\..*$", "r1_21")
|
||||
));
|
||||
|
||||
// BETA patterns
|
||||
map.put("beta", List.of(
|
||||
new Entry("^1\\.7\\.3$", "b1_7_3")
|
||||
));
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
private int compareVersions(String v1, String v2) {
|
||||
String clean1 = v1.replaceAll("[^0-9.]", "");
|
||||
String clean2 = v2.replaceAll("[^0-9.]", "");
|
||||
|
||||
String[] a1 = clean1.split("\\.");
|
||||
String[] a2 = clean2.split("\\.");
|
||||
|
||||
int len = Math.max(a1.length, a2.length);
|
||||
for (int i = 0; i < len; i++) {
|
||||
int n1 = i < a1.length ? parseInt(a1[i]) : 0;
|
||||
int n2 = i < a2.length ? parseInt(a2[i]) : 0;
|
||||
if (n1 != n2) {
|
||||
return n1 - n2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int parseInt(String s) {
|
||||
try {
|
||||
return Integer.parseInt(s);
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public Glimmer loadGlim() {
|
||||
String rawVersion = null;
|
||||
try {
|
||||
if (Bukkit.getServer() != null) {
|
||||
rawVersion = Bukkit.getMinecraftVersion();
|
||||
}
|
||||
} catch (NoSuchMethodError ignored) {}
|
||||
|
||||
if (rawVersion == null || rawVersion.isEmpty()) {
|
||||
try {
|
||||
if (Bukkit.getServer() != null) {
|
||||
String v = Bukkit.getVersion(); // e.g. "git-Bukkit-0.0.0-1060-... (MC: 1.7.3)"
|
||||
int start = v.lastIndexOf("MC: ");
|
||||
if (start != -1) {
|
||||
rawVersion = v.substring(start + 4, v.length() - 1);
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
if (rawVersion == null || rawVersion.isEmpty()) {
|
||||
rawVersion = "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
String matchInfo = getVersion("release", rawVersion);
|
||||
if (matchInfo.isEmpty()) {
|
||||
matchInfo = getVersion("beta", rawVersion);
|
||||
}
|
||||
|
||||
if (matchInfo.isEmpty()) {
|
||||
// Fallback to b1.7.3 if everything fails, or throw error?
|
||||
Glimmer fallback = tryInstantiate("org.adrianvictor.realtime.impl.b1_7_3");
|
||||
if (fallback != null) return fallback;
|
||||
throw new IllegalStateException("No suitable implementation found for version " + rawVersion);
|
||||
}
|
||||
|
||||
String[] partsInfo = matchInfo.split("\\|");
|
||||
String classSuffix = partsInfo[1];
|
||||
|
||||
Glimmer glimmer = tryInstantiate("org.adrianvictor.realtime.impl." + classSuffix);
|
||||
if (glimmer != null) return glimmer;
|
||||
|
||||
// Backward search for older implementations
|
||||
String[] versionParts = rawVersion.split("\\.");
|
||||
int major = parseInt(versionParts[0]);
|
||||
int minor = versionParts.length > 1 ? parseInt(versionParts[1]) : 0;
|
||||
int patch = versionParts.length > 2 ? parseInt(versionParts[2]) : 0;
|
||||
|
||||
while (major >= 0) {
|
||||
while (minor >= 0) {
|
||||
while (patch >= 0) {
|
||||
String className = String.format("org.adrianvictor.realtime.impl.r%d_%d_%d", major, minor, patch);
|
||||
glimmer = tryInstantiate(className);
|
||||
if (glimmer != null) return glimmer;
|
||||
|
||||
className = String.format("org.adrianvictor.realtime.impl.r%d_%d", major, minor);
|
||||
glimmer = tryInstantiate(className);
|
||||
if (glimmer != null) return glimmer;
|
||||
|
||||
patch--;
|
||||
}
|
||||
minor--;
|
||||
patch = 20; // Search up to .20 patch of previous minor
|
||||
}
|
||||
major--;
|
||||
minor = 30; // Search up to .30 minor of previous major
|
||||
}
|
||||
|
||||
if (isNewEventSystem()) {
|
||||
Glimmer modern = tryInstantiate("org.adrianvictor.realtime.impl.modern.Glimmer");
|
||||
if (modern != null) return modern;
|
||||
} else {
|
||||
Glimmer legacy = tryInstantiate("org.adrianvictor.realtime.impl.legacy.Glimmer");
|
||||
if (legacy != null) return legacy;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("No suitable implementation found for version " + rawVersion);
|
||||
}
|
||||
|
||||
private boolean isNewEventSystem() {
|
||||
try {
|
||||
Class.forName("org.bukkit.event.EventHandler");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private Glimmer tryInstantiate(String className) {
|
||||
try {
|
||||
Class<?> clazz = Class.forName(className, true, getClass().getClassLoader());
|
||||
if (!Glimmer.class.isAssignableFrom(clazz)) {
|
||||
return null;
|
||||
}
|
||||
return (Glimmer) clazz.getDeclaredConstructor().newInstance();
|
||||
} catch (ReflectiveOperationException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean safeMatches(String expression, String against) {
|
||||
String cleanPattern = expression.trim();
|
||||
Pattern pattern = Pattern.compile(cleanPattern, Pattern.CASE_INSENSITIVE);
|
||||
return pattern.matcher(against).matches();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
ticksBetweenUpdate: 0 # 20 ticks is 1 second
|
||||
ticksBetweenUpdate: 1 # 20 ticks is 1 second, 0 lags the server
|
||||
timezone: "America/Sao_Paulo" # comment this line to use system's default timezone
|
||||
preventSleep: true # Players will sleep and time will sync afterwards, so it's better to disable unless you have a reason to
|
||||
worlds:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue