diff --git a/.gitignore b/.gitignore
index df892ec..6c0a1cf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,4 +11,5 @@ out/
# Ignore Gradle build output directory
build
-run/
\ No newline at end of file
+run/
+runBeta/
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
index 69c6377..703388f 100644
--- a/.idea/jarRepositories.xml
+++ b/.idea/jarRepositories.xml
@@ -21,5 +21,15 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index bc40598..8a100b2 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -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())
}
-tasks.register("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("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 {
tasks.runServer {
minecraftVersion("1.21")
- val bundleAll = tasks.named("bundleAll")
+ val modern = tasks.named("jarModern")
val tLibBundleAll = project(":tenkumaLib").tasks.named("bundleAll")
- dependsOn(bundleAll)
+ dependsOn(modern)
dependsOn(tLibBundleAll)
pluginJars(
- bundleAll.flatMap { it.archiveFile },
+ modern.flatMap { it.archiveFile },
tLibBundleAll.flatMap { it.archiveFile }
)
+}
+
+tasks.register("copyLegacyPlugin") {
+ from(project(":tenkumaLib").tasks.named("bundleAll"))
+ from(tasks.named("jarLegacy"))
+ into("runBeta/plugins")
+}
+
+tasks.register("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()
}
\ No newline at end of file
diff --git a/src/main/java/org/adrianvictor/realtime/Events.java b/src/main/java/org/adrianvictor/realtime/Events.java
index 3c26358..f97a206 100644
--- a/src/main/java/org/adrianvictor/realtime/Events.java
+++ b/src/main/java/org/adrianvictor/realtime/Events.java
@@ -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);
}
}
diff --git a/src/main/java/org/adrianvictor/realtime/GlimmerFactory.java b/src/main/java/org/adrianvictor/realtime/GlimmerFactory.java
new file mode 100644
index 0000000..915b971
--- /dev/null
+++ b/src/main/java/org/adrianvictor/realtime/GlimmerFactory.java
@@ -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);
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/adrianvictor/realtime/Main.java b/src/main/java/org/adrianvictor/realtime/Main.java
index c2e9cf5..b77ef01 100644
--- a/src/main/java/org/adrianvictor/realtime/Main.java
+++ b/src/main/java/org/adrianvictor/realtime/Main.java
@@ -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 worlds = config.getStringList("worlds", null);
+ List 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;
}
diff --git a/src/main/java/org/adrianvictor/realtime/Runnable.java b/src/main/java/org/adrianvictor/realtime/Runnable.java
index d48e911..38968a5 100644
--- a/src/main/java/org/adrianvictor/realtime/Runnable.java
+++ b/src/main/java/org/adrianvictor/realtime/Runnable.java
@@ -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);
}
}
}
diff --git a/src/main/java/org/adrianvictor/realtime/reflection/VersionMatcher.java b/src/main/java/org/adrianvictor/realtime/reflection/VersionMatcher.java
deleted file mode 100644
index 3412ac2..0000000
--- a/src/main/java/org/adrianvictor/realtime/reflection/VersionMatcher.java
+++ /dev/null
@@ -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> map = populateMap();
- List 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 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> populateMap() {
- Map> 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();
- }
-
-}
\ No newline at end of file
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index c736a8c..d2c4221 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -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: