Convert to Gradle plugin, add support for modern Paper with reflection and add config.yml option to block bed usage.
This commit is contained in:
parent
a510e17c3e
commit
690fc1a4dc
39 changed files with 1062 additions and 105 deletions
|
|
@ -1,51 +0,0 @@
|
|||
package gd.rf.adrianvictor.realtime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import gd.rf.adrianvictor.lib.Log;
|
||||
import gd.rf.adrianvictor.lib.ConfigurationEx;
|
||||
|
||||
public class Main extends JavaPlugin {
|
||||
Log log;
|
||||
ConfigurationEx config;
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
log.info("Disabling!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
log = new Log(this);
|
||||
log.info("Starting!");
|
||||
config = new ConfigurationEx(this, "config.yml", log);
|
||||
config.loadConfig();
|
||||
int ticksBetweenUpdate = config.getInt("ticksBetweenUpdate", 20);
|
||||
List<String> worlds = config.getStringList("worlds", null);
|
||||
Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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.");
|
||||
worlds.remove(worldName);
|
||||
return;
|
||||
}
|
||||
ZonedDateTime time = ZonedDateTime.now(ZoneId.of(config.getString("timezone", ZoneId.systemDefault().toString())));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}, 0L, ticksBetweenUpdate);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package org.adrianvictor.realtime.impl.legacy;
|
||||
|
||||
import org.adrianvictor.realtime.Main;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Event;
|
||||
|
||||
public class Glimmer implements org.adrianvictor.realtime.reflection.Glimmer {
|
||||
@Override
|
||||
public void onStart() {
|
||||
Bukkit.getServer().getPluginManager().registerEvent(Event.Type.PLAYER_BED_ENTER, new PlayerListener(), Event.Priority.Highest, Main.getInstance());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package org.adrianvictor.realtime.impl.legacy;
|
||||
|
||||
import org.adrianvictor.realtime.Events;
|
||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
||||
|
||||
public class PlayerListener extends org.bukkit.event.player.PlayerListener {
|
||||
@Override
|
||||
public void onPlayerBedEnter(PlayerBedEnterEvent event) {
|
||||
Events.onBedEnter(event);
|
||||
}
|
||||
}
|
||||
10
src/main/java/org/adrianvictor/realtime/Events.java
Normal file
10
src/main/java/org/adrianvictor/realtime/Events.java
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package org.adrianvictor.realtime;
|
||||
|
||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
||||
|
||||
public class Events {
|
||||
public static void onBedEnter(PlayerBedEnterEvent event) {
|
||||
boolean isCancelled = Main.getInstance().getConfig().getBoolean("preventSleep", true);
|
||||
event.setCancelled(isCancelled);
|
||||
}
|
||||
}
|
||||
51
src/main/java/org/adrianvictor/realtime/Main.java
Normal file
51
src/main/java/org/adrianvictor/realtime/Main.java
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package org.adrianvictor.realtime;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.ZoneId;
|
||||
import java.util.List;
|
||||
|
||||
import org.adrianvictor.lib.configuration.Configuration;
|
||||
import org.adrianvictor.lib.configuration.exception.InvalidConfigurationException;
|
||||
import org.adrianvictor.lib.configuration.provider.ConfigurationProvider;
|
||||
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;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
saveResource("config.yml", false);
|
||||
plugin = this;
|
||||
config = Configuration.create(org.adrianvictor.lib.Main.getVersionedServiceFactory());
|
||||
|
||||
try {
|
||||
config.load(new File(getDataFolder(), "config.yml"));
|
||||
} catch (IOException | InvalidConfigurationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
new VersionMatcher().loadGlim().onStart();
|
||||
|
||||
int ticksBetweenUpdate = config.getInt("ticksBetweenUpdate", 20);
|
||||
List<String> worlds = config.getStringList("worlds", null);
|
||||
ZoneId zone = ZoneId.of(config.getString("timezone", ZoneId.systemDefault().toString()));
|
||||
|
||||
Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(
|
||||
this,
|
||||
new Runnable(worlds, zone),
|
||||
0L,
|
||||
ticksBetweenUpdate
|
||||
);
|
||||
}
|
||||
|
||||
public static JavaPlugin getInstance() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public ConfigurationProvider getConfigProvider() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
38
src/main/java/org/adrianvictor/realtime/Runnable.java
Normal file
38
src/main/java/org/adrianvictor/realtime/Runnable.java
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
package org.adrianvictor.realtime;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
public class Runnable implements java.lang.Runnable {
|
||||
List<String> worlds;
|
||||
ZoneId zone;
|
||||
|
||||
public Runnable(List<String> worlds, ZoneId zone) {
|
||||
this.worlds = worlds;
|
||||
this.zone = zone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
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.");
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package org.adrianvictor.realtime.reflection;
|
||||
|
||||
public interface Glimmer {
|
||||
void onStart();
|
||||
}
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
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();
|
||||
}
|
||||
|
||||
}
|
||||
5
src/main/resources/config.yml
Normal file
5
src/main/resources/config.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
ticksBetweenUpdate: 0 # 20 ticks is 1 second
|
||||
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:
|
||||
- "world"
|
||||
8
src/main/resources/plugin.yml
Normal file
8
src/main/resources/plugin.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
author: tenkuma
|
||||
database: false
|
||||
main: org.adrianvictor.realtime.Main
|
||||
name: TimeKeeper
|
||||
depend: [tenkumaLib]
|
||||
url: https://adrianvictor.rf.gd
|
||||
version: '1.0'
|
||||
api-version: "1.13"
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package org.adrianvictor.realtime.impl.modern;
|
||||
|
||||
import org.adrianvictor.realtime.Events;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerBedEnterEvent;
|
||||
|
||||
public class EventListener implements Listener {
|
||||
@EventHandler
|
||||
public void onPlayerBedEnter(PlayerBedEnterEvent event) {
|
||||
Events.onBedEnter(event);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package org.adrianvictor.realtime.impl.modern;
|
||||
|
||||
import org.adrianvictor.realtime.Main;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class Glimmer implements org.adrianvictor.realtime.reflection.Glimmer {
|
||||
@Override
|
||||
public void onStart() {
|
||||
Bukkit.getServer().getPluginManager().registerEvents(new EventListener(), Main.getInstance());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue